首页 文章

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

提问于
浏览
7

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

我的主要问题是在不停止程序的情况下读取按键的键盘状态 . 我发现了一些方法,但它们非常有限 . INT 21h,AH 0Ch读取最后按下的键,但采用文本编辑方式 . 它不仅一次只能读取一个键,而且类似记事本的命中检测使得无法知道密钥被保持了多长时间 . 在Google旅行期间,我也看到了60h到64h端口的引用,但就是这样,引用 . 实际解释和工作代码几乎不存在 . 或者也许我只是在使用搜索引擎时那么糟糕 .

我需要知道的是密钥是否被按下 . 最好的解决方案是拥有所有键盘键的缓冲区/数组并读取其状态; 1表示它已经下降,0表示它不是 . 或者只是访问已被命中和释放的最后一个键的列表将是很好的(当然,有一种方法可以清除缓冲区) . 谁能指出我正确的方向?

Edit: 首先,我应该提到我使用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是如何工作的话 .

3 回答

  • 0

    这是你如何做到的:

    ; 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位Vista / 7或DosBox中运行它 .

    UPDATE: 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
    
  • 0

    通常对于像这样的旧系统,人们使用BIOS有点像预先提供的库函数集,其中键盘函数之类的东西仅在它们方便时使用 . 在您的情况下,BIOS键盘服务不方便,因此您不使用它们 .

    相反,您希望用您自己的键盘中断处理程序替换BIOS键盘中断处理程序并实现您自己的键盘驱动程序 . 键盘使用IRQ1,它是中断9.中断向量表从0x0000:0x0000开始,所以你想得到4个字节在0x0000:9 * 4 = 0x0000:0x0024并将它们存储在某处(所以你可以把东西放回去当你的软件退出时正常)并将你自己的键盘IRQ处理程序的地址(偏移然后段)放在那里 .

    要编写自己的键盘驱动程序,首先要了解所涉及的硬件有两个 . 计算机中有键盘控制器芯片(或“PS / 2控制器”),它与键盘内部的芯片通话(通过串行通信) .

    有关键盘控制器芯片的信息,请参阅http://wiki.osdev.org/%228042%22_PS/2_Controller

    有关键盘内部芯片的信息,请参阅http://wiki.osdev.org/PS/2_Keyboard

  • 3

    使用端口60h和端口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
    

相关问题