;**     Code from 86world column in Micro Cornucopia Magazine Issue #41
;**
;**
;***************************************************************************
;**	TURKKEYS.ASM - a program to demonstrate how to trap the INT 16h	 **
;**		keyboard by translating several alt+<key> and		 **
;**		alt+shift+<key> combinations into accented characters	 **
;**		used in the Turkish alphabet but not present on the 	 **
;**		standard IBM keyboard.					 **
;**									 **
;**		For example, alt+c becomes (c with cedilla)		 **
;**		and alt+shift+c (alt+C) becomes (capital C w/cedilla)	 **
;**									 **
;**	TO ASSEMBLE:	MASM TURKKEYS;					 **
;**			LINK TURKKEYS;					 **
;**			EXE2BIN TURKKEYS TURKKEYS.COM			 **
;**			ERASE TURKKEYS.EXE (and TURKKEYS.OBJ)		 **
;**									 **
;**	NOTES:	Obviously, not many people have a burning need to type	 **
;**		Turkish text. What's important here is the method, which **
;**		can be used for any number of other things. All		 **
;**		translations are controlled by the tables XLATE and	 **
;**		SHIFTXLATE, making it possible to translate nearly	 **
;**		anything to anything.					 **
;**									 **
;**		"Use it as you will" Laine Stump, Feb. 13, 1988	 **
;**						 (orig. Feb, 1986)	 **
;**************************************************************************
;       macro definitions and other constants
	INCLUDE		MSDOS.MAC

Keyboard	equ	16h
 conin	equ	0	;function code to put in AH
 constat	equ	1
 shiftstat	equ	2
	ctrl	equ	00000100b ;shift bits returned in AL
	alt	equ	00001000b
	shifts	equ	00000011b
	caps	equ	01000000b
;
;***************************************************************************
CODE	SEGMENT PUBLIC
	ASSUME	CS:CODE
FirstByte	equ	this byte	;between here & LastByte remains res.

	ORG	100h
START:	JMP	INIT		;init code is at end so we can get rid of it.

OldKbdInt	equ	this dword
 OldKbdIntOfs	DW	?
 OldKbdIntSeg	DW	?
;
;***************************************************************************
;	input translation table for 16 bit IBM character codes
;
;	first word of a pair is original 16 bit character code (see
;	the Pink Shirt book for details), second word is its xlation
;	End of table indicated by a 0 word.
;
;	Characters marked by ** are not present in the standard IBM
;	Extended Character Set and require a new character generator ROM
;	to function properly.
;
Xlate	DW	1600h,1681h	;umlaut u
	DW	1700h,178Dh	;undotted i **
	DW	1800h,1894h	;umlaut o
	DW	1E00h,1E83h	;circumflex a
	DW	1F00h,1F9Fh	;cedilla s **
	DW	2200h,22A7h	;soft g **
	DW	2E00h,2E87h	;cedilla c
	DW	0		;end of table
;
;	translation table used if a <shift> key is depressed
;
ShiftXlate DW	1600h,169Ah	;umlaut U
	DW	1700h,1798h	;dotted I **
	DW	1800h,1899h	;umlaut O
	DW	1E00h,1E8Eh	;circumflex A **
	DW	1F00h,1F9Eh	;cedilla S **
	DW	2200h,22A6h	;soft G **
	DW	2E00h,2E80h	;cedilla C
	DW	0		;end of table
;
;*******************************************************************
;	translate 16 bit character in AX according to Xlate table
;
KeyXlate:
	CALL	AltDown?	;xlate only if "alt" is not down
	JNZ	KeyXlate9	;(actually if alt+ctl is not down)
	PUSH	BX		;(since we have modified shiftstat)
	MOV	BX,offset Xlate
	CALL	ShiftDown?
	JZ	KeyXlate1
	MOV	BX,offset ShiftXlate
KeyXlate1:
	CMP	word ptr CS:[BX],0	;WHILE not end of table
	JE	KeyXlate3
	CMP	CS:[BX],AX		; AND not found
	JE	KeyXlate2
	 ADD	 BX,4			; tableptr++
	 JMP	 KeyXlate1
KeyXlate2:
	MOV	AX,CS:[BX+2]		;IF found, replace original
KeyXlate3:
	POP	BX
KeyXlate9:
	RET
;
;*******************************************************************
NewKbdInt:	;This is where all INT 16s now go
	STI
	CMP	AH,shiftstat
	JZ	ShiftStatFunction
	CMP	AH,constat
	JZ	ConStatFunction
	CMP	AH,conin
	JZ	ConinFunction
	JMP	OldKbdInt	;pass unknown functions on
;
;*******************************************************************
ConinFunction:
	PUSHF			;simulate INT 16h
	CALL	OldKbdInt	;to get a character
	CALL	KeyXlate
	IRET
;
;*******************************************************************
ConStatFunction	PROC FAR
	PUSHF	;call original stat routine
	CALL	OldKbdInt
	JZ	ConStat9
	PUSHF	;save to return to calling program
	CALL	KeyXlate
	POPF
ConStat9:
	RET	2		;instead of IRET so caller gets flags
ConStatFunction ENDP
;
;*******************************************************************
ShiftStatFunction:
	PUSHF	;simulate an INT
	CALL	OldKbdInt
	TEST	AL,alt		;see if alt key is down
	JZ	ShiftStat9	; we will only show alt if also ctrl
	AND	AL,NOT alt	; assume no ctrl
	TEST	AL,ctrl
	JZ	ShiftStat9
	OR	AL,alt		; else turn alt on & ctrl off
	AND	AL,NOT ctrl
ShiftStat9:
	IRET
;
;*******************************************************************
;	ask ROM BIOS about state of shift keys
;	returns NZ if left or right shift is down, or if capslock is on
;
ShiftDown?:
	PUSH	AX
	PUSH	BX
	MOV	AH,shiftstat
	INT	Keyboard	;HEY! Are we reentrant or what??
	TEST	AL,shifts
	JZ	SHIFTDOWN2
	 NOT	 AL
SHIFTDOWN2:
	TEST	AL,caps
	POP	BX
	POP	AX
	RET
;
;*******************************************************************
AltDown?:	;test status of alt key
	PUSH	AX
	PUSH	BX
	MOV	AH,shiftstat
	INT	Keyboard
	TEST	AL,alt
	POP	BX
	POP	AX
	RET
;
LastByte	equ	this byte
;************************************************************************
;	Below this point only used during initialization, then discarded
;
	ASSUME	DS:CODE
Msg	DB	'TURKKEYS input translator 02/13/88<lrs>',CR,LF
MsgLen	= ($-Msg)

INIT:	Output	stdout,Msg,MsgLen

	MOV	AL,Keyboard		;get the original INT 16h vector
	DOS	GetVector
	MOV	OldKbdIntOfs,BX		;save to call later
	MOV	OldKbdIntSeg,ES

	MOV	AL,Keyboard		;install our own vector
	MOV	DX,offset NewKbdInt
	DOS	SetVector

	MOV DX,(LastByte-FirstByte+15)/16
	MOV	AL,0
	DOS	TerminateKeep

CODE	ENDS
	END	START


