问题
Is it possible to detect and collect keyboard makes and brakes faster than just reading from hardware port 60h?
Whenever I press a key, let's say the 'W' key, then very quickly press another key, the break code for the 'W' key is still returned by port 60h.
In the game i am writing, this has the effect of locking the player sprite in place when a user tries to quickly change direction.
I have tried using int 16h function 01h along with int 16h function 00, but it's very choppy and slow compared to port 60h.
Here's my input code using port 60h. I just pass a scancode into bp. All my procedures that require user input check the scancode in bp.
HANDLE_INPUT PROC
;CLEARS THE KEYBOARD TYPEHEAD BUFFER AND COLLECTS A SCANCODE
;ALTERS BP
push ax
push es
mov ax, 40h
mov es, ax ;access keyboard data area via segment 40h
mov WORD PTR es:[1ah], 1eh ;set the kbd buff head to start of buff
mov WORD PTR es:[1ch], 1eh ;set the kbd buff tail to same as buff head
;the keyboard typehead buffer is now cleared
xor ah, ah
in al, 60h ;al -> scancode
mov bp, ax ;bp -> scancode, accessible globally
pop es
pop ax
ret
HANDLE_INPUT ENDP
And here's the alternate version using int 16h, doesn't work nearly as well as the above version that uses port 60h.
HANDLE_INPUT PROC
;COLLECTS A SCANCODE
;ALTERS BP
push ax
xor bp, bp ;clear out bp
mov ah, 1 ;Function 1, check key status.
int 16h ;Is a key ready?
jz NO_KEY ;If zf cleared, then no.
xor ah, ah ;Otherwise, a key is waiting.
int 16h ;ah -> scancode
xor al, al
xchg al, ah ;ax -> scancode
mov bp, ax ;bp -> scancode, accessible globally
NO_KEY:
pop ax
ret
HANDLE_INPUT ENDP
回答1:
To answer my own question, scancodes provided via port 60h were not actually too slow, they were too fast.
In the following example given in my question: "Whenever I press a key, let's say the 'W' key, then very quickly press another key, the break code for the 'W' key is still returned by port 60h."
I thought the reason port 60h still returned the break code for the 'W' was due to the keyboard controller not having enough time to register the fact that I had struck a new key.
Actually, I was pressing the other key first, and the make code for the key was indeed being returned. Then, a split second later, my finger lifted from the 'W' key overwriting the byte returned by port 60h with the 'W' break code.
The solution: Only honor break codes if they correspond with the make code already stored in bp.
New HANDLE_INPUT procedure, now working much better:
HANDLE_INPUT PROC
;CLEARS THE KEYBOARD TYPEHEAD BUFFER AND COLLECTS A SCANCODE
;ALTERS BP
push ax
push bx
push es
mov ax, 40h
mov es, ax ;access keyboard data area via segment 40h
mov WORD PTR es:[1ah], 1eh ;set the kbd buff head to start of buff
mov WORD PTR es:[1ch], 1eh ;set the kbd buff tail to same as buff head
;the keyboard typehead buffer is now cleared
xor ah, ah
in al, 60h ;al -> scancode
test al, 80h ;Is a break code in al?
jz ACCEPT_KEY ;If not, accept it.
;If so, check to see if it's the break code
;that corresponds with the make code in bp.
mov bx, bp ;bx -> make code
or bl, 80h ;change make code into it's break code
cmp bl, al ;Do the new and old break codes match?
je ACCEPT_KEY ;If so, accept the break code.
pop es ;If not, bp retains old make code.
pop bx
pop ax
ret
ACCEPT_KEY:
mov bp, ax ;bp -> scancode, accessible globally
pop es
pop bx
pop ax
ret
HANDLE_INPUT ENDP
来源:https://stackoverflow.com/questions/47786199/faster-keyboard-scan-code-detection-in-8086-assembly