/*******************************************************************************

  Copyright(c) 2003-2004 Aurelien Reynaud.

  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the Free
  Software Foundation; either version 2 of the License, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc., 59
  Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  The full GNU General Public License is included in this distribution in the
  file called COPYING.

*******************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "ggiterm.h"
#include "debug.h"
#include "lowlevel/lowlevel.h"
#include "terminal.h"



/*
 * Handles the given keyboard event, generally by putting the
 * corresponding sequence into the internal buffer.
 * Return values:
 * 	0: event was handled successfully
 * 	1: couldn't handle event because internal buffer is full
 */
int keyboard_handle_event (ggi_event event)
{
#ifdef DEBUG
	debug (DEBUG_INPUT, "GGI event fields:");
	debug (DEBUG_INPUT,
	       "\t- Key number (scancode): %ld, 0x%lX",
	       (unsigned long)event.key.button,
	       (unsigned long)event.key.button);
#ifdef MULTIBYTE
	if (GII_UNICODE (event.key.label) && iswprint ((wint_t) event.key.label)) {
		debug (DEBUG_INPUT,
		       "\t- Key label:             %lc [%ld, 0x%lX]",
		       (wint_t)event.key.label,
		       (unsigned long)event.key.label,
		       (unsigned long)event.key.label);
#else
	if (GII_UNICODE (event.key.label) && isprint ((int) event.key.label)) {
		debug (DEBUG_INPUT,
		       "\t- Key label:             %c [%ld, 0x%lX]",
		       (int)event.key.label,
		       (unsigned long)event.key.label,
		       (unsigned long)event.key.label);
#endif
	}
	else {
		debug (DEBUG_INPUT,
		       "\t- Key label:             ? [%ld, 0x%lX] (unprintable)",
		       (unsigned long)event.key.label,
		       (unsigned long)event.key.label);
	}
#ifdef MULTIBYTE
	if (GII_UNICODE (event.key.sym) && iswprint ((wint_t) event.key.sym)) {
		debug (DEBUG_INPUT,
		       "\t- Symbol produced:       %lc [%ld, 0x%lX]",
		       (wint_t)event.key.sym,
		       (unsigned long)event.key.sym,
		       (unsigned long)event.key.sym);
#else
	if (GII_UNICODE (event.key.sym) && isprint ((int) event.key.sym)) {
		debug (DEBUG_INPUT,
		       "\t- Symbol produced:       %c [%ld, 0x%lX]",
		       (int)event.key.sym,
		       (unsigned long)event.key.sym,
		       (unsigned long)event.key.sym);
#endif
	}
	else {
		debug (DEBUG_INPUT,
		       "\t- Symbol produced:       ? [%ld, 0x%lX] (unprintable)",
		       (unsigned long)event.key.sym,
		       (unsigned long)event.key.sym);
	}
	debug (DEBUG_INPUT, "\t- Modifiers:");
	if (event.key.modifiers & GII_MOD_SHIFT)
		debug (DEBUG_INPUT, "\t\tSHIFT");
	if (event.key.modifiers & GII_MOD_CTRL)
		debug (DEBUG_INPUT, "\t\tCTRL");
	if (event.key.modifiers & GII_MOD_ALT)
		debug (DEBUG_INPUT, "\t\tALT");
	if (event.key.modifiers & GII_MOD_META)
		debug (DEBUG_INPUT, "\t\tMETA");
	if (event.key.modifiers & GII_MOD_SUPER)
		debug (DEBUG_INPUT, "\t\tSUPER");
	if (event.key.modifiers & GII_MOD_HYPER)
		debug (DEBUG_INPUT, "\t\tHYPER");
	if (event.key.modifiers & GII_MOD_ALTGR)
		debug (DEBUG_INPUT, "\t\tALTGR");
	if (event.key.modifiers & GII_MOD_CAPS)
		debug (DEBUG_INPUT, "\t\tCAPS");
	if (event.key.modifiers & GII_MOD_NUM)
		debug (DEBUG_INPUT, "\t\tNUM");
	if (event.key.modifiers & GII_MOD_SCROLL)
		debug (DEBUG_INPUT, "\t\tSCROLL");
	debug (DEBUG_INPUT, "\t- Type:");
	if (GII_KTYP(event.key.sym) == GII_KT_LATIN1)
		debug (DEBUG_INPUT, "\t\tGII_KT_LATIN1");
	if (GII_KTYP(event.key.sym) == GII_KT_SPEC)
		debug (DEBUG_INPUT, "\t\tGII_KT_SPEC");
	if (GII_KTYP(event.key.sym) == GII_KT_FN)
		debug (DEBUG_INPUT, "\t\tGII_KT_FN");
	if (GII_KTYP(event.key.sym) == GII_KT_PAD)
		debug (DEBUG_INPUT, "\t\tGII_KT_PAD");
	if (GII_KTYP(event.key.sym) == GII_KT_MOD)
		debug (DEBUG_INPUT, "\t\tGII_KT_MOD");
	if (GII_KTYP(event.key.sym) == GII_KT_DEAD)
		debug (DEBUG_INPUT, "\t\tGII_KT_DEAD");
#endif /* DEBUG */
	
	/* For the keypad, we must ignore the symbol because it depends
	   on the NumLock state. vt100 says it is programmable (rmkx/smkx) */
	switch (event.key.label) {
		case GIIK_P1:
			if (ignore_keypad_num) {
				debug (DEBUG_INPUT, "You pressed [PAD DOWN LEFT]");
				return buffer_send_string ("\033Op");
			}
			break;
		case GIIK_P2:
			if (ignore_keypad_num) event.key.sym = GIIK_Down;
			break;
		case GIIK_P3:
			if (ignore_keypad_num) {
				debug (DEBUG_INPUT, "You pressed [PAD DOWN RIGHT]");
				return buffer_send_string ("\033On");
			}
			break;
		case GIIK_P4:
			if (ignore_keypad_num) event.key.sym = GIIK_Left;
			break;
		case GIIK_P5:
			if (ignore_keypad_num) {
				debug (DEBUG_INPUT, "You pressed [PAD CENTER]");
				return buffer_send_string ("\033Or");
			}
			break;
		case GIIK_P6:
			if (ignore_keypad_num) event.key.sym = GIIK_Right;
			break;
		case GIIK_P7:
			if (ignore_keypad_num) {
				debug (DEBUG_INPUT, "You pressed [PAD UP LEFT]");
				return buffer_send_string ("\033Oq");
			}
			break;
		case GIIK_P8:
			if (ignore_keypad_num) event.key.sym = GIIK_Up;
			break;
		case GIIK_P9:
			if (ignore_keypad_num) {
				debug (DEBUG_INPUT, "You pressed [PAD UP RIGHT]");
				return buffer_send_string ("\033Os");
			}
			break;
		case GIIK_PEnter:
			if (ignore_keypad_num) {
				debug (DEBUG_INPUT, "You pressed [KEYPAD ENTER]");
				return buffer_send_string ("\033OM");
			}
			break;
		case GIIUC_Tab:
			if (GII_KTYP(event.key.sym) == GII_KT_SPEC) {
				debug (DEBUG_INPUT, "You pressed [BACKTAB]");
				return buffer_send_string ("\033[Z");
			}
			break;
	}
		
	switch (event.key.sym) {
		case GIIK_Enter:
			debug (DEBUG_INPUT, "You pressed [ENTER]");
			return buffer_send_char ('\r');
			break;
		case GIIK_Left:
			debug (DEBUG_INPUT, "You pressed [LEFT]");
			return buffer_send_string ("\033OD");
			break;
		case GIIK_Right:
			debug (DEBUG_INPUT, "You pressed [RIGHT]");
			return buffer_send_string ("\033OC");
			break;
		case GIIK_Up:
			debug (DEBUG_INPUT, "You pressed [UP]");
			return buffer_send_string ("\033OA");
			break;
		case GIIK_Down:
			debug (DEBUG_INPUT, "You pressed [DOWN]");
			return buffer_send_string ("\033OB");
			break;
		case GIIK_PageUp:
			if (event.key.modifiers & GII_MOD_SHIFT) {
				debug (DEBUG_INPUT, "You pressed [SHIFT+PAGE-UP]");
				internal_page_up ();
			} else {
				debug (DEBUG_INPUT, "You pressed [PAGE-UP]");
				return buffer_send_string ("\033[5~");
			}
			break;
		case GIIK_PageDown:
			if (event.key.modifiers & GII_MOD_SHIFT) {
				debug (DEBUG_INPUT, "You pressed [SHIFT+PAGE-DOWN]");
				internal_page_down ();
			} else {
				debug (DEBUG_INPUT, "You pressed [PAGE-DOWN]");
				return buffer_send_string ("\033[6~");
			}
			break;
		/*case GIIK_End:
			debug (DEBUG_INPUT, "You pressed [END]");
			return buffer_send_string ("\033Op");
			break;*/
		case GIIK_Home:
			debug (DEBUG_INPUT, "You pressed [HOME]");
			return buffer_send_string ("\033[H");
			break;
		case GIIK_Insert:
			debug (DEBUG_INPUT, "You pressed [INSERT]");
			return buffer_send_string ("\033[L");
			break;
		case GIIK_F0:
			debug (DEBUG_INPUT, "You pressed [F0]");
			return buffer_send_string ("\033Oy");
			break;
		case GIIK_F1:
			debug (DEBUG_INPUT, "You pressed [F1]");
			return buffer_send_string ("\033OP");
			break;
		case GIIK_F2:
			debug (DEBUG_INPUT, "You pressed [F2]");
			return buffer_send_string ("\033OQ");
			break;
		case GIIK_F3:
			debug (DEBUG_INPUT, "You pressed [F3]");
			return buffer_send_string ("\033OR");
			break;
		case GIIK_F4:
			debug (DEBUG_INPUT, "You pressed [F4]");
			return buffer_send_string ("\033OS");
			break;
		case GIIK_F5:
			debug (DEBUG_INPUT, "You pressed [F5]");
			return buffer_send_string ("\033Ot");
			break;
		case GIIK_F6:
			debug (DEBUG_INPUT, "You pressed [F6]");
			return buffer_send_string ("\033Ou");
			break;
		case GIIK_F7:
			debug (DEBUG_INPUT, "You pressed [F7]");
			return buffer_send_string ("\033Ov");
			break;
		case GIIK_F8:
			debug (DEBUG_INPUT, "You pressed [F8]");
			return buffer_send_string ("\033Ol");
			break;
		case GIIK_F9:
			debug (DEBUG_INPUT, "You pressed [F9]");
			return buffer_send_string ("\033Ow");
			break;
		case GIIK_F10:
			debug (DEBUG_INPUT, "You pressed [F10]");
			return buffer_send_string ("\033Ox");
			break;
		/* The following are not strictly needed: the cases are handled
		   by the default section but this way debugging output is not
		   messed up! */
		case GIIUC_BackSpace:
			debug (DEBUG_INPUT, "You pressed [BACKSPACE]");
			/*return buffer_send_char (0x08);*/
			/* the vt100 BackSpace key sends ^? (DEL), so do we */
			return buffer_send_char (0x7F);
			break;
		case GIIUC_Delete:
			debug (DEBUG_INPUT, "You pressed [DELETE]");
			/*return buffer_send_char (0x7F);*/
			/* DEL is sent by BackSpace in vt100 and Delete doesn't
			   exist. vt220 introduced a Delete key mapped to \E[3~
			   so we use this */
			return buffer_send_string ("\033[3~");
			break;
		case GIIUC_Tab:
			debug (DEBUG_INPUT, "You pressed [TAB]");
			return buffer_send_char (0x09);
			break;
		default:
			if (GII_UNICODE(event.key.sym)) {
#ifdef DEBUG
#ifdef MULTIBYTE
				if (iswprint ((wint_t) event.key.sym)) {
					debug (DEBUG_INPUT,
					       "You pressed the key: '%lc'",
					       (wint_t)event.key.sym);
#else /* MULTIBYTE */
				if (isprint ((int) event.key.sym)) {
					debug (DEBUG_INPUT,
					       "You pressed the key: '%c'",
					       (int)event.key.sym);
#endif /* MULTIBYTE */
				} else {
					debug (DEBUG_INPUT,
					       "You pressed the key: '?' (unprintable)");
				}
#endif /* DEBUG */
				debug (DEBUG_INPUT, "Unicode -> passed on");
				return buffer_send_char ((wchar_t)event.key.sym);
			} else {
				debug (DEBUG_INPUT,
				       "You pressed the key: [UNICODE PRIVATE RANGE - GGI INTERNAL USE]");
				debug (DEBUG_INPUT, "NOT Unicode -> ignored");
			}
	}
	return 0;
}
