/*
 * keybrd.ti:
 *	functions, maps and interrupt handlers for TI Pro keyboards
 *
 * Copyright (c) 1989 University of Toronto. All rights reserved.
 * Anyone may use or copy this software, except that it may not be
 * sold for profit, that this copyright notice remain intact, and that
 * credit is given where it is due. The University of Toronto and the
 * author make no warranty and accept no liability for this software.
 */
static char rcsid[] = "$Header: keybrd.ti,v 1.6 89/02/23 20:39:31 pkern Exp $";

#include <dos.h>
#include "cterm.h"
#include "ti.h"

#define word	unsigned int

uchar kqueued=0, keyboom=0;

static union REGS r;
static uchar f_map=0, f_vec=0, kb_mode=0;

extern int (*xmit)();
extern uchar flowctl, local, xoff;

/* check for queued keys */
kbdhit()
{
#ifdef KBDQUE
	return (kqueued);
#else
	r.h.ah = 1;
	int86(KBD_INT, &r, &r);
	return (!(r.x.flags & Zflag));	/* ie. ! Z-flag */
#endif
}

/* flush keyboard type-ahead queue */
kbflush()
{
	r.h.ah = 3;
	int86(KBD_INT, &r, &r);
	kqueued = 0;
}

/* toggle keyboard autorepeat */
kbautorep(sw)
int sw;	/* switch : 1 = on, 0 = off */
{
	r.h.ah = 4;
	r.h.al = (sw) ? 1 : 2;
	int86(KBD_INT, &r, &r);
}

/* get keyboard word */
word
kbdget()
{
	r.h.ah = 2; int86(KBD_INT, &r, &r);
	kb_mode = r.h.al;
	r.h.ah = 0; int86(KBD_INT, &r, &r);
	kqueued--;
	return((word) r.x.ax);
}

/* return a keypadv[] offset | 8-bit alternative */
kbdfn(kn)
word kn;
{
	word fn;
	extern word keymap[], alt8[];

	kn = kn >> 8;
	fn = alt8[kn] & 0x7f;
	if (fn) {
		if (kb_mode & 0x01)	/* CTRL key */
			fn = (alt8[kn] >> 8) & 0x3f;
		else if (kb_mode & 0x04)	/* SHIFT key */
			fn = alt8[kn] >> 8;
		kb_mode = 0;
		fn |= 0x80;
	}
	return((fn << 8) | keymap[kn]);
}

/*
 *  keypad map (aN = alt N, cN = ctrl N, sN = shift N)
 * +-----+-----+-----+-----+
 * | PF1 | PF2 | PF3 | PF4 |		cursor code offsets:
 * | aF1 | aF2 | aF3 | aF4 |		       UP - 0
 * +-----+-----+-----+-----+		       DOWN - 1
 * |  7  |  8  |  9  |  -  |		       RIGHT - 2
 * | a1  | a2  | a3  | a4  |		       LEFT - 3
 * | F5  | F6  | F7  | F8  |
 * +-----+-----+-----+-----+
 * |  4  |  5  |  6  |  ,  |	keypad code string offsets:
 * | aQ  | aW  | aE  | aR  |	8 - "0"	 10 - "8"	18 - "F3"
 * | cF5 | cF6 | cF7 | cF8 |	9 - "1"  11 - "9"	19 - "F4"
 * +-----+-----+-----+-----+	A - "2"  12 - "-"	1A - "\200"
 * |  1  |  2  |  3  | aF  |	B - "3"  13 - ","	1B - "\b"
 * | aA  | aS  | aD  | aF8 |	C - "4"  14 - "."	1C - "\003"
 * | aF5 | aF6 | aF7 |     |	D - "5"  15 - "ENTER"	1D - "\r\n"
 * +-----+-----+-----+Enter|	E - "6"  16 - "F1"	1E *-> ansback
 * |     0     |  .  |     |	F - "7"  17 - "F2"	1F - ""	 (empty)
 * | aZ    aX  | aC  | aV  |
 * | sF5   sF6 | sF7 | sF8 |
 * +-----------+-----+-----+
 */


/*
 * keymap:
 *	keypadv[] offsets for all (ie. 90H) extended function codes
 */
static word keymap[0x90] = {
/* 0x0_ */	0x1f, 0x1f, 0x1f, 0x1a, 0x1f, 0x1f, 0x1f, 0x1f,
		0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x1f, 0x1f,
/* 0x1_ */	0x0c, 0x0d, 0x0e, 0x13, 0x1f, 0x1f, 0x1f, 0x1f,
		0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x09, 0x0a,
/* 0x2_ */	0x0b, 0x15, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
		0x1f, 0x1f, 0x1f, 0x1f, 0x08, 0x08, 0x14, 0x15,
/* 0x3_ */	0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
		0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1b, 0x0f,
/* 0x4_ */	0x10, 0x11, 0x12, 0x00, 0x01, 0x03, 0x02, 0x1f,
		0x00, 0x00, 0x1f, 0x03, 0x03, 0x02, 0x02, 0x1f,
/* 0x5_ */	0x01, 0x01, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
		0x08, 0x08, 0x14, 0x15, 0x00, 0x01, 0x1f, 0x1f,
/* 0x6_ */	0x1f, 0x1f, 0x0c, 0x0d, 0x0e, 0x13, 0x00, 0x01,
		0x16, 0x17, 0x18, 0x19, 0x09, 0x0a, 0x0b, 0x15,
/* 0x7_ */	0x00, 0x01, 0x1f, 0x03, 0x02, 0x1f, 0x01, 0x1f,
		0x0f, 0x10, 0x11, 0x12, 0x1f, 0x1f, 0x1f, 0x1f,
/* 0x8_ */	0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
		0x00, 0x01, 0x02, 0x03, 0x16, 0x17, 0x18, 0x19
};

/*
 * alt8:
 *	keymap[] ALTernatives with 8th bit set.
 *	(Turbo C direct storage: 'lsb msb')
 */
static word alt8[0x90] = {
/* 0x0_ */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x1_ */	'qQ', 'wW', 'eE', 'rR',
		'tT', 'yY', 'uU', 'iI',
		'oO', 'pP', 0, 0, 0, 0, 'aA', 'sS',
/* 0x2_ */	'dD', 'fF', 'gG', 'hH',
		'jJ', 'kK', 'lL', 0, 0, 0, 0, 0,
		'zZ', 'xX', 'cC', 'vV',
/* 0x3_ */	'bB', 'nN', 'mM', 
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x4_ */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x5_ */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x6_ */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x7_ */	0, 0, 0, 0, 0, 0, 0, 0,
		'1!', '2@', '3#', '4$',
		'5%', '6^', '7&', '8*',
/* 0x8_ */	'9(', '0)', '-_', '=+',
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* k_brk -- intercept SHIFT BRK/PAUS interrupt */
void interrupt
k_brk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
	flags |= Cflag;		/* ie. don't queue it */
	keyboom++;
}	

/* k_paus -- intercept PAUS key interrupt */
void interrupt
k_paus(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
	if (flowctl && !local)
		if (xoff)
			{ xmit(XON); xoff = 0; }
		else
			{ xmit(XOFF); xoff++; }
	flags |= Cflag;		/* don't queue it */
}

/* k_que -- take note of new keystroke in buffer */
void interrupt
k_que()
{
	kqueued++;
/*	outport(0,7);	/* simple but pathetic-sounding keyclick */
}

/*
 * remap: table of scan codes for remapping TI Pro keypad
 *	- new scan values for scan codes 27 -> 44
 *	 (first 4 bits = ctrl/alt/shift bit choice
 *	   last 8 bits = the new scan code)
 * 0 = scan code unused (ie. it should never occur)
 */
static unsigned int remap[22] = {
	0x217, 0x218, 0x219, 0x21a,
	0x201, 0, 0x401, 0x204,
	0x101, 0x102, 0x003, 0x004,
	0x202, 0,   0,   0,
	0x001, 0x002, 0x103, 0x104,
	0x203, 0x403
};

/* k_map -- remap keypad scan codes */
void interrupt
k_map(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
	uchar al, ah;

	al = ax & 0xff; ah = (ax >> 11);
	if (al < 45 && al > 22)
		ax = (ah << 11) + remap[al-23];
	else if ((ax & 0x300) && al == 81)	/* CTRL/ALT-SPACE */
		ax = (ax & 0xff00) | 10;	/* CTRL/ALT-2@ */
}

/*
 * o_brk, o_paus, o_que, o_map:
 *	temp storage for old interrupt vectors
 */
void interrupt (*o_brk)();
void interrupt (*o_paus)();
void interrupt (*o_que)();
void interrupt (*o_map)();

init_kbd()
{
	if (f_vec) return(0);

	kbflush();

	/* remember old intr vector(s) */
	o_brk = getvect(KEYBRK);
	o_paus = getvect(KEYPAUS);
	o_que = getvect(KBDQUE);
	o_map = getvect(KBDMAP);
	/* install new one(s) */
	disable();
	setvect(KEYBRK, k_brk);
	setvect(KEYPAUS, k_paus);
	setvect(KBDQUE, k_que);
	setvect(KBDMAP, k_map);
	enable();

	f_vec = 1;	/* vector(s) installed */

	/* some important key mappings */
	keymap[K_SETUP >> 8] = 0x80;	/* flag the SETUP key */
	keymap[(K_SETUP >> 8)+1] = 0x80;	/* ditto on F2 */
	keymap[K_shBRK >> 8] = 0x40;	/* shiftBrk - hang up */
	keymap[K_NUL >> 8] = 0x41;	/* ctrl-2@  - send NUL */
	keymap[K_BREAK >> 8] = 0x42;	/* BREAK    - send BREAK */
	keymap[K_BKSP >> 8] = 0x1b;	/* backsp keypadv[] position */
	keymap[K_cBRK >> 8] = 0x1e;	/* ctrlBrk keypadv[] position */
	keyboom = 0;
}

reset_kbd()
{
	if (!f_vec) return;	/* no vectors to reset, yet */

	kbflush();

	/* restore old intr vector(s) */
	disable();
	setvect(KEYBRK, o_brk);
	setvect(KEYPAUS, o_paus);
	setvect(KBDQUE, o_que);
	setvect(KBDMAP, o_map);
	enable();

	f_vec = 0;	/* vector(s) reset */
}

/* switch newline mode */
nlmod(sw)
uchar sw;
{
	/* shift ENTER offset, if needed */
	keymap[0x21] = keymap[0x2f] = ((sw) ? 0x1d : 0x15);
}
