/**
 * Keyboard translation code
 * (C) Nettle developers 2000-2001
 *
 * $Id: keyboard,v 1.12 2002/12/01 17:22:56 archifishal Exp $
 */


#include "generic.h"
#include "globals.h"

#include "keyboard.h"
#include "seln.h"
#include "wimp.h"


bool inkey (int key)
{
  return _swi(OS_Byte, _INR(0,2)|_RETURN(1), 129, key & 255, key >> 8)
    ? true : false;
}


static int
setmod (char *block, const char *key, int extra)
{
  int length = strlen (key);

  strncpy (block, key, length);

  extra = (extra | extra >> 1) & 0x5;	/* modifier keys: ccss -> 0c0s */
  block[length] = "~$  ^@"[extra];

  return length + 1;
}



int
decode_key (struct session_struct *session, int key, int extra, char *block)
{
#define SETBLOCK(LEN,STR) { strcpy (block, STR); return LEN; }
  int ekey = extra >> 16;
#define APPLI(TRUE,FALSE) \
  ((session->other_session_flags & NETTLE_OTHER_APPLI_MODE) ? TRUE : FALSE)

  switch (key)
  {
  case 0x008:			/* Backspace */
    if (ekey == 30 && (session->other_session_flags & NETTLE_OTHER_BACKSPACE_MODE))
    {
      SETBLOCK (1, "\x7F");
    }
    else
    {
      SETBLOCK (1, "\b");
    }
  case 0x00D:			/* Return */
    if (ekey == 103 &&
	(((session->other_session_flags & NETTLE_OTHER_APPLI_MODE) != 0) ^
	 ((extra & 0x3) != 0)))
    {
      SETBLOCK (3, "\x1BOM");	/* Enter */
    }
      /* Leaving this as it is for now - it's more likely to break things if we change it */
      /* now IMO - leave it til post 1st Sep */
    #ifdef KEYBOARD_RETURN_BODGE
    else if (session->other_session_flags & NETTLE_OTHER_LINEFEED_MODE)
    {
      SETBLOCK (2, "\r\n");
    }
    else
    {
      SETBLOCK (1, "\r");
    }
    #else
    else if (session->connection_type == NETTLE_TASKWINDOW)
    {
      SETBLOCK (1, "\r");
    }
    else if (session->other_session_flags & NETTLE_OTHER_LINEFEED_MODE)
    {
      SETBLOCK (3, "\r\n\n");
    }
    else
    {
      SETBLOCK (2, "\r\n");
    }
    #endif
  case 0x01E:			/* Home */
    if (ekey != 32)
    {
      SETBLOCK (1, "\x1E");
    }
    else
    {
      return setmod (block, "\x1B[1", extra);
    }
  case 0x07F:			/* Delete */
    if (session->other_session_flags & NETTLE_OTHER_BACKSPACE_MODE)
    {
      return setmod (block, "\x1B[3", extra);
    }
    else
    {
      SETBLOCK (1, "\x7F");
    }

  case 0x181:			/* F1 */
    SETBLOCK (3, "\x1BOP");
  case 0x182:			/* F2 */
    SETBLOCK (3, "\x1BOQ");
  case 0x183:			/* F3 */
    SETBLOCK (3, "\x1BOR");
  case 0x184:			/* F4 */
    SETBLOCK (3, "\x1BOS");
  case 0x185:			/* F5 */
    SETBLOCK (5, "\x1B[15~");
  case 0x186:			/* F6 */
    SETBLOCK (5, "\x1B[17~");
  case 0x187:			/* F7 */
    SETBLOCK (5, "\x1B[18~");
  case 0x188:			/* F8 */
    SETBLOCK (5, "\x1B[19~");
  case 0x189:			/* F9 */
    SETBLOCK (5, "\x1B[20~");
  case 0x18A:			/* Tab */
    SETBLOCK (1, "\t");
  case 0x18B:			/* Copy */
    SETBLOCK (4, "\x1B[4~");
  case 0x18C:			/* Left */
    SETBLOCK (3, APPLI ("\x1BOD", "\x1B[D"));
  case 0x18D:			/* Right */
    SETBLOCK (3, APPLI ("\x1BOC", "\x1B[C"));
  case 0x18E:			/* Down, sPageDown */
    if (ekey != 54)
    {
      SETBLOCK (3, APPLI ("\x1BOB", "\x1B[B"));
    }
  case 0x18F:			/* Up, sPageUp */
    if (ekey != 33)
    {
      SETBLOCK (3, APPLI ("\x1BOA", "\x1B[A"));
    }
  case 0x191:			/* sF1 */
    SETBLOCK (5, "\x1B[23~");
  case 0x192:			/* sF2 */
    SETBLOCK (5, "\x1B[24~");
  case 0x193:			/* sF3 */
    SETBLOCK (5, "\x1B[25~");
  case 0x194:			/* sF4 */
    SETBLOCK (5, "\x1B[26~");
  case 0x195:			/* sF5 */
    SETBLOCK (5, "\x1B[28~");
  case 0x196:			/* sF6 */
    SETBLOCK (5, "\x1B[29~");
  case 0x197:			/* sF7 */
    SETBLOCK (5, "\x1B[31~");
  case 0x198:			/* sF8 */
    SETBLOCK (5, "\x1B[32~");
  case 0x199:			/* sF9 */
    SETBLOCK (5, "\x1B[33~");
  case 0x19A:			/* sTab */
    SETBLOCK (3, "\x1B[Z");
  case 0x19B:			/* sCopy */
    SETBLOCK (4, "\x1B[4$");
  case 0x19C:                   /* sLeft */
    SETBLOCK (3, APPLI ("\x1BOd", "\x1B[d"));
  case 0x19D:                   /* sRight */
    SETBLOCK (3, APPLI ("\x1BOc", "\x1B[c"));
  case 0x19E:			/* PgDown, sDown */
    if (ekey == 99)
    {
      SETBLOCK (3, APPLI ("\x1BOb", "\x1B[b"))
    }
    else
    {
      SETBLOCK (4, "\x1B[6~")
    }
  case 0x19F:			/* PgUp, sUp */
    if (ekey == 89)
    {
      SETBLOCK (3, APPLI ("\x1BOa", "\x1B[a"))
    }
    else
    {
      SETBLOCK (4, "\x1B[5~")
    }

  case 0x1A1:			/* cF1 */
    SETBLOCK (3, "\x1B[11^");
  case 0x1A2:			/* cF2 */
    SETBLOCK (3, "\x1B[12^");
  case 0x1A3:			/* cF3 */
    SETBLOCK (3, "\x1B[13^");
  case 0x1A4:			/* cF4 */
    SETBLOCK (3, "\x1B[14^");
  case 0x1A5:			/* cF5 */
    SETBLOCK (5, "\x1B[15^");
  case 0x1A6:			/* cF6 */
    SETBLOCK (5, "\x1B[17^");
  case 0x1A7:			/* cF7 */
    SETBLOCK (5, "\x1B[18^");
  case 0x1A8:			/* cF8 */
    SETBLOCK (5, "\x1B[19^");
  case 0x1A9:			/* cF9 */
    SETBLOCK (5, "\x1B[20^");
  case 0x1AA:			/* cTab */
    SETBLOCK (1, "\t");
  case 0x1AB:			/* cCopy */
    SETBLOCK (4, "\x1B[4^");
  case 0x1AC:			/* cLeft */
    SETBLOCK (3, APPLI ("\x1B[d", "\x1BOd"));
  case 0x1AD:			/* cRight */
    SETBLOCK (3, APPLI ("\x1B[c", "\x1BOc"));
  case 0x1AE:			/* scPgDown, cDown */
    if (ekey == 99)
    {
      SETBLOCK (3, APPLI ("\x1B[b", "\x1BOb"));
    }
    else
    {
      SETBLOCK (4, "\x1B[6@");
    }
  case 0x1AF:			/* scPgUp, cUp */
    if (ekey == 89)
    {
      SETBLOCK (3, APPLI ("\x1B[a", "\x1BOa"));
    }
    else
    {
      SETBLOCK (4, "\x1B[5@");
    };

  case 0x1B1:			/* csF1 */
    SETBLOCK (5, "\x1B[23^");
  case 0x1B2:			/* csF2 */
    SETBLOCK (5, "\x1B[24^");
  case 0x1B3:			/* csF3 */
    SETBLOCK (5, "\x1B[25^");
  case 0x1B4:			/* csF4 */
    SETBLOCK (5, "\x1B[26^");
  case 0x1B5:			/* csF5 */
    SETBLOCK (5, "\x1B[28^");
  case 0x1B6:			/* csF6 */
    SETBLOCK (5, "\x1B[29^");
  case 0x1B7:			/* csF7 */
    SETBLOCK (5, "\x1B[31^");
  case 0x1B8:			/* csF8 */
    SETBLOCK (5, "\x1B[32^");
  case 0x1B9:			/* csF9 */
    SETBLOCK (5, "\x1B[33~");
  case 0x1BA:			/* csTab */
    SETBLOCK (3, "\x1B[Z");
  case 0x1BB:			/* csCopy */
    SETBLOCK (4, "\x1B[4@");
  case 0x1BC:			/* scLeft */
    SETBLOCK (3, APPLI ("\x1B[d", "\x1BOd"));
  case 0x1BD:			/* scRight */
    SETBLOCK (3, APPLI ("\x1B[c", "\x1BOc"));
  case 0x1BE:			/* cPgDown, scDown */
    if (ekey == 99)
    {
      SETBLOCK (3, APPLI ("\x1BOb", "\x1B[b"));
    }
    else
    {
      SETBLOCK (4, "\x1B[6^");
    }
  case 0x1BF:			/* cPgUp, scUp */
    if (ekey == 89)
    {
      SETBLOCK (3, APPLI ("\x1BOa", "\x1B[a"));
    }
    else
    {
      SETBLOCK (4, "\x1B[5^");
    }

  case 0x1CA:			/* F10 */
    SETBLOCK (5, "\x1B[21~");
  case 0x1CB:			/* F11 */
    SETBLOCK (5, "\x1B[23~");
  case 0x1CC:			/* F12 */
    SETBLOCK (5, "\x1B[24~");
  case 0x1CD:			/* Insert */
    SETBLOCK (4, "\x1B[2~");

  case 0x1DA:			/* sF10 */
    SETBLOCK (5, "\x1B[34~");
  case 0x1DB:			/* sF11 */
    SETBLOCK (5, "\x1B[23~");
  case 0x1DC:			/* sF12 */
    SETBLOCK (5, "\x1B[24~");

  case 0x1EA:			/* cF10 */
    SETBLOCK (5, "\x1B[21^");
  case 0x1EB:			/* cF11 */
    SETBLOCK (5, "\x1B[23^");
  case 0x1EC:			/* cF12 */
    SETBLOCK (5, "\x1B[24^");
  case 0x1ED:			/* cInsert */
    SETBLOCK (4, "\x1B[2^");

  case 0x1FA:			/* csF10 */
    SETBLOCK (5, "\x1B[34^");
  case 0x1FB:			/* csF11 */
    SETBLOCK (5, "\x1B[23^");
  case 0x1FC:			/* csF12 */
    SETBLOCK (5, "\x1B[24^");
  case 0x1FD:			/* csInsert */
    SETBLOCK (4, "\x1B[2@");

  default:
    if (((session->other_session_flags & NETTLE_OTHER_APPLI_MODE) != 0) ^
	((extra & 0x3) != 0))
      /* application keypad *eor* Shift pressed */
      switch (key)
      {
      case '0':		/* keypad 0 */
	if (ekey == 101)
	  SETBLOCK (3, "\x1BOp");
	break;
      case '1':		/* keypad 1 */
	if (ekey == 90)
	  SETBLOCK (3, "\x1BOq");
	break;
      case '2':		/* keypad 2 */
	if (ekey == 91)
	  SETBLOCK (3, "\x1BOr");
	break;
      case '3':		/* keypad 3 */
	if (ekey == 92)
	  SETBLOCK (3, "\x1BOs");
	break;
      case '4':		/* keypad 4 */
	if (ekey == 72)
	  SETBLOCK (3, "\x1BOt");
	break;
      case '5':		/* keypad 5 */
	if (ekey == 73)
	  SETBLOCK (3, "\x1BOu");
	break;
      case '6':		/* keypad 6 */
	if (ekey == 74)
	  SETBLOCK (3, "\x1BOv");
	break;
      case '7':		/* keypad 7 */
	if (ekey == 55)
	  SETBLOCK (3, "\x1BOw");
	break;
      case '8':		/* keypad 8 */
	if (ekey == 56)
	  SETBLOCK (3, "\x1BOx");
	break;
      case '9':		/* keypad 9 */
	if (ekey == 57)
	  SETBLOCK (3, "\x1BOy");
	break;
      case '+':		/* keypad + */
	if (ekey == 75)
	  SETBLOCK (3, "\x1BOl"); /* should be on ','... */
	break;
      case '-':		/* keypad - */
	if (ekey == 58)
	  SETBLOCK (3, "\x1BOm");
	break;
      case '.':		/* keypad . */
	if (ekey == 102)
	  SETBLOCK (3, "\x1BOn");
	break;
      case 0x0D:		/* Enter */
	if (ekey == 57)
	  SETBLOCK (3, "\x1BOM");
	break;
      }
    if (key < 0x100)
    {
      sprintf (block, "%c", key);
      return 1;
    }
  }
  return 0;
}
