8086 汇编中更快的键盘扫描代码检测

Faster keyboard scan code detection in 8086 assembly

是否有可能比仅从硬件端口 60h 读取更快地检测和收集键盘启动和制动?

每当我按下一个键,比方说 'W' 键,然后很快按下另一个键,'W' 键的中断代码仍然由端口 60h 返回。

在我正在编写的游戏中,这具有在用户尝试快速改变方向时将玩家精灵锁定在适当位置的效果。

我试过使用 int 16h 函数 01h 和 int 16h 函数 00,但与端口 60h 相比,它非常不稳定和缓慢。

这是我使用端口 60h 的输入代码。我只是将扫描码传递给 bp。我所有需要用户输入的程序都会检查 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

这里是使用 int 16h 的替代版本,效果不如使用端口 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

为了回答我自己的问题,通过端口 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."

我认为端口 60h 仍然返回 'W' 的中断代码的原因是键盘控制器没有足够的时间来记录我按下了一个新键的事实。

其实我是先按了另一个键,确实返回了那个键的make code。然后,一瞬间后,我的手指从 'W' 键上移开,用 'W' 中断代码覆盖端口 60h 返回的字节。

解决方案:只有与已存储在 bp 中的 make 代码相对应时才接受 break 代码。

新 HANDLE_INPUT 程序,现在运行得更好:

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