;
;	Command & Conquer Red Alert(tm)
;	Copyright 2025 Electronic Arts Inc.
;
;	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 3 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, see <http://www.gnu.org/licenses/>.
;

;***************************************************************************
;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
;***************************************************************************
;*                                                                         *
;*                 Project Name : Library                                  *
;*                                                                         *
;*                    File Name : KEYINTR.ASM                              *
;*                                                                         *
;*                   Programmer : Christopher Yates                        *
;*                                                                         *
;*                   Start Date : May 21, 1992                             *
;*                                                                         *
;*                  Last Update : July 13, 1994   [PWG]                    *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;*   KeyNum_Translate -- Translates the given keynum to ???                *
;*   Install_Interrupt -- Installs the keyboard interrupt                  *
;*   Stuff_Key_Word -- Stuffs a word of data into keyboard buffer          *
;*   Stuff_Key_Num -- Stuffs a key num code into the circular buffer       *
;*   Remove_Interrupt -- Removes the keyboard interrupt and restores the chai*
;*   Keystroke_Interrupt -- Handles input that comes from the keyboard     *
;*   Break_Interrupt -- Handles the break key interrupt                    *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
;*									   *
;*	Keyboard driver -- 8086 Assembly portion;			   *
;*	updated by: Phil Gorrow for 32 bit Protected Mode		   *
;***************************************************************************

;---------------------------------------------------------------------------
; Set the assembly directives
;---------------------------------------------------------------------------
IDEAL				; the product runs in ideal mode
P386N				; use 386 real mode instructions
MODEL TINY			; code must be tiny so it fits
LOCALS ??			; ?? is the symbol for a local
WARN				; generate all warnings we can
JUMPS				; optimize jumps if possible

;---------------------------------------------------------------------------
; Include all of the keyboard specific defines
;---------------------------------------------------------------------------
INCLUDE "keyboard.inc"

CODESEG


SoundOn		DW	1	; toggled by alt S
MusicOn		DW	1	; toggled by alt M
KeyFlags	DW	REPEATON+CTRLALTTURBO	; all but repeat for now


Break		DW	0

KeyMouseMove	DB	-1,0,1
		DB	-16,0,16

ScreenEdge	DW	320/2,0		; North
		DW	319,0		; North-East
		DW	319,138/2	; East
		DW	319,137		; South-East
		DW	320/2,137	; South
		DW	0,137		; South-West
		DW	0,138/2		; West
		DW	0,0		; North-West
		DW	320/2,138/2	; Center


Bits		DB	01H,02H,04H,08H,10H,20H,40H,80H

CondPassKey	DW	0220H, 0320H, 060CH, 070DH, 066AH
		DW	0669H, 0230H, 0330H, 007DH, 017DH
		DW	025AH, 035AH, 0200H, 0410H, 046EH
		DW	026EH, 007CH

CondPassCond	DW	CTRLSON, CTRLSON, CTRLALTTURBO, CTRLALTTURBO, CTRLALTTURBO
		DW	CTRLALTTURBO, CTRLCON, CTRLCON, SCROLLLOCKON, SCROLLLOCKON
		DW	PAUSEON, PAUSEON, BREAKON, TASKSWITCHABLE, TASKSWITCHABLE
		DW	TASKSWITCHABLE, BREAKON

EscRoutine	DD	0	; vector to execute on esc key press (0=none)

; Extended raw keycodes to be converted to Westwood keycodes.
ExtCodes	DB	038H,01DH,052H,053H,04BH,047H,04FH,048H,050H,049H
		DB	051H,04DH,035H,01CH,037H
		DB	046H
; The matching Westwood keycodes.
ExtNums		DB	62,  64,  75,  76,  79,  80,  81,  83,  84,  85
		DB	86,  89,  95, 108, 124,  0
; If extended mapping is disabled, then these codes really are...
ExtRemap	DB	60,  58,  99, 104,  92,  91,  93,  96,  98, 101
		DB	103, 102, 55,  43, 124,  0
ExtRemapEnd	DB	0

ExtKeyboard	DB	0	; flag for 101/102-key keyboard


KeyBuffer	DW	128 DUP(0) ; set to empty
KeyBufferHead	DW	0	; set to first entry
KeyBufferTail	DW	0	; set to head for empty buffer
KeyLock		DW	0	; num and caps lock bits
KeyNums		DB	127,110,002,003,004,005,006,007,008,009,010,011,012,013,015,016
		DB	017,018,019,020,021,022,023,024,025,026,027,028,043,058,031,032
		DB	033,034,035,036,037,038,039,040,041,001,044,029,046,047,048,049
		DB	050,051,052,053,054,055,057,100,060,061,030,112,113,114,115,116
		DB	117,118,119,120,121,090,125,091,096,101,105,092,097,102,106,093
		DB	098,103,099,104,127,127,127,122,123

KeysCapsLock	DB	0,0,0FEH,087H,0FFH,0C0H,01FH,0,0,0,0,0,0,0,0,0
KeysNumLock	DB	0,0,0,0,0,0,0,0,0,0,0,038H,0EFH,1,0,0
KeysUpDown	DB	16 DUP(0) ; set to all keys up
KeyStream	DB	16 DUP(0) ; set to all keys up
PassCount	DW	0
KeyStreamIndex	DW	0
LastKeyE0	DB	0
LastKeyE1	DB	0

;
; Westwood key number values of keys to pass through
;
;			CAPS, LEFT_SHIFT, RIGHT_SHIFT, LEFT_CTRL, LEFT_ALT,
;			RIGHT_ALT, RIGHT_CTRL, NUM_LOCK, UNKNOWN
PassAlways	DB	30, 44, 57, 58, 60, 62, 64, 90, 128, 128
PassAlwaysEnd	DB	128		; invalid code to END PassAlways
CtrlFlags	DB	0

Buffer		DW	?
Time		DW	?

ADJUST	= 1			; do not modify DRD

XYAdjust	DB	-ADJUST, -ADJUST	; 91 -> upleft
		DB	-ADJUST,  0		; 92 -> left
		DB	-ADJUST,  ADJUST	; 93 -> downleft
		DB	 0,  0			; 94 illegal
		DB	 0,  0			; 95 illegal
		DB	 0, -ADJUST		; 96 -> up
		DB	 0,  0			; 97 illegal (center)
		DB	 0,  ADJUST		; 98 -> down
		DB	 0,  0			; 99 illegal
		DB	 0,  0			; 100 illegal
		DB	 ADJUST, -ADJUST	; 101 -> upright
		DB	 ADJUST,  0		; 102 -> right
		DB	 ADJUST,  ADJUST	; 103 -> downright
EdgeConv	DW	8,2,8,6,4,3,8,5,8,8,8,8,0,1,8,7

MouseUpdate		DW	0
MouseX			DW	0
LocalMouseX		DW	0
MouseY			DW	0
LocalMouseY		DW	0
Button			DW	0
IsExtKey		DB	0
ExtIndex		DW	0

OldRMI			DD	0	; The origianl RM interrupt seg:off.
OldPMIOffset		DD	0	; The origianl PM interrupt offset		
OldPMISelector		DD	0	; The original PM interrupt segment.

CodeOffset		DW	RM_Keystroke_Interrupt	; Offset of the code in the RM stuff.
CallRMIntOffset		DW	Call_Interrupt_Chain		; Offset of function to call DOS timer interrupt.
CallRMIntAddr		DD	0	; PM address of CallRealIntOffset for speed.

;***************************************************************************
;* KEYNUM_TRANSLATE -- Translates the given keynum to ???                  *
;*                                                                         *
;* INPUT:	UWORD the keynum to translate				   *
;*                                                                         *
;* OUTPUT:	WORD the translated keynum                                 *
;*                                                                         *
;* PROTO:	UWORD KeyNum_Translate(UWORD keynum);			   *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/11/1994 PWG : Created.                                             *
;*=========================================================================*
	GLOBAL	KeyNum_Translate:FAR
	PROC	KeyNum_Translate C FAR 
	USES	cx,di,es,ds
	ARG	keycode:WORD

	mov	ax,cs				; since we are in tiny model
	mov	ds,ax				; set cs = ds
	mov	es,ax				; set es up for scansb

	mov	ax,[keycode]
	test	[KeyFlags],TRACKEXT
	jne 	short ??fini

	mov	cx,ExtRemap-ExtNums
	mov	di,OFFSET ExtNums

	repne	scasb
	jcxz	short ??fini			; No match found.

	mov	di,OFFSET ExtRemapEnd
	dec	di
	sub	di,cx
	mov	al,[es:di]
??fini:
	ret
	ENDP	KeyNum_Translate

;***************************************************************************
;* STUFF_KEY_WORD -- Stuffs a word of data into keyboard buffer            *
;*                                                                         *
;* INPUT:	WORD the code to stick into the circular buffer            *
;*                                                                         *
;* OUTPUT:      WORD !=0 is sucessful, ==0 is not enough room		   *
;*                                                                         *
;* PROTO:	VOID Stuff_Key_WORD(WORD code);				   *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/11/1994 PWG : Created.                                             *
;*=========================================================================*
	GLOBAL	C Stuff_Key_WORD:FAR
	PROC	Stuff_Key_WORD C FAR 
	USES	si,bx,ds
	ARG	code:WORD

	mov	ax,cs				; since we are in tiny model
	mov	ds,ax				; set cs = ds

	mov	ax,[KeyBufferTail]
	mov	si,ax
	add	ax,2
	and	ax,0FFh				; New KeyBufferTail value.
	cmp	[KeyBufferHead],ax
	je 	short ??noroom

	mov	bx,[code]
	mov	[KeyBuffer+si],bx		; Record the keystroke.
	mov	[KeyBufferTail],ax
	xor	ax,ax
	ret

??noroom:
	mov	ax,1
	ret

	ENDP	Stuff_Key_WORD

;***************************************************************************
;* STUFF_KEY_NUM -- Stuffs a key num code into the circular buffer         *
;*                                                                         *
;* INPUT:	WORD the keycode to stuff                                  *
;*                                                                         *
;* OUTPUT:      WORD !=0 is sucessful, ==0 is not enough room		   *
;*                                                                         *
;* PROTO:	VOID Stuff_Key_Num(WORD keynum);			   *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/11/1994 PWG : Created.                                             *
;*=========================================================================*
	GLOBAL	C Stuff_Key_Num:FAR
	PROC	Stuff_Key_Num C FAR 
	USES	ax,bx,cx,dx,di,si,ds
	ARG	keycode:WORD
	LOCAL	tail:WORD		; Original keybuffer tail (safety copy).
	LOCAL	size:WORD		; Size of write.

	pushf
	cli				; disable interrupts

	; Abort key recognition if in record mode and unable
	; to output key due to simultaneous DOS operation.
	mov	ax,cs				; since we are in tiny model
	mov	ds,ax				; set cs = ds


	; Record the mouse position to be stuffed into buffer.
	mov	ax,[MouseX]
	mov	[LocalMouseX],ax
	mov	ax,[MouseY]
	mov	[LocalMouseY],ax

??cando:
	mov	ax,[keycode]		; get the code
	or	ax,ax			; Null keycodes are not recorded.
	jne	short ??validkey
	jmp	??exit


??validkey:

	test	[KeyFlags],KEYMOUSE	; is the numeric keypad moving the mouse?
	je	??no_pad_move

	; ALT-cursor keys are undefined.  Pass them on to the program.
	test	ah,ALTPRESS		; is either alt key down?
	jne	??no_pad_move

	test	[KeyFlags],SIMLBUTTON	; are we simulating left mouse presses
	je	short ??chkinsert

	cmp	al,KN_RETURN
	je	short ??forceleft

	cmp	al,KN_SPACE
	je	short ??forceleft

	cmp	al,KN_KEYPAD_RETURN
	je	short ??forceleft

??chkinsert:
	cmp	al,KN_INSERT
	jne	short ??regular

??forceleft:
	mov	al,KN_LMOUSE
	or	[Button],1		; Left mouse bit.
	test	ah,KEYRELEASE
	je	??mousefake
	and	[Button],NOT 1
	jmp	??mousefake

??regular:
	cmp	al,KN_DELETE
	jne	short ??regular2
	mov	al,KN_RMOUSE
	or	[Button],2		; Right mouse bit.
	test	ah,KEYRELEASE
	je	??mousefake
	and	[Button],NOT 2
	jmp	??mousefake

??regular2:
	; DRD correction to ignore key releases for key mouse movement
	test	ah,KEYRELEASE
	jne	??no_pad_move

	cmp	al,KN_CENTER
	je	short ??pad_move
	cmp	al,KN_UPLEFT		; less than upleft?
	jb	??no_pad_move		; yes, then it isn't a keypad key
	cmp	al,KN_DOWNRIGHT		; greater than downright?
	ja	??no_pad_move		; yes, then it isn't a keypad key
	cmp	al,KN_DOWNLEFT		; is it UPLEFT, LEFT, or DOWNLEFT?
	jbe	short ??pad_move
	cmp	al,KN_UPRIGHT		; is it UPRIGHT, RIGHT, or DOWNRIGHT?
	jae	short ??pad_move
	cmp	al,KN_UP		; up?
	je	short ??pad_move
	cmp	al,KN_DOWN		; down?
	jne	??no_pad_move

??pad_move:
	; DRD correction to use ch for ah
	mov	ch,ah			; save shift-ctrl-alt-rlse status

	xor	ah,ah			; get rid of any bits
	sub	al,KN_UPLEFT		; get a number between 0 and 12
	mov	bx,ax
	shl	bx,1			; double for WORD index
	add	bx,OFFSET XYAdjust
	mov	ax,[bx]			; get x,y add value

	mov	bl,ah
	cbw
	xchg	ax,bx
	cbw
	xchg	ax,bx			; AX = mouse x delta, BX = mouse y delta

	; DRD correction to use ch
	; The CTRL key moves the mouse to the edge of the screen.
	test	ch,CTRLPRESS		; is either ctrl key down?
	jne	short ??ctrlon		; if so, ctrl is on

	; DRD correction to use ch
	; use fast speed of the mouse move if the shift key is held down.
	mov	dx,1			; for slow speed
	test	ch,SHIFTPRESS		; is either shift key down?
	je	short ??normspeed	; if not then neither shift is down
??doublespeed:
	add	dx,3			; for fast speed
??normspeed:
	add	bx,dx			; add speed for y index
	mov	bl,[KeyMouseMove+bx] 	; get speed for y delta
	xchg	ax,bx			; swap with ax to extend sign
	cbw
	xchg	ax,bx
	xchg	bx,dx			; save mouse y delta
	add	bx,ax			; add speed for x index
	mov	al,[KeyMouseMove+bx]	; get speed for x delta
	cbw
	xchg	bx,dx			; restore mouse y delta

	jmp	short ??ctrloff

??ctrlon:

	; Table lookup method for determining hotkey positions for CTRL
	; cursor combination.  This algorithm is hard coded for an ADJUST
	; value of 3.  If this value changed, then this section will also
	; have to be modified.
	and	bx,011b			; Y = 1, 0, 3
	and	ax,011b			; X = 1, 0, 3
	; Table lookup method for determining hotkey positions for CTRL
	; cursor combination.  This algorithm is hard coded.
					;    -1, 0, 1
	and	bx,011b			; Y = 3, 0, 1
	and	ax,011b			; X = 3, 0, 1
	shl	bx,1
	shl	bx,1
	or	bx,ax			; Lookup index.

	; Convert raw index into logical (clockwise) index.
	shl	bx,1
	mov	bx,[EdgeConv+bx]
	shl	bx,1
	shl	bx,1
	mov	ax,[ScreenEdge+bx]	; New absolute X
	mov	bx,[ScreenEdge+bx+2] ; New absolute Y
	mov	[LocalMouseX],ax
	mov	[LocalMouseY],bx

??set_xyz:
	mov	ax,[LocalMouseX]	; get new mouse x,y
	mov	bx,[LocalMouseY]
	jmp	short ??set_xy

	; Process a normal faked mouse move.
??ctrloff:
	; DRD change
	add	[LocalMouseX],ax	; save it in our local
	jns	short ??not_negative_x
	xor	ax,ax
	mov	[LocalMouseX],ax	; clear our local

??not_negative_x:
; DRD change
	add	[LocalMouseY],bx	; save it in our local
	jns	short ??not_negative_y
	xor	bx,bx
	mov	[LocalMouseY],bx	; clear our local

??not_negative_y:
	mov	ax,[LocalMouseX]	; get new mouse x,y
	mov	bx,[LocalMouseY]
	cmp	ax,MAX_X_PIXEL		; bigger than
	jle	short ??check_y
	mov	ax,MAX_X_PIXEL

??check_y:
	cmp	bx,MAX_Y_PIXEL		; bigger than
	jle	short ??set_xy
	mov	bx,MAX_Y_PIXEL

??set_xy:
	mov	[LocalMouseX],ax
	mov	[LocalMouseY],bx
	mov	[MouseX],ax
	mov	[MouseY],bx
	cmp	[MouseUpdate],0	; wait until mouse interrupt is done
	jne	short ??noshow
; PWG: ARRGGGHHHH!
;	call	Low_Hide_Mouse
;	call	Low_Show_Mouse
??noshow:
	mov	ax,KN_MOUSE_MOVE
??mousefake:
	mov	[keycode],ax		; Fake a MOUSE_MOVE event.

??no_pad_move:
	; Fetch working pointers to the keyboard ends.
	mov	si,[KeyBufferTail]
	mov	[tail],si		; Safety record.
	mov	di,[KeyBufferHead]

	; Record the base keycode (if there is room).
	push	ax
	call	Stuff_Key_WORD
	add	sp,2
	or	ax,ax
	jne	short ??jmpnoroom

	; Also record the mouse coordinates if necessary.
	mov	ax,[keycode]		; get key code
	cmp	al,KN_MOUSE_MOVE	; mouse move?
	je	short ??recordmouse	; yes? then record the mouse cooordinates
	cmp	al,KN_LMOUSE
	je	short ??recordmouse
	cmp	al,KN_RMOUSE
	je	short ??recordmouse
	jmp	short ??ok
??jmpnoroom:
	jmp	??noroom

	; Record mouse coordinate X.
??recordmouse:
	push	[LocalMouseX]
	call	Stuff_Key_WORD
	add	sp,2
	or	ax,ax
	jne	??jmpnoroom
	add	[size],2

	; Record mouse coordinate Y.
	push	[LocalMouseY]
	call	Stuff_Key_WORD
	add	sp,2
	or	ax,ax
	jne	??jmpnoroom
	add	[size],2
	
??ok:
	; If PASSBREAKS is not active and this is a keyboard
	; break AND it is not a mouse event, then don't put
	; it into the buffer.
	mov	bx,0101h		; Bit control tools.
	mov	ax,[keycode]
	cmp	al,KN_MOUSE_MOVE
	je 	short ??notreal
	cmp	al,127
	je	short ??notreal
	test	ah,KEYRELEASE
	je	short ??real
	xor	bl,bl
	test	[KeyFlags],PASSBREAKS
	jne 	short ??real
	cmp	al,KN_LMOUSE
	je 	short ??real
	cmp	al,KN_RMOUSE
	je 	short ??real
??notreal:
	mov	[KeyBufferTail],si	; Nullify any KeyBufferTail changes.
??real:

	; Update the KeysUpDown bit array.
	mov	di,ax
	and	di,07Fh
	mov	cl,3
	shr	di,cl			; DI = Byte offset into bit table.
	mov	cl,al
	and	cl,0111b		; CL = Bit offset into bit table byte.
	shl	bx,cl
	not	bh

	; If this is a reapeat key and the key is already being held
	; down, then don't stuff it into the keyboard buffer.
	test	bl,[KeysUpDown+di]
	je	short ??notalready
	test	[KeyFlags],REPEATON
	jne	short ??notalready
	mov	[KeyBufferTail],si	; Nullify any KeyBufferTail changes.
??notalready:
	and	[KeysUpDown+di],bh	; Force key bit to zero.
	or	[KeysUpDown+di],bl	; Insert key bit as appropriate.
;??notreal:

	; Successful keybuffer stuff could result in a
??norecord:
	mov	ax,1
	jmp short ??exit

	; Unsuccessful keybuffer stuff.
??noroom:
	mov	ax,[tail]
	mov	[KeyBufferTail],ax
	xor	ax,ax			; Signal an error.

??exit:
	popf
	ret

	ENDP	Stuff_Key_Num
;***********************************************************



;***************************************************************************
;* KEYSTROKE_INTERRUPT -- Handles input that comes from the keyboard       *
;*                                                                         *
;* This routine intercepts the key codes on their way to the		   *
;* BIOS.  With the adjustment of the Flags described above		   *
;* you can get a wide variety of effects.				   *
;*                                                                         *
;* INPUT:	none                                                       *
;*                                                                         *
;* OUTPUT:      none                                                       *
;*                                                                         *
;* WARNINGS:    This is an interrupt function                              *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/13/1994 PWG : Created.                                             *
;*=========================================================================*
label RM_Keystroke_Interrupt
	GLOBAL	C Keystroke_Interrupt:FAR
	PROC	Keystroke_Interrupt C FAR 

IF 0
	push	ax
	inc	ax
	pop	ax
	iret

ELSE
	push	ax
	push	bx
	push	cx
	push	di
	push	ds
	push	dx
	push	es
	push	si
	cld

	mov	ax,cs			; set ds to cs to avoid cs overide
	mov	ds,ax
	mov	dx,[KeyFlags]
	;*** The following fix allows proper caps and num lock tracking on Tandy
	; 10-6-89 LJC, DRD
					
	and	[KeyLock],NOT (NUMLOCK OR CAPSLOCK); assume caps and num inactive
	mov	ax,040H			; BIOS segment
	mov	es,ax			; put in es
	test	[BYTE PTR es:017H],040H	; test Caps lock bit in BIOS
	je	short ??bioscapsoff	; skip activate code
	or	[KeyLock],CAPSLOCK	; Caps Lock active

??bioscapsoff:
	test	[BYTE PTR es:017H],020H	; test Num lock bit in BIOS
	je	short ??biosnumoff	; skip activate code
	or	[KeyLock],NUMLOCK 	; Num Lock active

??biosnumoff:
	mov	[ExtKeyboard],TRUE 	; assume 101/102-key keyboard
	test	[BYTE PTR es:096H],010H	; test for 101/102-key keyboard
	jne	short ??extkeyboard	; skip deactivate code
	mov	[ExtKeyboard],FALSE 	; no 101/102-key keyboard

??extkeyboard:
	mov	ax,cs			; set ds to cs to avoid cs overide
	mov	es,ax

	cld				; clear direction flag for strings
	xor	ah,ah			; clear ctrl flags to 0
	mov	bx,0101H		; set key to a make by default
	in	al,KEYDATA		; get a code from the keyboard

	;
	; New CODE to montior key stream
	;
	mov	bx,[KeyStreamIndex]
	mov	[KeyStream+bx],al
	inc	bx
	and	bx,15
	mov	[KeyStreamIndex],bx
	mov	bx,0101H		; set key to a make by default
	;
	; END OF SEQUENCE
	;

	;
	; Handle the PAUSE key being pressed.  If it is pressed, then
	; signal that the next two input codes are to be thrown out.
	;
	cmp	al,0E1H			; see if this is a pause/break
	jne	short ??notpcode	; not a pause/break start code
	mov	[LastKeyE1],3		; absorb this and next two codes

??notpcode:
	cmp	[LastKeyE1],0		; are we in a pause/break code
	je	short ??notpause	; no, just keep going
	dec	[LastKeyE1]		; yes, dec the count
	test	dx,PAUSEON		; should it pass these codes
	jne 	??passcode		; pass the code
	jmp	??absorbcode		; don't pass code

??notpause:
	;
	; Record any extended key codes that arrive.  They will be
	; taken into account with the next code.
	;
	cmp	al,0E0H			; is it an extended code
	jne	short ??notextcode	; if not skip to handle key
	mov	[LastKeyE0],TRUE	; set the extended code to 1
??jmppasscode:
	jmp	??passcode		; always pass E0s

??notextcode:
	;
	; Check and acknowledge if the key is a make or a break.
	;
	test	al,080H			; test for high bit
	je	short ??make		; if off its a make
	xor	bl,bl			; set make/break to break
	and	al,07FH			; clear high bit
	or	ah,KEYRELEASE		; CDY NEW -- ABSENT IN OLD CODE

??make:
	;
	; Translate the raw keycode into the Westwood keycode.
	;
	cmp	[LastKeyE0],FALSE	; was the prev byte an E0?
	je 	short ??normal		; if not it is a normal key
	mov	[LastKeyE0],FALSE	; if so clear for next read
	mov	[IsExtKey],TRUE	; it is an extended key
	mov	di,OFFSET ExtCodes	; get offset of extended codes table
	mov	cx,(ExtNums-ExtCodes)	; get number of entrys in ext table
	repne	scasb			; look for a match
	jcxz	??absorbcode		; Not recognized, so throw it away.
	mov	al,[(ExtNums - ExtCodes) - 1 + di] ; get the match
	mov	[IsExtKey],FALSE	; it is not an extended key
	jmp 	short ??notext

??normal:
	cmp	al,07Ah
	jne	short ??normok
	mov	al,128
	jmp	short ??notext
??normok:
	mov	di,ax			; use code as an index
	and	di,007Fh		; Mask off any release bit.
	mov	al,[KeyNums+di]		; get the key number of this key

??notext:
	;
	; Test and set the CTRL bit.
	;
	test	[KeysUpDown+8],001H	; is the right ctrl down?
	jne	short ??ctrlon		; if so, ctrl is on
	test	[KeysUpDown+7],004H	; is the left ctrl down?
	je	short ??ctrloff		; if not, neither are down, no ctrl

	; DRD
	; check for CTRL-NUMLOCK for pause on some keyboards

	cmp	al,KN_NUMLOCK		; check for CTRL-NUMLOCK
	jne	short ??ctrlon

	cmp	[ExtKeyboard],TRUE	; if 101/102-key keyboard it is ok
	je	short ??ctrlon

	test	dx,PAUSEON		; should it pass these codes
	jne	short ??ctrlon		; pass the code

	jmp	??absorbcode		; don't pass code

??ctrlon:
	or	ah,CTRLPRESS		; or on the ctrl bit in flags

??ctrloff:
	;
	; Test and set the ALT bit.
	;
	test	[KeysUpDown + 7],050H	; is either alt key down?
	je	short ??altoff
	or	ah,ALTPRESS		; or on the alt bit in flags

??altoff:
	;
	; Remap the keyboard keys if this is requested. (Do not set DGROUP
	;   as it is unecessary)
	push	ax
	call	KeyNum_Translate
	add	sp,2

;------	Set the shift bit if necessary.
	test	[KeysUpDown+5],010H	; is the left shift down?
	jne	short ??shifton		; if so the shift is on
	test	[KeysUpDown+7],002H	; is the right shift down?
	je	short ??shiftoff	; if not then neither shift is down

??shifton:
	or	ah,SHIFTPRESS		; or on the shift bit in flags

??shiftoff:
	;
	;------	Toggle the shift state if the caps lock key is on (if necessary).
	;
	mov	di,ax
	and	di,07Fh
	shr	di,1
	shr	di,1
	shr	di,1
	mov	bx,ax
	and	bx,07Fh
	and	bl,0111b
	mov	ch,[Bits+bx]		; get the bit to test
	test	[KeyLock],CAPSLOCK	; is the caps lock on?
	je	short ??capsoff		; if not don't worry about it
	test	ch,[KeysCapsLock+di]	; get code for keycaps
	je	short ??capsoff		; its not effected
	xor	ah,SHIFTPRESS		; toggle the shift flag

??capsoff:
	;
	;------	Toggle the shift state if the num-lock key is on (if necessary).
	;
	test	[KeyLock],NUMLOCK	; is the num lock key on?
	je	short ??numlockoff	; if not don't worry about it
	test	ch,[KeysNumLock+di]	; get code for numlock
	je	short ??numlockoff	; if not effected skip toggle
	xor	ah,SHIFTPRESS		; toggle the shift flag if effected

??numlockoff:
;------ Remember the current control/shift/alt bit settings for later use.

;??noshiftever:
	mov	[CtrlFlags],ah		; save off shift-ctrl-alt flags
					; for the mouse and joystick routines
					; to use in stuffing key into the
					; keyboard buffer.

;------	The CTRL-ALT-DEL key combination always gets passed to the system.
	cmp	ax,0668H		; is it ctrl alt del?
	je	??passcode
	cmp	ax,064CH		; is it ctrl alt ext del?
	je	??passcode	; if so don't add it to the buffer

;------ Special Ctrl-C check.
	cmp	ax,0230h
	je	short ??breaker
	cmp	ax,027Eh
	jne	short ??nobreak
??breaker:
	mov	[Break],1

??nobreak:
;------	Check for Music and Sound control keys.
	cmp	ax,0420H		; is this an alt s
	jne	short ??checkmusic	; toggle the Sound variable
	push	ax
	mov	ax,[SoundOn]
	xor	ax,01H
	push	ax
	add	sp,2
	pop	ax

??checkmusic:
	cmp	ax,0434H		; is this an alt m
	jne	short ??esc		; toggle the Music variable
	push	ax
	mov	ax,[MusicOn]
	xor	ax,01H
	push	ax
	add	sp,2
	pop	ax

??esc:

	push	ax
	call	Stuff_Key_Num
	pop	ax
??skipstuff:

;------	Do the special ESC routine if necessary.
	cmp	al,110			; is this the esc key?
	jne	short ??noroutine	; if not goto the pass always
	cmp	[WORD PTR EscRoutine+2],0 ;if vector is 0 don't jump
	je	short ??noroutine
	push	ax
	call	[EscRoutine]
	pop	ax

??noroutine:
;------	Check to see if the key is to be passed to the system or not.
	mov	di,OFFSET PassAlways	; get offset to table
	mov	cx,(PassAlwaysEnd - PassAlways) ; get number of pass always CDY JLB MOD 7/11 was +1
	repne	scasb			; look for a match
	or	cx,cx			; see if there was no match
	jne	??passcode	; CDY JLB 7/11 optimization




??passalways:
	; now check for conditional passes
	mov	di,OFFSET CondPassKey	; get offset to cond key table
	mov	cx,(CondPassCond-CondPassKey) ; get number of entries
	shr	cx,1			; cut in half for words
	repne	scasw			; look for a match
	jcxz	short ??notcondpass	; OPTIMIZATION CDY JLB
	mov	bx,[(CondPassCond - CondPassKey) - 2 + di]
	and	bx,dx			; are the conditions met?
	je	short ??notcondpass	; NO... check normally.
	jmp	short ??passcode	; YES... pass back to system.
;
;------	Last check before passing keycode back to the system.
;
??notcondpass:
	test	dx,FILTERONLY		; is the filter only flag on?
	je	short ??absorbcode	; if not, absorb the code.
;***********************************************************
	pushf
;	push	di
;	push	es
	
	mov	ax,0B000h
	mov	es,ax
	inc	[BYTE PTR es:0]

;	pop	es
;	pop	di
	popf
;***********************************************************

??passcode:

	pop	si
	pop	es
	pop	dx
	pop	ds
	pop	di
	pop	cx
	pop	bx
	pop	ax
	inc	[cs:PassCount]
	jmp	[cs:OldRMI]

??absorbcode:
	in	al,KEYCTRL			; get the control port
	mov	ah,al
	or	al,080H				; reset bit for keyboard
	out	KEYCTRL,al
	xchg	ah,al				; get orig control data
	out	KEYCTRL,al			; restore control data

	mov	ax,040h				; BIOS paragraph is always @ 040h
	mov	es,ax				; put in es as BIOS paragraph
	mov	al,[es:96h]			; get extended keys
	and	al,0FDh				; turn off last key e0 flag
	mov	[es:96h],al			; set extended keys

	mov	al,CLEARISR			; value to clear In Service Register
	out	INTCHIP0,al			; 8259 interrupt chip controller 0
	pop	si
	pop	es
	pop	dx
	pop	ds
	pop	di
	pop	cx
	pop	bx
	pop	ax
	iret	
ENDIF

	ENDP	Keystroke_Interrupt

;***************************************************************************
;* BREAK_INTERRUPT -- Handles the break key interrupt                      *
;*                                                                         *
;* INPUT:	none                                                       *
;*                                                                         *
;* OUTPUT:      none                                                       *
;*                                                                         *
;* WARNINGS:    This is an interrupt routine.                              *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/13/1994 PWG : Created.                                             *
;*=========================================================================*
	GLOBAL	C Break_Interrupt:FAR
	PROC	Break_Interrupt C FAR

	iret	

	ENDP	Break_Interrupt

;**************************************************************************
;* CALL_INTERRUPT_CHAIN -- Function PM calls to call the RM interrupt chain*
;*                                                                         *
;*                                                                         *
;* INPUT:                                                                  *
;*                                                                         *
;* OUTPUT:                                                                 *
;*                                                                         *
;* WARNINGS:                                                               *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/08/1994 SKB : Created.                                             *
;*=========================================================================*
Call_Interrupt_Chain:
IF 0
	pushf
	push	ax
	push	di
	push	es

	mov	ax,0B000h		; ES:DI = Mono RAM address.
	mov	es,ax
		
	mov	al,'A'
	mov	ah,2
	and	di,63

	stosw

	in	al,KEYDATA		; get a code from the keyboard
	mov	al,CLEARISR		; value to clear In Service Register
	out	INTCHIP0,al		; 8259 interrupt chip controller 0


	pop	es
	pop	di
	pop	ax
	popf
ENDIF
	pushf
	call	Keystroke_Interrupt ;[OldRMI]
	retf

STACK	   ; Don't really need this

;***********************************************************
END
