第一次按键后int 16h / ah = 1

时间:2019-04-30 18:50:43

标签: assembly keyboard x86-16 bios

我正在用程序集8086编写游戏。我修复了游戏无法打开时的问题,但无法修复控件。

ESC 键起作用。当我按下它时,它会进入 _QUIT 功能,但是如果在此之前按下任何其他键,控件将冻结并且不会对任何键做出反应。

我的功能有问题吗?

我试图将AL寄存器更改为AH,但是没有用。

_KEYCHECK:
        mov ah,01h
        int 16h

        cmp al,1Bh      ;ESC
        je _QUIT
        cmp al,48h      ;UP
        je _PLAYER.UP
        cmp al,50h      ;DOWN
        je _PLAYER.DOWN
        cmp al,4Bh      ;LEFT
        je _PLAYER.LEFT
        cmp al,4Dh      ;RIGHT
        je _PLAYER.RIGHT
        ret

2 个答案:

答案 0 :(得分:3)

您的 _KEYCHECK 功能正在使用BIOS.ReadKeyboard 状态功能。

如果没有可用的按键,它会通过设置ZeroFlag(ZF)来通知您有关键盘按键的可用性,或者如果有一个按键在等待中,则会通过清除ZeroFlag来通知您。在后一种情况下,您还将收到密钥的ASCII码和扫描码。
重要的是,报告的可用键保留在键盘缓冲区中。在某种意义上,您在ALAH中获得的信息只是预览而不是实际的密钥。这解释了您的观察:

  

...但是如果在此之前按下了其他任何键,则控件将释放...

解决方案是从键盘缓冲区中删除键。这就是BIOS.ReadKeyboard 字符的功能。如果某个键在等待,它将很快从缓冲区中删除该键而返回。如果没有可用的密钥,它将等到一个可用的密钥之后再返回,并从缓冲区中删除该密钥。

_KEYCHECK:
    mov     ah, 01h     ; BIOS.ReadKeyboardStatus
    int     16h         ; -> AX ZF
    jz      NoKeyAvailable
    mov     ah, 00h     ; BIOS.ReadKeyboardCharacter
    int     16h         ; -> AX

    cmp     al, 1Bh      ;ESC
    je      _QUIT
    cmp     ah, 48h      ;UP
    je      _PLAYER.UP
    cmp     ah, 50h      ;DOWN
    je      _PLAYER.DOWN
    cmp     ah, 4Bh      ;LEFT
    je      _PLAYER.LEFT
    cmp     ah, 4Dh      ;RIGHT
    je      _PLAYER.RIGHT
NoKeyAvailable:
    ret

请注意:

  • 您实际上并没有检查ZeroFlag来确定ALAH中的信息是否有效。
  • 数字1Bh(ESC)是ASCII码,必须从AL中进行检查,但是所有其他代码48h(UP),50h(DOWN),4Bh(LEFT)和4Dh(RIGHT)都是扫描码,因此必须从AH中进行检查。

答案 1 :(得分:1)

您正在使用int 16h,1。 如您所见here,特殊键(如箭头)的值称为扫描代码,并且扫描代码以ah返回。试试

        mov ah,01h
        int 16h
        cmp al,1Bh      ;ESC
        je _QUIT
        cmp ah,48h      ;UP
        je _PLAYER.UP
        cmp ah,50h      ;DOWN
        je _PLAYER.DOWN
        cmp ah,4Bh      ;LEFT
        je _PLAYER.LEFT
        cmp ah,4Dh      ;RIGHT
        je _PLAYER.RIGHT

如果那不起作用,建议您调试并检查问题是否在其他地方(例如,尝试在_PLAYER.UP下打印内容)