如何检查 x86 程序集中的键状态? [英] How to check keys status in x86 assembly?
问题描述
去年 1 月,我将 x86 组装作为一种爱好,因此我可以制作可以在 PCj 和 Tandy 1000 等老式 8086 驱动计算机上运行的游戏,但我发现的书籍并没有确切地教授该特定主题的内容.虽然一些 dos 和 bios 中断可以完成这项工作,但它们远非完美.
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't exactly teach much on that specific topic. While some dos and bios interrupts kind of do the job, they're far from perfect.
我的主要问题是在不停止程序的情况下读取按键的键盘状态.我找到了一些方法,但它们非常有限.INT 21h, AH 0Ch 读取最后按下的键,但以文本版本的方式.它不仅一次只能读取一个键,而且类似记事本的命中检测功能也使得无法知道该键被按住了多长时间.在我的谷歌旅行期间,我还看到了对端口 60h 到 64h 的引用,但仅此而已.实际的解释和工作代码几乎不存在.或者也许我只是不擅长使用搜索引擎.
My main issue is reading the keyboard status for pressed keys without halting the program. I found a few methods, but they're very limited. INT 21h, AH 0Ch reads the last pressed key, but in a text-edition fashion. Not only does it read only one key at a time, but the notepad-like hit detection makes it impossible to know how long the key has been held. I've also seen references to the ports 60h to 64h during my Google travels, but it's just that, references. Actual explanations and working code is virtually non-existent. Or maybe I'm just that bad at using search engines.
我需要知道一个键是否被按下.最好的解决方案是拥有所有键盘键的缓冲区/数组并读取其状态;1 表示已关闭,0 表示未关闭.或者只是访问最后一个被击中和释放的键的列表会很好(当然,有一种方法可以清除该缓冲区).谁能指出我正确的方向?
What I need to know is whether a key is held down or not. The best solution would be to have a buffer/array of all the keyboard keys and read its state; 1 means it's down, 0 means it's not. Or just having access to a list of the last keys to have been hit and released would be nice (with a way to clear that buffer, of course). Can anyone point me in the right direction?
首先,我应该提到我使用的是 Borland TASM.现在我编译了你的代码,它运行良好,尽管我几乎羞于承认我不理解其中的一半.我试图让它与 TASM 兼容,但它所做的只是在屏幕上创建垃圾并冻结.
First off, I should have mentioned that I use Borland TASM. Now I compiled your code and it works great and all, even though I'm almost shy to admit I don't understand half of it. I tried to make it compatible with TASM but all it does is create garbage on the screen and freeze.
这是我想出的;
.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 是如何工作的,那就见鬼了.
I'm not sure if I even coded the interrupt right. And heck if I know how the ports 060h - 064h work.
推荐答案
你可以这样做:
; 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, "$"
在 DOS/Win9x/NT/2K/XP/32-bit Vista/7 或 DosBox 中运行.
Run it in DOS/Win9x/NT/2K/XP/32-bit Vista/7 or DosBox.
更新: TASM 版本:
; 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
这篇关于如何检查 x86 程序集中的键状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!