	.MODEL	TINY
	INCLUDE DOS.INC

MLALT	EQU	00208H			;Флаги для левого Alt
MRALT	EQU	00008H			;Флаги для правого Alt (00808H?)
MLCTRL	EQU	00104H			;Флаги для левого Ctrl
MRCTRL	EQU	00004H			;Флаги для правого Ctrl (00404H?)
MCLEAR	EQU	0F0F3H			;Маска игнорирования флагов Alt и Ctrl

;Макрос для сохранения регистров в стеке.
@PUSH	MACRO	REGLIST
	IRP	REG, <REGLIST>
		PUSH	REG
	ENDM
ENDM

;Макрос для восстановления регистров из стека.
@POP	MACRO	REGLIST
	IRP	REG, <REGLIST>
		POP	REG
	ENDM
ENDM

SCODE	SEGMENT PARA 'CODE'
	ORG	100H
BEGIN:
	JMP	START
;================================= Данные ================================
;Указатель на старый оработчик INT 009H
PINT9	LABEL DWORD
OINT9	DW 		?
SINT9	DW 		?
;Указатель на старый обработчик INT 02FH
PINT2F	LABEL DWORD
OINT2F	DW		?
SINT2F	DW		?
;MUX резидентной программы
MUX_ID	DB		?
;Свободный MUX
MUX_0	DB		0
;-------------------------
KEXT	DB		0			;Признак расширенного кода
KALT	DW		0			;Признак нажатого левого Alt
KCTRL	DW		0			;Признак нажатого левого Ctrl
KRALT	DW		0			;Признак нажатого правого Alt
KRCTRL	DW		0			;Признак нажатого правого Ctrl
KLW	DW		0			;-//- левого Start'а
KRW	DW		0			;-//- правого Start'а
KMN	DW		0			;-//- Menu
MAND	DW		0			;AND-маска для флагов BIOS
MOR	DW		0			;OR-маска для флагов BIOS
;=========================================================================

;======================= Резидентные подпрограммы ========================

;----------- Обработчик аппаратного клавиатурного прерывания -------------
INT9	PROC	NEAR
	@PUSH		<AX, ES>
	MOV		AX, 40H
	MOV		ES, AX
	MOV		CS:MAND, 0FFFFH		;Сброс маски в обычное состояние
	MOV		CS:MOR, 0		;-//-
	IN		AL, 060H
	MOV		AH, AL
	AND		AL, 7FH
	CMP		AH, 0E0H
	JNE		@@WHICH
	MOV		CS:KEXT, 1
	JMP		@@OLD
@@WHICH:
	CMP		CS:KEXT, 0
	JNE		@@EXTENDED
	CMP		AL, 38H
	JE		@@ALT
	CMP		AL, 1DH
	JE		@@CTRL
	JMP		@@OLD
@@ALT:
	MOV		CS:KALT, MLALT
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KALT, 0
	JMP		@@OLD
@@CTRL:
	MOV		CS:KCTRL, MLCTRL
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KCTRL, 0
	JMP		@@OLD
@@RALT:
	MOV		CS:KRALT, MRALT
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KRALT, 0
	JMP		@@OLD
@@RCTRL:
	MOV		CS:KRCTRL, MRCTRL
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KRCTRL, 0
	JMP		@@OLD
@@EXTENDED:
	MOV		CS:KEXT, 0
	CMP		AL, 5BH
	JE		@@LW
	CMP		AL, 5CH
	JE		@@RW
	CMP		AL, 5DH
	JE		@@MN
	CMP		AL, 38H
	JE		@@RALT
	CMP		AL, 1DH
	JE		@@RCTRL
	JMP		@@OLD
@@LW:
	MOV		CS:KLW, MLALT
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KLW, 0
	JMP		@@OLD
@@RW:
	MOV		CS:KRW, MRALT
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KRW, 0
	JMP		@@OLD
@@MN:
	MOV		CS:KMN, MRCTRL
	TEST		AH, 80H
	JZ		@@OLD
	MOV		CS:KMN, 0
	JMP		@@OLD
@@OLD:
	CALL		CALC		;Модифиц. флагов до обработчика BIOS
	PUSHF
  	CALL		DWORD PTR CS:OINT9
	MOV		AX, ES:[17H]
	AND		AX, CS:MAND
	OR		AX, CS:MOR
	MOV		ES:[17H], AX
	CALL		CALC		;Модифиц.флагов после обработчика BIOS
	@POP		<ES, AX>
	IRET
CALC	PROC NEAR
;Модифицирует флаги BIOS'а по признакам нажатия клавиш: Alt,Ctrl,Start,Menu
	PUSH		AX
	MOV		AX, CS:KALT
	OR		AX, CS:KLW
	OR		AX, CS:KRALT
	OR		AX, CS:KRW
	OR		AX, CS:KCTRL
	OR		AX, CS:KRCTRL
	OR		AX, CS:KMN
	MOV		CS:MOR, AX
	MOV		CS:MAND, MCLEAR
	MOV		AX, ES:[17H]
	AND		AX, CS:MAND
	OR		AX, CS:MOR
	MOV		ES:[17H], AX
	POP		AX
	RET
CALC	ENDP
INT9	ENDP
;-------------------------------------------------------------------------

;----------------------- Новый обработчик INT 02FH -----------------------
INT2F	PROC	NEAR
	CMP		AH, CS:MUX_ID
	JE		OUR_MUX			;Наш MUX
	JMP		CS:PINT2F
OUR_MUX:
	OR		AL, AL
	JZ		CHECK			;Ф-ция проверки установки
	JMP		CS:PINT2F
CHECK:
	NOT		AL			;Признак установки - AL=0FFH
	MOV		DX, "WK"
	MOV		CX, "BD"		;CX и DX - уникальный код
	MOV		BX, CS			;BX - сегмент драйвера
	IRET
INT2F	ENDP
;-------------------------------------------------------------------------
;=========================================================================

;========================= Сообщения программы ===========================
M_PROG	DB		"Keyboard driver for win-keyboard "
	DB		"installed.",13,10
	DB		"Author: Frunze A.A. (C) '98",13,10,"$"
M_RMV	DB		"WKBD removed.",13,10,"$"
M_RERR	DB		"Can't remove WKBD from memory!",13,10,"$"
;=========================================================================

;------------------- П/П проверки установки драйвера ---------------------
FIND	PROC	NEAR
	MOV		MUX_ID, 0C0H
F_NEXT:
	MOV		AH, MUX_ID
	XOR		AL, AL
	INT		02FH
	CMP		AL, 0FFH
	JE		F_CHECK			;Что-то установлено
	MOV		AH, MUX_ID
	MOV		MUX_0, AH		;Свободный MUX
F_OTHER:
	INC		MUX_ID
	JNZ		F_NEXT
	CLC					;Наш драйвер не установлен
	RET
F_CHECK:
	CMP		DX, "WK"
	JNE		F_OTHER
	CMP		CX, "BD"
	JNE		F_OTHER
	STC					;Наш драйвер уже установлен
	RET
FIND	ENDP
;-------------------------------------------------------------------------

;============================= Программа =================================
START:
	MOV		ES, WORD PTR CS:[02CH]  ;Освободили блок переменных
	@FREEBLOCK				;окружения драйвера
	@GETINT		009H
	MOV		CS:OINT9, BX
	MOV		CS:SINT9, ES		;Получили INT 009H
	@GETINT		02FH
	MOV		CS:OINT2F, BX
	MOV		CS:SINT2F, ES		;Получили INT 02FH
	CALL		FIND
	JNC		L_INST			;Наш драйвер еще не установлен
L_REMOVE:
	MOV		AX, CS:SINT9
	CMP		AX, BX
	JNE		L_RERR			;Не равны сегменты
	MOV		AX, CS:SINT2F
	CMP		AX, BX
	JNE		L_RERR			;Не равны сегменты
	MOV		AX, CS:OINT9
	CMP		AX, OFFSET INT9
	JNE		L_RERR			;Не равны смещения
	MOV		AX, CS:OINT2F
	CMP		AX, OFFSET INT2F
	JNE		L_RERR			;Не равны смещения
	MOV		DI, OFFSET PINT9
	MOV		DX, ES:[DI]
	MOV		AX, ES:[DI+2]
	MOV		DS, AX
	MOV		AX, 02509H
	INT		021H			;Восстановили INT 009H
	MOV		DX, ES:[DI+4]
	MOV		AX, ES:[DI+6]
	MOV		DS, AX
	MOV		AX, 0252FH
	INT		021H			;Восстановили INT 02FH
	MOV		AX, CS
	MOV		DS, AX
	@FREEBLOCK				;Освободили память
	JC		L_RERR			;Ошибка освобождения
	@SHOWSTR	M_RMV			;Сообщение об успешн. выгрузке
	JMP		L_EXIT
L_RERR:
	@SHOWSTR	M_RERR			;Сообщение об ошибке выгрузки
	JMP		L_EXIT
L_INST:
	MOV		AH, MUX_0
	MOV		MUX_ID, AH		;Заняли свободный MUX
	MOV		AX, CS
	MOV		DS, AX
	@SETINT		009H, INT9		;Установили новый INT 009H
	@SETINT		02FH, INT2F		;Установили новый INT 02FH
	@SHOWSTR	M_PROG			;Сообщение о резидентности
	MOV		DX, OFFSET M_PROG	;Оставили программу до M_PROG
	INT		027H			;резидентной и вышли в DOS
L_EXIT:
	@EXIT		0			;Выход в DOS
;=========================================================================
SCODE	ENDS
END	BEGIN
