如何在x86程序集中检查密钥状态?

Die*_*Jay 7 keyboard x86 assembly input x86-16

我在今年1月份将x86程序集作为业余爱好,因此我可以制作适用于旧PC 80和Tandy 1000等老式8086计算机的游戏,但我找到的书并没有完全讲授这个特定主题.虽然有些dos和bios中断了这项工作,但它们远非完美.

我的主要问题是在不停止程序的情况下读取按键的键盘状态.我发现了一些方法,但它们非常有限.INT 21h,AH 0Ch读取最后按下的键,但采用文本编辑方式.它不仅一次只能读取一个键,而且类似记事本的命中检测使得无法知道密钥被保持了多长时间.在Google旅行期间,我也看到了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
Run Code Online (Sandbox Code Playgroud)

我不确定我是否正确编码了中断.如果我知道端口060h - 064h是如何工作的话.

Ale*_*nze 3

您可以这样做:

; 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 Code Online (Sandbox Code Playgroud)

在 DOS/Win9x/NT/2K/XP/32 位 Vista/7 或 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
Run Code Online (Sandbox Code Playgroud)