// keydecodeドライバ for TOWNS ver.0.8
// ドライバーなので、タスクとは独立

segment DecodeMdl(USE32, PARA);

default(code == DecodeMdl);

void near Keydecode_Init();
void near Keydecode_setlock();

void far Keydecode_syscmd()
{
	int *cmd == FS:EBX;

	PUSHAD();
	AX = CS;
	PUSH(DS);
	AX += 8;
	DS = AX;
nextcmd:
	EAX = *cmd;
	if (EAX == 0)
		goto cmd0000;
	if (EAX == 0x0104)
		goto cmd0104; // Keydecode_setlock
	if (EAX == 0x0108)
		goto cmd0108; // Keydecode_Mainへのベクタ通知
	if (EAX == 0x0100)
		goto cmd0100; // 初期化
	INT(0x03);

cmd0000:
	POP(DS);
	[SS:ESP + 16] = EBX;
	POPAD();
	return;

cmd0100:
	// 初期化
	PUSH((offset) cmd);
	Keydecode_Init();
	POP((offset) cmd);
	(offset) cmd += 4;
	goto nextcmd;

cmd0104:
	// Keydecode_setlock
	EAX = cmd[4];
	PUSH((offset) cmd);
	Keydecode_setlock();
	POP((offset) cmd);
	(offset) cmd += 8;
	goto nextcmd;

cmd0108:
	// Keydecode_Mainへのベクタ通知
	asmout("MOV DWORD PTR FS:[EBX+4],OFFSET Keydecode_Main");
	(short) cmd[8] = CS;
	(offset) cmd += 12;
	goto nextcmd;
}

void far Keydecode_Main()
{
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;

	segment DecodeMdl == CS;
 
	asmout("#work_keycode   EQU 0");
	asmout("#work_keytype   EQU #work_keycode+256");
	asmout("#work_msg       EQU #work_keytype+256");
	asmout("#work_tenkey    EQU #work_msg+64");
	asmout("#work_twocase   EQU #work_tenkey");
	asmout("#work_signal    EQU #work_twocase+60H");
	asmout("#work_jmptable  EQU #work_signal+8");
	asmout("#work_shiftflag EQU #work_jmptable+20");
	asmout("#work_pause     EQU #work_shiftflag+1");
	asmout("#work_dummy0    EQU #work_pause+1");
	asmout("#work_sigcall   EQU #work_dummy0+2");
	asmout("#work_size      EQU #work_sigcall+8");

	asmout("KeyCode_Esc         EQU 080H");
	asmout("KeyCode_F1          EQU 081H");
	asmout("KeyCode_F2          EQU 082H");
	asmout("KeyCode_F3          EQU 083H");
	asmout("KeyCode_F4          EQU 084H");
	asmout("KeyCode_F5          EQU 085H");
	asmout("KeyCode_F6          EQU 086H");
	asmout("KeyCode_F7          EQU 087H");
	asmout("KeyCode_F8          EQU 088H");
	asmout("KeyCode_F9          EQU 089H");
	asmout("KeyCode_F10         EQU 08AH");
	asmout("KeyCode_F11         EQU 08BH");
	asmout("KeyCode_F12         EQU 08CH");
	asmout("KeyCode_Enter       EQU 0A0H");
	asmout("KeyCode_Backspace   EQU 0A1H");
	asmout("KeyCode_Tab         EQU 0A2H");
	asmout("KeyCode_Insert      EQU 0A4H");
	asmout("KeyCode_Delete      EQU 0A5H");
	asmout("KeyCode_Home        EQU 0A6H");
	asmout("KeyCode_End         EQU 0A7H");
	asmout("KeyCode_PageUp      EQU 0A8H");
	asmout("KeyCode_PageDown    EQU 0A9H");
	asmout("KeyCode_Left        EQU 0ACH");
	asmout("KeyCode_Right       EQU 0ADH");
	asmout("KeyCode_Up          EQU 0AEH");
	asmout("KeyCode_Down        EQU 0AFH");
	asmout("KeyCode_PrintScreen EQU 0B0H");
	asmout("KeyCode_ScrollLock  EQU 0B1H");
	asmout("KeyCode_NumLock     EQU 0B2H");
	asmout("KeyCode_CapsLock    EQU 0B3H");
	asmout("KeyCode_Pause       EQU 0B4H");
	asmout("KeyCode_Break       EQU 0B5H");
	asmout("KeyCode_SysRq       EQU 0B6H");
	asmout("KeyCode_Windows     EQU 0B8H");
	asmout("KeyCode_Menu        EQU 0BAh");
	asmout("KeyCode_Zenkaku     EQU 0C0H");
	asmout("KeyCode_Muhenkan    EQU 0C1H");
	asmout("KeyCode_Henkan      EQU 0C2H");
	asmout("KeyCode_Hiragana    EQU 0C3H");

	int *msg == DS:ESI;

	AX = CS;
	PUSH(DS);
	AX += 8;
	PUSH(ESI);
	DS = AX;
	EAX = msg[8];
	ECX = EAX;
	EAX <<= 4;
	ECX >>= 12;
	EAX &= 0xff0;
	ECX &= 0x3000;
	LEA(ESI, [EAX + ECX + 0x2000]);
	TEST((char) [DS:ESI], 0x0f);
	if (!= 0) {
		asmout("CALL FWORD PTR DS:[#work_sigcall]");
	//	asmout("fcall 12*8,TAPI_SingnalMessageTimer");
	}
	POP(ESI);
	POP(DS);

	EAX = msg[8];
	if ((unsigned) EAX >= 0x03000000) // overbreakとerrorは捨てる
		goto ret;
	DX = CS;
	PUSHFD();
	DX += 8;
	CLI(); // こんがらがらないようにするため
	PUSH(DS);
	DS = DX;
	ECX = EAX;
	EAX &= 0xffffff;
	if ((unsigned) EAX >= 0x100)
		goto over100;
	asmout("MOVZX EBX,BYTE PTR DS:[#work_keytype][EAX]");
	asmout("MOV AL,BYTE PTR DS:[#work_keycode][EAX]");
	if (EBX == 0)
		goto shift;
	TEST(ECX, 0x01000000);
	if (!= 0) // breakは無視
		goto ret2;
	asmout("JMP DWORD PTR DS:[#work_jmptable][EBX-4]");

over100:
	if (!=)
		goto ret2;
	asmout("MOV AL,BYTE PTR DS:[#work_pause]");
send_al:
asmout("Keydecode_Main_sendal:"); // type == 0x14
	asmout("MOV AH,BYTE PTR DS:[#work_shiftflag]");

send_ax:
asmout("Keydecode_Main_sendax:");
	asmout("MOV WORD PTR DS:[#work_msg+8],AX");
	PUSH(ESI);
	asmout("MOV ESI,OFFSET #work_msg");
	asmout("CALL FWORD PTR DS:[#work_signal]");
	POP(ESI);
ret2:
asmout("Keydecode_Main_ret2:");
	POP(DS);
	POPFD();
ret:
	return;

shift:
asmout("Keydecode_Main_shift:"); // type == 0x00
	if (ECX >= 0x02000000) // make/break以外は無視
		goto ret2;
	if (ECX < 0x01000000) { // make
		asmout("OR BYTE PTR DS:[#work_shiftflag],AL");
		goto ret2;
	}
	AL =~ AL;
	asmout("AND BYTE PTR DS:[#work_shiftflag],AL");
	goto ret2;

asmout("Keydecode_Main_lock:"); // type == 0x04
	PUSH(EAX);
	asmout("MOV BL,BYTE PTR DS:[#work_shiftflag]");
	if (BL == 0) {
		asmout("XOR AL,BYTE PTR DS:[#work_shiftflag]");
		asmout("MOV BYTE PTR DS:[#work_shiftflag],AL");
	//	SHR(AL,4);
	//	PUSH(FS);
	//	PUSH(EBX);
	//	PUSH((int) 0);
	//	PUSH(EAX);
	//	PUSH(0x0108 /* KeySetLed */);
	//	AX = SS;
	//	EBX = ESP;
	//	FS = AX;
	//	DB(0x9a); DD(0); DW((short) keyint_sel);
	//	ESP += 12;
	//	POP(EBX);
	//	POP(FS);
	//	asmout("fcall 8*8, KeySetLed");
	}
	POP(ECX);
//	asmout("MOV AL,KeyCode_NumLock");
//	if (CL == 0x20)
//		goto send_al;
	asmout("MOV AL,KeyCode_CapsLock");
	if (CL == 0x40)
		goto send_al;
	asmout("MOV AL,KeyCode_ScrollLock");
//	if (CL == 0x10)
		goto send_al;

asmout("Keydecode_Main_tenkey:"); // type == 0x08
	EBX = EAX;
	asmout("MOV AH,BYTE PTR DS:[#work_shiftflag]");
	asmout("MOV AL,BYTE PTR DS:[#work_tenkey][EBX]");
	TEST(AH, 0x20); // NumLock
	if (== 0)
		goto tenkey_skip;
	TEST(AH, 0x01); // shift
	/* (false) */ if (!= 0)
		goto tenkey_skip2;
	asmout("MOV AL,BYTE PTR DS:[#work_tenkey+30H][EBX]");
tenkey_skip:
	if (AL != 0)
		goto send_ax;
	goto ret2;

tenkey_skip2:
	AH &= 0xfe; // shiftを消す
	if (AL != 0)
		goto send_ax;
	goto ret2;

asmout("Keydecode_Main_alphabet:"); // type == 0x0C
	asmout("MOV AH,BYTE PTR DS:[#work_shiftflag]");
	TEST(AH, 0x01); // shift
	if (!= 0) {
		AL ^= 0x20;
	}
	TEST(AH, 0x40); // caps
	if (== 0)
		goto send_ax;
	AL ^= 0x20;
	goto send_ax;

asmout("Keydecode_Main_twocase:"); // type == 0x10
	EBX = EAX;
	asmout("MOV AH,BYTE PTR DS:[#work_shiftflag]");
	asmout("MOV AL,BYTE PTR DS:[#work_twocase][EBX]");
	TEST(AH, 0x01); // shift
	if (== 0)
		goto send_ax;
	asmout("MOV AL,BYTE PTR DS:[#work_twocase+30H][EBX]");
	goto send_ax;
}

void near Keydecode_setlock()
// ALの上位4bitを使う。下位4bitは0にすること。
{
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;

	asmout("#work_keycode   EQU 0");
	asmout("#work_keytype   EQU #work_keycode+256");
	asmout("#work_msg       EQU #work_keytype+256");
	asmout("#work_tenkey    EQU #work_msg+64");
	asmout("#work_twocase   EQU #work_tenkey");
	asmout("#work_signal    EQU #work_twocase+60H");
	asmout("#work_jmptable  EQU #work_signal+8");
	asmout("#work_shiftflag EQU #work_jmptable+20");
	asmout("#work_pause     EQU #work_shiftflag+1");
	asmout("#work_dummy0    EQU #work_pause+1");
	asmout("#work_sigcall   EQU #work_dummy0+2");
	asmout("#work_size      EQU #work_sigcall+8");

//	PUSH(EAX);
//	PUSH(ECX);
	asmout("MOV CL,BYTE PTR DS:[#work_shiftflag]");
	CL &= 0x0f;
	AL |= CL;
	asmout("MOV BYTE PTR DS:[#work_shiftflag],AL");
	SHR(AL,4);
	PUSH(FS);
	PUSH((int) 0);
	PUSH(EAX);
	PUSH(0x0108 /* KeySetLed */);
	AX = SS;
	EBX = ESP;
	FS = AX;
	DB(0x9a); DD(0); DW((short) keyint_sel);
	ESP += 12;
	POP(FS);
//	asmout("fcall 8*8, KeySetLed");
//	POP(ECX);
//	POP(EAX);
	return;
}

void near Keydecode_Init()
{
	unsigned int Init_sel     ==  2 * 8, TAPI_sel   == 12 * 8;

	asmout("#work_keycode   EQU 0");
	asmout("#work_keytype   EQU #work_keycode+256");
	asmout("#work_msg       EQU #work_keytype+256");
	asmout("#work_tenkey    EQU #work_msg+64");
	asmout("#work_twocase   EQU #work_tenkey");
	asmout("#work_signal    EQU #work_twocase+60H");
	asmout("#work_jmptable  EQU #work_signal+8");
	asmout("#work_shiftflag EQU #work_jmptable+20");
	asmout("#work_pause     EQU #work_shiftflag+1");
	asmout("#work_dummy0    EQU #work_pause+1");
	asmout("#work_sigcall   EQU #work_dummy0+2");
	asmout("#work_size      EQU #work_sigcall+8");

	ECX = 4096 * 6 / 4;
	EAX = 0;
	ESI = 0;
	do {
		(int) [DS:ESI] = EAX;
		ESI += 4;
		ECX--;
	} while (!= 0);

	PUSH(FS);
	PUSH((int) 0); // eoc
	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x011c /* TAPI_SingnalMessageTimerのベクタをもらう */);
	AX = SS;
	EBX = ESP;
	FS = AX;
	DB(0x9a); DD(0); DW((short) TAPI_sel);
	POP(EAX);
	asmout("POP DWORD PTR DS:[#work_sigcall+0]");
	asmout("POP DWORD PTR DS:[#work_sigcall+4]");
	POP(EAX);
	POP(FS);

//	asmout("MOV DWORD PTR DS:[#WorkMsg+0],0"); // すべて捨てるモード
//	asmout("MOV DWORD PTR DS:[#WorkMsg+4],16"); // from keydecoder
	asmout("MOV DWORD PTR DS:[#work_msg+8],0");
//	asmout("MOV DWORD PTR DS:[#WorkSignal+0],OFFSET TAPI_SingnalMessageTimer"); // もう一段はさむ
//	asmout("MOV DWORD PTR DS:[#WorkSignal+4],12*8");
	asmout("MOV DWORD PTR DS:[#work_signal+0],OFFSET filter0");
	asmout("MOV DWORD PTR DS:[#work_signal+4],22*8");

	// リダイレクト先は３通り。F1〜F6のみ、music_player、scrath_pad

	struct keydecode_init_data {
		unsigned short addr;
		unsigned char data0, data1;
	};

//	EBX = 0;
//	EAX = 0;
//	asmout("MOV ECX,(#WorkSiz+3)/4");
//	do {
//		[DS:EBX] = EAX;
//		EBX += 4;
//		ECX--;
//	} while (!= 0);

	keydecode_init_data *table == CS:ESI;
	asmout("MOV ESI,OFFSET #InitTable");

	EBX = table->addr;
//	AL = table->data0;
//	AH = table->data1;
	AX = [CS:ESI + 2];
	(offset) table += sizeof (keydecode_init_data);
	do {
	//	TEST(AH, AH);
		[DS:EBX] = AL;
	//	if ((signed) >= 0) {
			[DS:EBX + 256] = AH;
	//	}
		EBX = table->addr;
	//	AL = table->data0;
	//	AH = table->data1;
		AX = [CS:ESI + 2];
		(offset) table += sizeof (keydecode_init_data);
	} while (EBX != 0xffff);

//	asmout("MOV ESI,OFFSET #InitTable2");

	EBX = table->addr;
	AL = table->data0;
	AH = table->data1;
	AX = [CS:ESI + 2];
	(offset) table += sizeof (keydecode_init_data);
	do {
	//	TEST(AH, AH);
		[DS:EBX] = AL;
	//	if ((signed) >= 0) {
			[DS:EBX + 0x30] = AH;
	//	}
		EBX = table->addr;
	//	AL = table->data0;
	//	AH = table->data1;
		AX = [CS:ESI + 2];
		(offset) table += sizeof (keydecode_init_data);
	} while (EBX != 0xffff);

	asmout("MOV BYTE PTR DS:[#work_pause],KeyCode_Pause");
	asmout("MOV BYTE PTR DS:[#work_shiftflag],0");
	asmout("MOV DWORD PTR DS:[#work_jmptable-4+04H],OFFSET Keydecode_Main_lock");
	asmout("MOV DWORD PTR DS:[#work_jmptable-4+08H],OFFSET Keydecode_Main_tenkey");
	asmout("MOV DWORD PTR DS:[#work_jmptable-4+0CH],OFFSET Keydecode_Main_alphabet");
	asmout("MOV DWORD PTR DS:[#work_jmptable-4+10H],OFFSET Keydecode_Main_twocase");
	asmout("MOV DWORD PTR DS:[#work_jmptable-4+14H],OFFSET Keydecode_Main_sendal");

	return;

	ALIGN(4);

	// bit 0- 7 : keycode from key-driver
	// bit 8-15 : 0
	// bit16-23 : keycode
	// bit24-31 : keytype(80ならこのフィールドを使わない)

	asmout("#InitTable:");

	asmout("DD #work_keycode+00010053H"); // shift
	asmout("DD #work_keycode+00020052H"); // ctrl
	asmout("DD #work_keycode+0004005CH"); // alt
	asmout("DD #work_keycode+00040072H"); /* alt代替の取り消し */

	asmout("DD #work_keycode+04400055H"); // caps-lock

	asmout("DD #work_keycode+0C000011H+65536*'q'");
	asmout("DD #work_keycode+0C000012H+65536*'w'");
	asmout("DD #work_keycode+0C000013H+65536*'e'");
	asmout("DD #work_keycode+0C000014H+65536*'r'");
	asmout("DD #work_keycode+0C000015H+65536*'t'");
	asmout("DD #work_keycode+0C000016H+65536*'y'");
	asmout("DD #work_keycode+0C000017H+65536*'u'");
	asmout("DD #work_keycode+0C000018H+65536*'i'");
	asmout("DD #work_keycode+0C000019H+65536*'o'");
	asmout("DD #work_keycode+0C00001AH+65536*'p'");
	asmout("DD #work_keycode+0C00001EH+65536*'a'");
	asmout("DD #work_keycode+0C00001FH+65536*'s'");
	asmout("DD #work_keycode+0C000020H+65536*'d'");
	asmout("DD #work_keycode+0C000021H+65536*'f'");
	asmout("DD #work_keycode+0C000022H+65536*'g'");
	asmout("DD #work_keycode+0C000023H+65536*'h'");
	asmout("DD #work_keycode+0C000024H+65536*'j'");
	asmout("DD #work_keycode+0C000025H+65536*'k'");
	asmout("DD #work_keycode+0C000026H+65536*'l'");
	asmout("DD #work_keycode+0C00002AH+65536*'z'");
	asmout("DD #work_keycode+0C00002BH+65536*'x'");
	asmout("DD #work_keycode+0C00002CH+65536*'c'");
	asmout("DD #work_keycode+0C00002DH+65536*'v'");
	asmout("DD #work_keycode+0C00002EH+65536*'b'");
	asmout("DD #work_keycode+0C00002FH+65536*'n'");
	asmout("DD #work_keycode+0C000030H+65536*'m'");

	asmout("DD #work_keycode+100B0002H"); // 1!
	asmout("DD #work_keycode+100C0003H"); // 2"
	asmout("DD #work_keycode+100D0004H"); // 3#
	asmout("DD #work_keycode+100E0005H"); // 4$
	asmout("DD #work_keycode+100F0006H"); // 5%
	asmout("DD #work_keycode+10100007H"); // 6&
	asmout("DD #work_keycode+10110008H"); // 7'
	asmout("DD #work_keycode+10120009H"); // 8(
	asmout("DD #work_keycode+1013000AH"); // 9)
	asmout("DD #work_keycode+1014000BH"); // 0~
	asmout("DD #work_keycode+1015000CH"); // -=
	asmout("DD #work_keycode+1016000DH"); // ^~
	asmout("DD #work_keycode+1017001BH"); // @`
	asmout("DD #work_keycode+1018001CH"); // [{
	asmout("DD #work_keycode+10190027H"); // ;+
	asmout("DD #work_keycode+101A0028H"); // :*
	asmout("DD #work_keycode+101B0029H"); // ]}
	asmout("DD #work_keycode+101C0031H"); // ,<
	asmout("DD #work_keycode+101D0032H"); // .>
	asmout("DD #work_keycode+101E0033H"); // /?
	asmout("DD #work_keycode+101F0034H"); // \_
	asmout("DD #work_keycode+1020000EH"); // \|

	asmout("DD #work_keycode+14000001H+65536*KeyCode_Esc");
	asmout("DD #work_keycode+1400000FH+65536*KeyCode_Backspace");
	asmout("DD #work_keycode+14000010H+65536*KeyCode_Tab");
	asmout("DD #work_keycode+1400001DH+65536*KeyCode_Enter");
	asmout("DD #work_keycode+14000071H+65536*KeyCode_Zenkaku");
	asmout("DD #work_keycode+14000036H+65536*'*'");
	asmout("DD #work_keycode+14000035H+65536*' '");
//	asmout("DD #work_keycode+14000055H+65536*KeyCode_CapsLock");
	asmout("DD #work_keycode+1400005DH+65536*KeyCode_F1");
	asmout("DD #work_keycode+1400005EH+65536*KeyCode_F2");
	asmout("DD #work_keycode+1400005FH+65536*KeyCode_F3");
	asmout("DD #work_keycode+14000060H+65536*KeyCode_F4");
	asmout("DD #work_keycode+14000061H+65536*KeyCode_F5");
	asmout("DD #work_keycode+14000062H+65536*KeyCode_F6");
	asmout("DD #work_keycode+14000063H+65536*KeyCode_F7");
	asmout("DD #work_keycode+14000064H+65536*KeyCode_F8");
	asmout("DD #work_keycode+14000065H+65536*KeyCode_F9");
	asmout("DD #work_keycode+14000066H+65536*KeyCode_F10");
//	asmout("DD #work_keycode+14000045H+65536*KeyCode_NumLock");
//	asmout("DD #work_keycode+14000046H+65536*KeyCode_ScrollLock");
	asmout("DD #work_keycode+14000039H+65536*'-'");
	asmout("DD #work_keycode+14000038H+65536*'+'");
	asmout("DD #work_keycode+140000DDH+65536*KeyCode_SysRq");
	asmout("DD #work_keycode+14000069H+65536*KeyCode_F11");
	asmout("DD #work_keycode+1400005BH+65536*KeyCode_F12");
	asmout("DD #work_keycode+14000056H+65536*KeyCode_Hiragana");
	asmout("DD #work_keycode+14000058H+65536*KeyCode_Henkan");
	asmout("DD #work_keycode+14000057H+65536*KeyCode_Muhenkan");
	asmout("DD #work_keycode+14000045H+65536*KeyCode_Enter");
	asmout("DD #work_keycode+14000037H+65536*'/'");
	asmout("DD #work_keycode+1400007DH+65536*KeyCode_PrintScreen");
	asmout("DD #work_keycode+1400007CH+65536*KeyCode_Break");
	asmout("DD #work_keycode+1400004EH+65536*KeyCode_Home");
	asmout("DD #work_keycode+1400004DH+65536*KeyCode_Up");
	asmout("DD #work_keycode+1400006EH+65536*KeyCode_PageUp");
	asmout("DD #work_keycode+1400004FH+65536*KeyCode_Left");
	asmout("DD #work_keycode+14000051H+65536*KeyCode_Right");
//	asmout("DD #work_keycode+140000CFH+65536*KeyCode_End");
	asmout("DD #work_keycode+14000050H+65536*KeyCode_Down");
	asmout("DD #work_keycode+14000070H+65536*KeyCode_PageDown");
	asmout("DD #work_keycode+14000048H+65536*KeyCode_Insert");
	asmout("DD #work_keycode+1400004BH+65536*KeyCode_Delete");
//	asmout("DD #work_keycode+140000DBH+65536*KeyCode_Windows");
//	asmout("DD #work_keycode+140000DCH+65536*KeyCode_Windows");
//	asmout("DD #work_keycode+140000DDH+65536*KeyCode_Menu");
	asmout("DD #work_keycode+140000E1H+65536*KeyCode_Home");
	asmout("DD #work_keycode+140000E2H+65536*KeyCode_End");

	asmout("DD #work_keycode+1400003AH+65536*'7'");
	asmout("DD #work_keycode+1400003BH+65536*'8'");
	asmout("DD #work_keycode+1400003CH+65536*'9'");
	asmout("DD #work_keycode+1400003DH+65536*'='");
	asmout("DD #work_keycode+1400003EH+65536*'4'");
	asmout("DD #work_keycode+1400003FH+65536*'5'");
	asmout("DD #work_keycode+14000040H+65536*'6'");
	asmout("DD #work_keycode+14000047H+65536*'.'");
	asmout("DD #work_keycode+14000042H+65536*'1'");
	asmout("DD #work_keycode+14000043H+65536*'2'");
	asmout("DD #work_keycode+14000044H+65536*'3'");
	asmout("DD #work_keycode+14000046H+65536*'0'");

	asmout("DD 0FFFFH");
#if 0
	asmout("DD #work_tenkey+0000H+1000000H*'7'+65536*KeyCode_Home");
	asmout("DD #work_tenkey+0001H+1000000H*'8'+65536*KeyCode_Up");
	asmout("DD #work_tenkey+0002H+1000000H*'9'+65536*KeyCode_PageUp");
	asmout("DD #work_tenkey+0003H+1000000H*'4'+65536*KeyCode_Left");
	asmout("DD #work_tenkey+0004H+1000000H*'5'+65536*'ｱ'");
	asmout("DD #work_tenkey+0005H+1000000H*'6'+65536*KeyCode_Right");
	asmout("DD #work_tenkey+0006H+1000000H*'1'+65536*KeyCode_End");
	asmout("DD #work_tenkey+0007H+1000000H*'2'+65536*KeyCode_Down");
	asmout("DD #work_tenkey+0008H+1000000H*'3'+65536*KeyCode_PageDown");
	asmout("DD #work_tenkey+0009H+1000000H*'0'+65536*KeyCode_Insert");
	asmout("DD #work_tenkey+000AH+1000000H*'.'+65536*KeyCode_Delete");
#endif
	asmout("DD #work_twocase+000BH+65536*'1'+1000000H*'!'");
	asmout("DD #work_twocase+000CH+65536*'2'+1000000H*22H");
	asmout("DD #work_twocase+000DH+65536*'3'+1000000H*23H");
	asmout("DD #work_twocase+000EH+65536*'4'+1000000H*'$'");
	asmout("DD #work_twocase+000FH+65536*'5'+1000000H*'%'");
	asmout("DD #work_twocase+0010H+65536*'6'+1000000H*'&'");
	asmout("DD #work_twocase+0011H+65536*'7'+1000000H*27H");
	asmout("DD #work_twocase+0012H+65536*'8'+1000000H*'('");
	asmout("DD #work_twocase+0013H+65536*'9'+1000000H*')'");
	asmout("DD #work_twocase+0014H+65536*'0'+1000000H*'0'");
	asmout("DD #work_twocase+0015H+65536*'-'+1000000H*'='");
	asmout("DD #work_twocase+0016H+65536*'^'+1000000H*'~'");
	asmout("DD #work_twocase+0017H+65536*'@'+1000000H*'`'");
	asmout("DD #work_twocase+0018H+65536*'['+1000000H*'{'");
	asmout("DD #work_twocase+0019H+65536*';'+1000000H*'+'");
	asmout("DD #work_twocase+001AH+65536*':'+1000000H*'*'");
	asmout("DD #work_twocase+001BH+65536*']'+1000000H*'}'");
	asmout("DD #work_twocase+001CH+65536*','+1000000H*'<'");
	asmout("DD #work_twocase+001DH+65536*'.'+1000000H*'>'");
	asmout("DD #work_twocase+001EH+65536*'/'+1000000H*'?'");
	asmout("DD #work_twocase+001FH+65536*'\'+1000000H*'_'");
	asmout("DD #work_twocase+0020H+65536*'\'+1000000H*'|'");

	asmout("DD 0FFFFH");

//	asmout("DD #work_pause+65536*KeyCode_Pause");
//	asmout("DD #WorkShiftFlag+65536*0"); // save対象
//	asmout("DD 0FFFFH");

}

void far filter0()
// F1〜F6しか通さないフィルター
{
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;

	asmout("#work_keycode   EQU 0");
	asmout("#work_keytype   EQU #work_keycode+256");
	asmout("#work_msg       EQU #work_keytype+256");
	asmout("#work_tenkey    EQU #work_msg+64");
	asmout("#work_twocase   EQU #work_tenkey");
	asmout("#work_signal    EQU #work_twocase+60H");
	asmout("#work_jmptable  EQU #work_signal+8");
	asmout("#work_shiftflag EQU #work_jmptable+20");
	asmout("#work_pause     EQU #work_shiftflag+1");
	asmout("#work_dummy0    EQU #work_pause+1");
	asmout("#work_sigcall   EQU #work_dummy0+2");
	asmout("#work_size      EQU #work_sigcall+8");

	EAX = [DS:ESI + 8];
	EAX &= 0x0fff;
	if (EAX == 0x6a5 /* Ctrl + Alt + Delete */) {
		// DMA停止
		CLI();
		AL = 0x0f;
		OUT(0x00af, AL);
		AL = 0;
		OUT(0x0020, AL);
		AL = 0x01;
		OUT(0x0020, AL);
		for (;;)
			HLT();

	/*	// double-faultでリセットをかける
		CLI();
		// GDTとIDTのリミットを0にする。
		EAX = 0;
		PUSH(EAX);
		PUSH(EAX);
		asmout("LGDTE FWORD PTR SS:[ESP+2]");
		asmout("LIDTE FWORD PTR SS:[ESP+2]");
		ESP = 256;
		INT(0x03);
	*/

	/*	PUSH([DS:ESI + 4]);
		PUSH([DS:ESI + 0]);
		(int) [DS:ESI + 0] = 0x00001241;
		(int) [DS:ESI + 4] = 0xffffff00;
		asmout("fcall 12*8,TAPI_SingnalMessageTimer");
		POP([DS:ESI + 0]);
		POP([DS:ESI + 4]);
		return;
*/	} else if (EAX == 0x6a4 /* Ctrl + Alt + Insert */) {
		PUSH([DS:ESI + 4]);
		PUSH([DS:ESI + 0]);
		(int) [DS:ESI + 0] = 0x00001241;
		(int) [DS:ESI + 4] = 0xffffff01;
		asmout("CALL FWORD PTR DS:[#work_sigcall]");
	//	asmout("fcall 12*8,TAPI_SingnalMessageTimer");
		POP([DS:ESI + 0]);
		POP([DS:ESI + 4]);
		return;
	}
	PUSH(DS);
	PUSH(ESI);
	EAX *= 16;
	ESI = 0x1000;
	EAX &= 0x0ff0;
	CX = CS; CX += 8; DS = CX;
	ESI += EAX;
	TEST((char) [DS:ESI], 0x0f);
	if (!= 0) {
		asmout("CALL FWORD PTR DS:[#work_sigcall]");
	//	asmout("fcall 12*8,TAPI_SingnalMessageTimer");
	}
	POP(ESI);
	POP(DS);
	return;
asmout("DecodeSiz:");
}

#if 0
void far filter1()
{
	EAX = [DS:ESI + 8];
	EAX &= 0x0fff;
	if (EAX == 0x6a5 /* Ctrl + Alt + Delete */) {
		asmout("fcall 8*8, KeyResetCPU");
		for (;;)
			HLT();

	/*	// double-faultでリセットをかける
		CLI();
		// GDTとIDTのリミットを0にする。
		EAX = 0;
		PUSH(EAX);
		PUSH(EAX);
		asmout("LGDTE FWORD PTR SS:[ESP+2]");
		asmout("LIDTE FWORD PTR SS:[ESP+2]");
		ESP = 256;
		INT(0x03);
	*/
	} else if (EAX == 0x6a4 /* Ctrl + Alt + Insert */) {
		CL = 0x01;
	} else if (EAX == 0x0ac /* left */) {
		CL = 0x10;
	} else if (EAX == 0x0ad /* right */) {
		CL = 0x11;
	} else if (EAX == 0x0a0 /* Enter */) {
		CL = 0x12;
	} else if (EAX == 0x1a0 /* Shift + Enter */) {
		CL = 0x13;
	} else if (EAX == 0x1ac /* Shift + left */) {
		CL = 0x14;
	} else if (EAX == 0x1ad /* Shift + right */) {
		CL = 0x15;
	} else if (EAX == 0x646 /* Ctrl + Alt + 'F' */) {
		CL = 0x16;
	} else if (EAX == 0x666 /* Ctrl + Alt + 'f' */) {
		CL = 0x16;
	} else if (EAX == 0x746 /* Shift + Ctrl + Alt + 'F' */) {
		CL = 0x17;
	} else if (EAX == 0x766 /* Shift + Ctrl + Alt + 'f' */) {
		CL = 0x17;
	} else
		return;

	ECX |= 0xffffff00;
	PUSH([DS:ESI + 4]);
	PUSH([DS:ESI + 0]);
	(int) [DS:ESI + 0] = 0x00001241;
	(int) [DS:ESI + 4] = ECX;
	asmout("fcall 12*8,TAPI_SingnalMessageTimer");
	POP([DS:ESI + 0]);
	POP([DS:ESI + 4]);
	return;
asmout("DecodeSiz:");
}
#endif
