How to check keys status in x86 assembly?

后端 未结 3 1594
暖寄归人
暖寄归人 2020-12-11 17:40

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\'

相关标签:
3条回答
  • 2020-12-11 17:55

    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

    0 讨论(0)
  • 2020-12-11 18:01

    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
    
    0 讨论(0)
  • 2020-12-11 18:16

    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
    
    0 讨论(0)
提交回复
热议问题