2012-05-09 19 views
7

wziąłem zespół x86 jako hobby W styczniu tego roku, więc może tworzyć gry, które działają na starych 8086 zasilanych komputerach takich jak PCJ i Tandy 1000 książek, ale nie znalazłem dokładnie nauczyć wiele na temat tego konkretnego tematu. Podczas gdy niektóre metody dos i bios przerywają rodzaj wykonywanej pracy, są dalekie od doskonałości.Jak sprawdzić status kluczy w zestawie x86?

Moim głównym problemem jest czytanie stan klawiatury po wciśnięciu przycisku bez zatrzymania programu. Znalazłem kilka metod, ale są one bardzo ograniczone. INT 21h, AH 0Ch czyta ostatni wciśnięty klawisz, ale w trybie edycji tekstu. Nie tylko odczytuje tylko jeden klucz na raz, ale wykrywanie trafienia w sposób podobny do notatnika uniemożliwia ustalenie, jak długo klucz był trzymany. Podczas moich podróży do Google widziałem także odniesienia do portów od 60 do 64 godzin, ale to tylko odniesienia. Rzeczywiste wyjaśnienia i działający kod praktycznie nie istnieją. A może po prostu źle korzystam z wyszukiwarek.

Co muszę wiedzieć, czy klawisz jest wciśnięty czy nie. Najlepszym rozwiązaniem byłoby posiadanie bufora/tablicy wszystkich klawiszy klawiatury i odczytanie jego stanu; 1 oznacza, że ​​jest wyłączony, 0 oznacza, że ​​nie. Lub po prostu dostęp do listy ostatnich kluczy, które zostały trafione i wydane, byłoby miłe (oczywiście z możliwością wyczyszczenia tego bufora). Czy ktoś może wskazać mi właściwy kierunek?

Edit: Po pierwsze, muszę wspomnieć, że używam Borland TASM. Teraz skompilowałem twój kod i działa świetnie i wszystko, mimo że jestem prawie nieśmiały, aby przyznać, że nie rozumiem połowy tego. Próbowałem uczynić go kompatybilnym z TASM, ale wszystko, co robi, to tworzenie śmieci na ekranie i zamrażanie.

Oto, co wymyśliłem;

.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 

Nie jestem pewien, czy nawet zakodowałem przerwanie w prawo. I do cholery, jeśli wiem, jak działają porty 060h - 064h.

+0

Twoim głównym problemem jest to, że robisz się programu podczas .EXE kod powinien zostać skompilowany do programu .COM. Zobacz zaktualizowaną odpowiedź. –

+0

Działający Tetris OS, który robi to, co chcesz: https://github.com/programble/tetrasm –

Odpowiedz

3

Oto w jaki sposób można to zrobić:

; 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, "$" 

Uruchom w systemie DOS/Win9x/NT/2K/XP/32-bit Vista/7 lub DosBox.

UPDATE: wersja 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

Po pierwsze, powinienem wspomnieć, że używam Borland TASM. Teraz skompilowałem twój kod i działa świetnie i wszystko, mimo że jestem prawie nieśmiały, aby przyznać, że nie rozumiem połowy tego. Próbowałem uczynić go kompatybilnym z TASM, ale wszystko, co robi, to tworzenie śmieci na ekranie i zamrażanie. – DieJay

+0

Tak! To działa! Zmodyfikowałem go tak, aby struktura pasowała do tego z mojego bieżącego projektu i jeszcze się nie zepsuła, więc jest po prostu idealna. Nie rozumiem dokładnie, jak to działa (na przykład w przypadku portów), ale tak długo, jak to się stanie, nie będę narzekać. Wielkie dzięki! Teraz mogę tworzyć gry akcji w czasie rzeczywistym! = D – DieJay

0

Typowo dla starych systemów, takich jak ten lud wykorzystywane bios trochę jak wcześniej dostarczony zestaw funkcji bibliotecznych, gdzie takie rzeczy funkcji klawiatury są używane tylko wtedy, gdy mam wygodne. W twoim przypadku usługi klawiatury systemu BIOS nie są wygodne, więc nie używasz ich.

Zamiast tego chcesz zastąpić obsługę przerwań klawiatury BIOS za pomocą własnego przerywacza klawiatury i zaimplementować własny sterownik klawiatury. Klawiatura wykorzystuje przerwanie IRQ1, które jest przerwaniem 9. Tabela wektorów przerwań rozpoczyna się od 0x0000: 0x0000, więc chcesz uzyskać 4 bajty o wartości 0x0000: 9 * 4 = 0x0000: 0x0024 i przechowywać je gdzieś (aby można było przywrócić dane z powrotem do normalnego po wyjściu z oprogramowania) i zamiast tego wstaw adres (offset, segment) własnej procedury obsługi przerwań na klawiaturze.

Aby napisać własny sterownik klawiatury, którą chcesz zacząć od zrozumienia, że ​​nie ma 2 kawałki sprzętowych. W komputerze jest układ kontrolera klawiatury (lub "kontroler PS/2"), który komunikuje się (za pośrednictwem komunikacji szeregowej) z chipem wewnątrz samej klawiatury.

Więcej informacji na temat sterownika układu klawiatury, zobaczyć coś takiego http://wiki.osdev.org/%228042%22_PS/2_Controller

uzyskać informacje na chipie wewnątrz samej klawiatury, zobaczyć coś takiego http://wiki.osdev.org/PS/2_Keyboard

0

Przykład odpytywania klawiaturze używając 60h i 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 
Powiązane problemy