Файл kbdc.c:
#include <stdio.h>
extern void SetNewIrq9Isr(void);
extern void RestoreOldIrq9Isr(void);
#define SCAN_BUF_SIZE 1024
extern volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
extern volatile unsigned ScanReadIdx;
extern volatile unsigned ScanWriteIdx;
const char ScanToChar[] =
"??1234567890-=??"
"QWERTYUIOP[]??AS"
"DFGHJKL;\"`?\\ZXCV"
"BNM,./??? ";
int IsScanCodeAvailable(void)
{
return ((ScanWriteIdx - ScanReadIdx) & (SCAN_BUF_SIZE - 1)) != 0;
}
unsigned char GetScanCode(void)
{
unsigned char code;
while (!IsScanCodeAvailable());
code = ScanBuf[ScanReadIdx];
ScanReadIdx++;
ScanReadIdx &= SCAN_BUF_SIZE - 1;
return code;
}
int main(void)
{
SetNewIrq9Isr();
printf("Press keys to see scan codes.\nPress ESC to exit.\n");
for (;;)
{
unsigned code, symbol;
code = GetScanCode();
symbol = code & 0x7F;
symbol = (symbol < sizeof(ScanToChar)) ? ScanToChar[symbol] : '?';
printf("scan code: 0x%02X, symbol: \"%c\"\n", code, (char)symbol);
if (code == 1)
{
break;
}
}
RestoreOldIrq9Isr();
return 0;
}
Файл kbda.asm:
GLOBAL _SetNewIrq9Isr, _RestoreOldIrq9Isr
GLOBAL _ScanBuf, _ScanReadIdx, _ScanWriteIdx
SEGMENT _TEXT PUBLIC CLASS=CODE USE16
; void SetNewIrq9Isr(void);
_SetNewIrq9Isr:
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, [es:bx]
mov [_pOldIrq9Isr], ax
mov word [es:bx], _NewIrq9Isr
mov ax, [es:bx + 2]
mov [_pOldIrq9Isr + 2], ax
mov [es:bx + 2], cs
sti
pop es
pop bx
ret
; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr:
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, [_pOldIrq9Isr]
mov [es:bx], ax
mov ax, [_pOldIrq9Isr + 2]
mov [es:bx + 2], ax
sti
pop es
pop bx
ret
_NewIrq9Isr:
pusha
push ds
mov ax, _DATA
mov ds, ax
in al, 60h
push ax
in al, 061h
mov ah, al
or al, 080h
out 061h, al
mov al, ah
out 061h, al
pop ax
; ScanBuf[ScanWriteIdx] = scan code;
; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
mov bx, [_ScanWriteIdx]
mov [_ScanBuf + bx], al
inc bx
and bx, 1023
mov [_ScanWriteIdx], bx
mov al, 20h
out 20h, al
pop ds
popa
iret
SEGMENT _DATA PUBLIC CLASS=DATA
_pOldIrq9Isr resd 1
; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf resb 1024
_ScanReadIdx dw 0
_ScanWriteIdx dw 0
Вывод:
Press keys to see scan codes.
Press ESC to exit.
scan code: 0x10, symbol: "Q"
scan code: 0x90, symbol: "Q"
scan code: 0x11, symbol: "W"
scan code: 0x91, symbol: "W"
scan code: 0x12, symbol: "E"
scan code: 0x92, symbol: "E"
scan code: 0x02, symbol: "1"
scan code: 0x82, symbol: "1"
scan code: 0x03, symbol: "2"
scan code: 0x83, symbol: "2"
scan code: 0x04, symbol: "3"
scan code: 0x84, symbol: "3"
scan code: 0x01, symbol: "?"
Теперь несколько слов о том, как это скомпилировать.
Скомпилируйте файл сборки с помощью NASM, используя nasm.exe -f obj kbda.asm
. Это произведет kbda.obj
. Создайте проект в Borland/Turbo C/C++ IDE, включите в него kbdc.c
и kbda.obj
. Убедитесь, что код будет скомпилирован в модели малой или крошечной памяти (по сути, нам нужно убедиться, что SetNewIrq9Isr()
и RestoreOldIrq9Isr()
будут вызываться как близлежащие функции). Скомпилируйте это.
Есть несколько предостережений.
Во-первых, ни одна из функций getc()
, gets()
, scanf()
и т. д. не будет работать, если ее вызывать между SetNewIrq9Isr()
и RestoreOldIrq9Isr()
. Они повесят программу.
Во-вторых, код не отслеживает ключи shift
, control
и alt
. Для вас это означает, что если вы запустите эту программу из IDE, нажав ctrl+F9
, когда программа завершится, IDE, скорее всего, подумает, что ctrl
все еще нажата. Чтобы «разблокировать» клавиатуру, вам нужно будет нажать и отпустить ctrl
. То же самое может относиться к другим подобным клавишам, если они удерживаются нажатыми при запуске этой программы. Вы можете включить дополнительный код, чтобы дождаться освобождения всех shift
, control
и alt
. Я считаю, что вы можете найти их текущее состояние в области данных BIOS.
Конечно, вы можете преобразовать файл сборки из синтаксиса NASM в синтаксис TASM и скомпилировать его с помощью TASM. Я просто использую бесплатные инструменты, Turbo C++ 1.01 и NASM.
ОБНОВЛЕНИЕ. Вот asm-файл для TASM:
PUBLIC _SetNewIrq9Isr, _RestoreOldIrq9Isr
PUBLIC _ScanBuf, _ScanReadIdx, _ScanWriteIdx
.386
_TEXT SEGMENT PUBLIC 'CODE' USE16
ASSUME CS:_TEXT, DS:_DATA
; void SetNewIrq9Isr(void);
_SetNewIrq9Isr PROC NEAR
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, es:[bx]
mov _pOldIrq9IsrOfs, ax
mov word ptr es:[bx], offset _NewIrq9Isr
mov ax, es:[bx + 2]
mov _pOldIrq9IsrSeg, ax
mov es:[bx + 2], cs
sti
pop es
pop bx
ret
_SetNewIrq9Isr ENDP
; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr PROC NEAR
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, _pOldIrq9IsrOfs
mov es:[bx], ax
mov ax, _pOldIrq9IsrSeg
mov es:[bx + 2], ax
sti
pop es
pop bx
ret
_RestoreOldIrq9Isr ENDP
_NewIrq9Isr PROC NEAR
pusha
push ds
mov ax, _DATA
mov ds, ax
in al, 60h
push ax
in al, 061h
mov ah, al
or al, 080h
out 061h, al
mov al, ah
out 061h, al
pop ax
; ScanBuf[ScanWriteIdx] = scan code;
; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
mov bx, _ScanWriteIdx
mov _ScanBuf[bx], al
inc bx
and bx, 1023
mov _ScanWriteIdx, bx
mov al, 20h
out 20h, al
pop ds
popa
iret
_NewIrq9Isr ENDP
_TEXT ENDS
_DATA SEGMENT PUBLIC 'DATA' USE16
_pOldIrq9IsrOfs dw ?
_pOldIrq9IsrSeg dw ?
; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf db 1024 dup (?)
_ScanReadIdx dw 0
_ScanWriteIdx dw 0
_DATA ENDS
END
Вы компилируете его, используя tasm.exe /ml kbda.asm
. В остальном то же самое.
03.12.2011