/*                      KBD.C
*       Terminal independent keyboard handling.
*/
#include    "def.h"

char    *keystrings ();

extern    char    MSG_tab[];
extern    char    MSG_esc[];
extern    char    MSG_ctl_x[];
extern    char    MSG_ctl[];
extern    char    MSG_fn[];
extern    char    MSG_ret[];
extern    char    MSG_bksp[];
extern    char    MSG_space[];
extern    char    MSG_rubout[];


/*
* Read in a key, doing the terminal
* independent prefix handling. The terminal specific
* "getkbd" routine gets the first swing, and may return
* one of the special codes used by the special keys
* on the keyboard. The "getkbd" routine returns the
* C0 controls as received; this routine moves them to
* the right spot in 11 bit code.
*/
int     getkey ()
{

	register int    c;
	c = getkbd ();
	if (c == METACH)            /* M-           */
	{
		c = KMETA | getctl ();
#ifdef VT100KEY
		if ((c & KCHAR) == '[')
			c = KMETA | KCTRL | KCTLX | getctl ();	/* flag VT100 sequence */
#endif
	}
	else if (c == CTRLCH)        /* C-           */
		c = KCTRL | getctl ();
	else if (c == CTMECH)    /* C-M-         */
		c = KCTRL | KMETA | getctl ();
	else if (c >= 0x00 && c <= 0x1F)/* Relocate control.    */
		c = KCTRL | (c + '@');

	if (c == (KCTRL | 'X'))     /* C-X          */
		c = KCTLX | getctl ();
	return (c);
}


/*
* Used above.
*/
int     getctl ()
{

	register int    c;

#if 1
	c = getkbd ();
	if (c == METACH)            /* M-           */
		c = KMETA | getctl ();
	else
		if (c == CTRLCH)        /* C-           */
			c = KCTRL | getctl ();
		else
			if (c == CTMECH)    /* C-M-         */
				c = KCTRL | KMETA | getctl ();
			else
				if (c >= 0x00 && c <= 0x1F)/* Relocate control.    */
					c = KCTRL | (c + '@');
#else
	c = getkey ();              /* Note recursion   */
	if (ISLOWER (c & 0xFF))
		c = (c & ~0xFF) | TOUPPER (c & 0xFF);
	if (c >= 0x00 && c <= 0x1F) /* Relocate control.    */
		c = KCTRL | (c + '@');
#endif
	if (ISLOWER (c & 0xFF))
		c = (c & ~0xFF) | TOUPPER (c & 0xFF);
	return (c);
}


/*
* Transform a key code into a name,
* using a table for the special keys and combination
* of some hard code and some general processing for
* the rest. None of this code is terminal specific any
* more. This makes adding keys easier.
*/
void keyname (cp, k)
register char  *cp;
register int    k;
{
	register char  *np;
	char    nbuf[3];

	static char hex[] =
	{
		'0', '1', '2', '3',
		'4', '5', '6', '7',
		'8', '9', 'A', 'B',
		'C', 'D', 'E', 'F'
	};
	*cp = 0;	/* terminate previous string */
#ifdef VT100KEY
	if ((k & (KMETA | KCTRL | KCTLX)) == (int)(KMETA | KCTRL | KCTLX))
	{
		sprintf (&cp[strlen (cp)], MSG_fn);
		sprintf (&cp[strlen (cp)], "%c", k & KCHAR);
		return;
	}
#endif
	if (k & 0x80)
	{
		if ((np = keystrings (k)) != NULL)
		{
			if ((k & KMETA) != 0)
				sprintf (&cp[strlen (cp)], MSG_esc);

			strcat (cp, np);
		}
		else
			cp[strlen (cp)] = 0;    /* null string */
		return;
	}

	if ((k & KCTLX) != 0)
	{
		/* Ctl-X prefix.      */
		sprintf (&cp[strlen (cp)], MSG_ctl_x);
		k &= ~KCTLX;
	}

	if ((k & KMETA) != 0)
	{
		/* Add Esc- mark.     */
		sprintf (&cp[strlen (cp)], MSG_esc);
		k &= ~KMETA;
	}

	if (k == (KCTRL | 'I'))/* Some specials.   */
		np = MSG_tab;
	else
	{
		if (k == (KCTRL | 'M'))
			np = MSG_ret;
		else if (k == (KCTRL | 'H'))
			np = MSG_bksp;
		else if (k == ' ')
			np = MSG_space;
		else if (k == 0x7F)
			np = MSG_rubout;
		else
		{
			if ((k & KCTRL) != 0)
			{
				/* Add Ctl- mark.     */
				sprintf (&cp[strlen (cp)], MSG_ctl);
			}
			np = &nbuf[0];
			if (((k & KCHAR) >= 0x20 && (k & KCHAR) <= 0x7E)
			    || ((k & KCHAR) >= 0xA0 && (k & KCHAR) <= 0xFE))
			{
				nbuf[0] = k & KCHAR;/* Graphic.     */
				nbuf[1] = 0;
			}
			else
			{
				/* Non graphic.     */
				nbuf[0] = hex[(k >> 4) & 0x0F];
				nbuf[1] = hex[k & 0x0F];
				nbuf[2] = 0;
			}
		}
	}
	strcat (cp, np);
}

