去年 1 月,我将 x86 组装作为一种爱好,因此我可以制作适用于 PCj 和 Tandy 1000 等老式 8086 计算机的游戏,但我发现的书籍并没有确切地教授该特定主题的内容。虽然一些 dos 和 bios 中断可以完成这项工作,但它们远非完美。
我的主要问题是在不停止程序的情况下读取按键的键盘状态。我找到了一些方法,但它们非常有限。INT 21h, AH 0Ch 读取最后按下的键,但以文本版本的方式。它不仅一次只能读取一个键,而且类似记事本的命中检测功能也使得无法知道该键被按住了多长时间。在我的谷歌旅行期间,我还看到了对端口 60h 到 64h 的引用,但仅此而已。实际的解释和工作代码几乎不存在。或者,也许我只是不擅长使用搜索引擎。
我需要知道的是一个键是否被按下。最好的解决方案是拥有所有键盘键的缓冲区/数组并读取其状态;1 表示已关闭,0 表示未关闭。或者只是访问最后一个被击中和释放的键的列表会很好(当然,有一种方法可以清除该缓冲区)。谁能指出我正确的方向?
编辑:首先,我应该提到我使用 Borland TASM。现在我编译了你的代码,它运行良好,尽管我几乎羞于承认我不理解其中的一半。我试图让它与 TASM 兼容,但它所做的只是在屏幕上创建垃圾并冻结。
这就是我想出的;
.MODEL TINY
.STACK 256
.DATA
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
main PROC
org 0100h
mov ax, @data
mov ds, ax
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]
lea si, irq1isr
mov word [es:9*4], si ; requires a register
mov [es:9*4+2],cs
sti
mov ah, 9
lea dx, msg1
int 021h ; 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)
lea dx, msg2
int 021h ; 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)
lea dx, msg3 ; print "ESC released"
int 021h
cli ; update ISR address w/ ints disabled
pop word [es:9*4] ; restore ISR address
pop word [es:9*4+2]
sti
ret
irq1isr:
push ax bx
; read keyboard scan code
in al, 060h
; update keyboard state
xor bh, bh
mov bl, al
and bl, 07Fh ; 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, 061h
mov ah, al
or al, 080h
out 061h, al
mov al, ah
out 061h, al
; send EOI to master PIC
mov al, 020h
out 020h, al
pop bx ax
iret
main ENDP
END main
我不确定我是否正确编码了中断。如果我知道端口 060h - 064h 是如何工作的,那就见鬼了。