I took x86 assembly as a hobby this past january so I could make games that would work on old 8086-powered computers like the PCj and Tandy 1000, but the books I found don\'
Typically for old systems like this people used the BIOS a bit like a pre-supplied set of library functions, where things like keyboard functions are only used if they've convenient. In your case the BIOS keyboard services aren't convenient, so you don't use them.
Instead, you want to replace the BIOS keyboard interrupt handler with your own keyboard interrupt handler and implement your own keyboard driver. The keyboard uses IRQ1, which is interrupt 9. The interrupt vector table starts at 0x0000:0x0000 so you'd want to get the 4 bytes at 0x0000:9*4 = 0x0000:0x0024 and store them somewhere (so you can put things back to normal when your software exits) and put the address (offset then segment) of your own keyboard IRQ handler there instead.
To write your own keyboard driver, you'd want to start by understanding that there's 2 pieces of hardware involved. There's the keyboard controller chip (or "PS/2 controller") in the computer which talks (via. serial communication) to a chip inside the keyboard itself.
For information on the keyboard controller chip, see something like http://wiki.osdev.org/%228042%22_PS/2_Controller
For information on the chip inside the keyboard itself, see something like http://wiki.osdev.org/PS/2_Keyboard
Here's how you can do it:
; compile with NASM: nasm.exe -f bin kbd.asm -o kbd.com
bits 16
org 0x100
xor ax, ax
mov es, ax
cli ; update ISR address w/ ints disabled
push word [es:9*4+2] ; preserve ISR address
push word [es:9*4]
mov word [es:9*4], irq1isr
mov [es:9*4+2],cs
sti
call test
cli ; update ISR address w/ ints disabled
pop word [es:9*4] ; restore ISR address
pop word [es:9*4+2]
sti
ret
test:
mov ah, 9
mov dx, msg1
int 0x21 ; print "Press and hold ESC"
test1:
mov al, [kbdbuf + 1] ; check Escape key state (Esc scan code = 1)
or al, al
jz test1 ; wait until it's nonzero (pressed/held)
mov dx, msg2
int 0x21 ; print "ESC pressed, release ESC"
test2:
mov al, [kbdbuf + 1] ; check Escape key state (Esc scan code = 1)
or al, al
jnz test2 ; wait until it's zero (released/not pressed)
mov dx, msg3 ; print "ESC released"
int 0x21
ret
irq1isr:
pusha
; read keyboard scan code
in al, 0x60
; update keyboard state
xor bh, bh
mov bl, al
and bl, 0x7F ; bx = scan code
shr al, 7 ; al = 0 if pressed, 1 if released
xor al, 1 ; al = 1 if pressed, 0 if released
mov [cs:bx+kbdbuf], al
; send EOI to XT keyboard
in al, 0x61
mov ah, al
or al, 0x80
out 0x61, al
mov al, ah
out 0x61, al
; send EOI to master PIC
mov al, 0x20
out 0x20, al
popa
iret
kbdbuf:
times 128 db 0
msg1 db "Press and hold ESC", 13, 10, "$"
msg2 db "ESC pressed, release ESC", 13, 10, "$"
msg3 db "ESC released", 13, 10, "$"
Run it in DOS/Win9x/NT/2K/XP/32-bit Vista/7 or DosBox.
UPDATE: TASM version:
; file: kbdt.asm
; compile with TASM/TLINK:
; tasm.exe kbdt.asm
; tlink.exe /t kbdt.obj
.286
code segment use16
assume cs:code, ds:code, ss:code
org 100h
main:
xor ax, ax
mov es, ax
cli ; update ISR address w/ ints disabled
push word ptr es:[9*4+2] ; preserve ISR address
push word ptr es:[9*4]
mov word ptr es:[9*4], offset irq1isr
mov es:[9*4+2],cs
sti
call test0
cli ; update ISR address w/ ints disabled
pop word ptr es:[9*4] ; restore ISR address
pop word ptr es:[9*4+2]
sti
ret
test0:
mov ah, 9
mov dx, offset msg1
int 21h ; print "Press and hold ESC"
test1:
mov al, [kbdbuf + 1] ; check Escape key state (Esc scan code = 1)
or al, al
jz test1 ; wait until it's nonzero (pressed/held)
mov dx, offset msg2
int 21h ; print "ESC pressed, release ESC"
test2:
mov al, [kbdbuf + 1] ; check Escape key state (Esc scan code = 1)
or al, al
jnz test2 ; wait until it's zero (released/not pressed)
mov dx, offset msg3 ; print "ESC released"
int 21h
ret
irq1isr:
pusha
; read keyboard scan code
in al, 60h
; update keyboard state
xor bh, bh
mov bl, al
and bl, 7Fh ; bx = scan code
shr al, 7 ; al = 0 if pressed, 1 if released
xor al, 1 ; al = 1 if pressed, 0 if released
mov cs:[bx+kbdbuf], al
; send EOI to XT keyboard
in al, 61h
mov ah, al
or al, 80h
out 61h, al
mov al, ah
out 61h, al
; send EOI to master PIC
mov al, 20h
out 20h, al
popa
iret
kbdbuf db 128 dup (0)
msg1 db "Press and hold ESC", 13, 10, "$"
msg2 db "ESC pressed, release ESC", 13, 10, "$"
msg3 db "ESC released", 13, 10, "$"
code ends
end main
Example of polling the keyboard using port 60h and port 64h:
cli ; stop software-Interrupts
mov al, 2 ; stop IRQ 1
out 21h, al
sti
P1:
in al, 64h ; get Status
test al, 1 ; is there something in the outputbuffer?
jz P1
test al, 20h ; it is a byte from the PS2-Mouse?
jnz P1
in al, 60h ; get a key
cmp al, 1 ; Escape-key?
jz XRAUS ; then goto end
;───────────────────────────────────────────────────────────────
mov si, OFFSET SONTAB ; get the offsetaddress of our special-key table
mov cl, Extablen ; lenght
XSUCH: cmp al, [si]
jz XFOUND
lea si, [si+1] ; instead of "inc si"
dec cl
jnz XSUCH
;───────────────────────────────────────────────────────────────
mov si, OFFSET TASTTAB ; get the offsetaddress of our key table
mov cx, tablen
mov bx, OFFSET TEXTTAB ; our corresponding ASCII table
SUCH: cmp al, [si]
jz short FOUND
lea si, [si+1]
dec cx
jnz SUCH
jmp P1
;───────────────────────────────────────────────────────────────
XRAUS: in al, 60h ; clear outputbuffer
cli
xor al, al ; enable IRQ 1
out 21h, al
sti
mov ah, 1 ; clear buffer in the ram
int 16h
; ...some more instructions
;───────────────────────────────────────────────────────────────
FOUND: mov si, tablen ; Length
sub si, cx
xor ecx, ecx
mov cl, [bx+si] ; get the ASCII from our table
; ...some more instructions
;───────────────────────────────────────────────────────────────
XFOUND:
; Tab,shift li.,shift re.,HOME,UP,LEFT,RIGHT,END,DOWN
cmp cl, 1 ; DOWN-key
jnz short ... ; jump to next
....
....
cmp cl, 9 ; Tab-key
jnz P1
; ...some more instructions
:------------------------Data area----------------------
TASTTAB DB 02h,03h,04h,05h,06h,07h,08h,09h,0Ah,0Bh,0Ch,0Dh
DB 10h,11h,12h,13h,14h,15h,16h,17h,18h,19h,1Ah,1Bh,1Eh,1Fh
DB 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Bh,2Ch,2Dh,2Eh,2Fh
DB 30h,31h,32h,33h,34h,35h,39h
DB 56h
tablen = ($-TASTTAB)
TEXTTAB DB "1234567890ß'" ; with some german letters inside
DB "qwertzuiopü+as"
DB "dfghjklöä^#yxcv"
DB "bnm,.- "
DB "<"
Textablen = ($-TEXTTAB)
;---------------------------------------------------------------------------
; Tab,shift left.,shift rigth.,HOME,UP,LEFT,RIGHT,END,DOWN
;----------
SONTAB DB 0Fh,2Ah,36h,47h,48h,4Bh,4Dh,4Fh,50h
Extablen = ($-SONTAB)
DB 0,0,0 ; for data_alignment of following entries