/*************** Драйвер руссификации клавиатуры ***************/

/* За основу взят алгоритм KEYRUS. В режиме ввода русских символов если удержи-
вать нажатой клавишу правый Alt, то вместо русских букв "бюёжэхъ" будут вво-
диться соответствующие им знаки препинания. */

?resize FALSE
?use80386
?jumptomain NONE
?include "WRITE.H--"
?include "SYSTEM.H--"
?include "TSR.H--"

?define OLDINT9 0x56
?define D9	0x5a
?define D10     0x5b
?define lat     0X5D
?define asn     0X64
?define asv     0X6B
?define keyk	0X72
?define MOVPROC 0xde
?define OLDI    0xec
?define NSERV   0XF0
//переключение на русс.36h-ShR,2ah-ShL,1dh-CtrL,9dh-CtrR
//перекл на лат.       38h-AltL,b8h-AltR,85h-F11,86h-F12
?define SWITCH_KEY 0x9d
?define COLOR_BAR  0x1a

MAIN1()
inline
{
	main();
}

interrupt INT9()
{
	$PUSHA
	$PUSH DS
	$PUSH ES
	$PUSH CS
	$POP DS
	$IN AL,0X60
	DL=DSBYTE[D9];
	BX=0X40;
	ES=BX;
	IF(AL==0XE0)DL|=0X80;
	BL=DL&3;
	CX=2;
L_0134:
	BL--;
	$JNS C1
	BL=2;
	$JMP SHORT L_014D
C1:
	AH=SWITCH_KEY;	//сканкод клавиши перекл режима
	$CMP	AL,0XE0
	$JZ L_01F8
L_0214:
	DH=AH;
	AH&=0X7F;
	IF(AL!=AH){
		AH|=0X80;
		$CMP	AL,AH
		$JNE	L_0260
		$TEST	DL,0X20
		$JZ	L_0260
		$TEST	DL,0X40
		$JNZ	L_0260
		$TEST	DL,0X80
		$JZ	L_025C
		$CMP	DH,DSBYTE[D10]
		$JNE	L_0260
L_025C:
		AH=0;
	}
	ELSE{
		$PUSH	DX
		DH=DH^DL&0X80;
		$POP	DX
		$JNZ	L_0260
		$TEST	DL,0X20
		IF(NOTZEROFLAG)DL|=0X40;
		ELSE{
			$TEST	DL,0X80
			IF(NOTZEROFLAG)DSBYTE[D10]=DH;
			DL|=0X20;
		}
		CX=0;
L_0260:
		$OR	AH,AH
	}
	IF(ZEROFLAG){
		DL=DL&0XC|BL;
		AL=0;
		$JMP	SHORT L_0182
	}
	$JCXZ	L_0152
L_014D:
	$LOOP	L_0134
	$AND	DL,0XF
L_0152:
	$TEST	AL,0X80
	IF(NOTZEROFLAG){
L_01F5:
		$AND	DL,0X7F
L_01F8:
		DSBYTE[D9]=DL;
		$POP	ES
		$POP	DS
		$POPA
		$JMP	FAR CSDWORD[OLDINT9]
	}
	$TEST	DL,8
	IF(ZEROFLAG){
		$TEST	DL,1
		$JNZ	L_01F5
	}
	$CMP	AL,0X35
	$JA	L_01F5
	AH=ESBYTE[0X17]&0XC;
	IF(AH==8){
		$CALL DSWORD[MOVPROC]
		$JNZ	L_0266
		$TEST	DL,3
		$JNZ	L_0266
		$XOR	AH,AH
		$MOV	AH,2
	}
	ELSE{
L_0266:
		AH&=0XC;
	}
	$JNZ	L_01F5
	BX=ESWORD[0X1C];
L_0182:
	$PUSHF
	$CALL	FAR DSDWORD[OLDINT9]
	$OR	AL,AL
	$JNZ	L_0194
	AL=DL;
	DSBYTE[D9]=AL;
	$PUSH	DX
	$STI
	$XOR	AH,AH
	$TEST	AL,1
	IF(ZEROFLAG)AH=COLOR_BAR;	//цвет рамки
	DX=0X3DA;
	do{
		$IN	AL,DX
		$TEST	AL,1
	}while(ZEROFLAG);
	AL=0X11;
	DL=0XC0;
	$OUT	DX,AL
	AL=AH;
	$OUT	DX,AL
	AL=0X20;
	$OUT	DX,AL
	$POP	DX
	$JMP	SHORT L_01E8
L_0194:
	$CMP	BX,ESWORD[0X1C]
	$JE	L_01E8
	$PUSH	BX
	$XOR	BL,BL
	$TEST	DL,1
	IF(NOTZEROFLAG)$OR	BL,4
	$TEST	DL,2
	IF(NOTZEROFLAG)$OR	BL,2
	$OR	BL,AH
	AH=ESBYTE[0X17];
	$TEST	AH,0X40
	$JZ	L_01C1
	$CMP	AL,0X10
	$JB	L_01C1
	$OR	BL,1
L_01C1:
	$TEST	AH,3
	IF(NOTZEROFLAG)$XOR	BL,1
	$TEST	BL,2
	IF(NOTZEROFLAG){
		$CALL DSWORD[MOVPROC]
		AH=AL;
		AL=6;
		AL-=CL;
		CX=asn;//преобр аргумент
		$TEST	BL,1
		IF(NOTZEROFLAG)CL=asv;//преобр аргумент
		BX><CX;
	}
	ELSE{
		CX=keyk+0X35;
		$OR BL,BL
		IF(ZEROFLAG)CL=keyk;
		BX><CX;
		AH=AL;
		AL--;
	}
	$XLAT
	IF(AL>=0X20)AH=0;
	$POP	BX
	ESWORD[BX]=AX;
L_01E8:
	DSBYTE[D9]=DL;
	$POP	ES
	$POP	DS
	$POPA
}

SCANSIM()
{
	$PUSH	ES
	CL=7;
	$PUSH	CS
	$POP	ES
	DI=lat;//преобр аргумент
	$REPNZ
	$SCASB
	$POP	ES
}

byte MOVEBL={0X1a,0X1b,0X27,0X28,0X33,0X34,0X35,
						91,93,59,0X27,44,46,47,
						123,125,58,34,60,62,63,
						27,49,50,51,52,53,54,55,56,57,48,45,61,8,9,169,230,227,170,165,
            173,163,232,233,167,229,234,13,255,228,235,162,160,175,224,174,
						171,164,166,237,96,255,92,239,231,225,172,168,226,236,161,238,241,
						27,33,64,35,36,34,58,44,46,40,41,95,43,8,9,137,150,147,138,133,
						141,131,152,153,135,149,154,13,255,148,155,130,128,143,144,142,
						139,132,134,157,126,255,124,159,151,145,140,136,146,156,129,158,240};

interrupt SERVIS()
{
	IF(AX!=0XFEDC)$JMP FAR CSDWORD[OLDI]
	@ENABLE();
	BX=CS;
	AX=0X1234;
}

?define sizek 64

main()
{
	SI=0X80;	//разбор ком строки
	$LODSB
	IF(AL!=0){
		do{
			$LODSB
		} while ( AL==0X20 );
		AL&=0X5F;
		IF(AL!='U'){
			WRITESTR("Неверная команда");
			$INT 0x20
		}
		AX=0XFEDC;
		$INT 0X12
		IF(AX!=0X1234){
			WRITESTR("Программа не загружена!");
			$INT 0x20
		}
		DS=BX;
		AX=0X3512;
		$INT 0X21
		AX=ES;
		BX=DS;
		IF(AX==BX){
			AX=0X3509;
			$INT 0X21
			AX=ES;
			BX=DS;
			IF(AX==BX){
				SETINTVECT(,0X12,DSWORD[OLDI+2],DSWORD[OLDI]);
				SETINTVECT(,0X09,DSWORD[OLDINT9+2],DSWORD[OLDINT9]);
				ES=DS;
				AH=0X49;
				$INT 0X21
				DS=CS;
				WRITESTR("Программа выгружена из памяти.\n");
				$INT 0X20
			}
		}
		DS=CS;
		WRITESTR("Программу невозможно выгрузить.\n");
		$INT 0X20
	}
	AX=0XFEDC;
	$INT 0X12
	IF(AX==0X1234){
		WRITESTR("Программа уже загружена!\n");
		$INT 0x20
	}
	SI=#MOVEBL;	//перенос таблицы
	CX=sizek;
	DI=lat;
	$REPE
	$MOVSW
	DSBYTE[D9]=5;
	SI=#SCANSIM;	//перенос процедур
	CX=6;
	DI=MOVPROC;
	AX=DI+2;
	$STOSW
	$REPE
	$MOVSW
	DI=NSERV;
	SI=#SERVIS;
	CX=9;
	$REPE
	$MOVSW
	GETINTVECT(OLDINT9,0X9);
	SETINTVECT(,9,DS,#INT9);
	GETINTVECT(OLDI,0X12);
	SETINTVECT(,0X12,DS,NSERV);
	@RELEASEENV();
	@KEEP(,,,#SCANSIM);
}
