第一次使用 int 16h / ah=1 按键后,我的游戏控件冻结
The controls of my game freeze after the first keypress with int 16h / ah=1
我正在用程序集 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
您正在使用 int 16h,1。
如你所见here,特殊键(如箭头)有一个名为扫描码的值,扫描码在啊中返回。尝试
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 下打印一些东西)
您的 _KEYCHECK 函数正在使用 BIOS.ReadKeyboardStatus 函数。
如果没有键可用,它会通过设置 ZeroFlag (ZF) 通知您键盘键的可用性,或者如果键正在等待,则通过清除 ZeroFlag 来通知您键盘键的可用性。在后一种情况下,您还将收到密钥的 ASCII 码和扫描码。
这里重要的是报告可用的键保留在键盘缓冲区中。您在 AL
和 AH
中获得的信息只是预览而不是实际密钥(在某种意义上)。这解释了您的观察结果:
... but if any other key was pressed before that the controls frees ...
解决办法是从键盘缓冲区中删除键。这就是 BIOS.ReadKeyboardCharacter 所做的。如果一个键正在等待,它会很快 return 并从缓冲区中删除该键。如果没有可用的密钥,它将等到一个可用,然后 return 从缓冲区中删除该密钥。
_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 来确定
AL
和 AH
中的信息是否有效。
- 数字 1Bh (ESC) 是一个 ASCII 代码,必须从
AL
开始检查,但所有其他代码 48h (UP)、50h (DOWN)、4Bh (LEFT) 和 4Dh (RIGHT) ) 是扫描码,因此必须从 AH
. 进行检查
我正在用程序集 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
您正在使用 int 16h,1。 如你所见here,特殊键(如箭头)有一个名为扫描码的值,扫描码在啊中返回。尝试
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 下打印一些东西)
您的 _KEYCHECK 函数正在使用 BIOS.ReadKeyboardStatus 函数。
如果没有键可用,它会通过设置 ZeroFlag (ZF) 通知您键盘键的可用性,或者如果键正在等待,则通过清除 ZeroFlag 来通知您键盘键的可用性。在后一种情况下,您还将收到密钥的 ASCII 码和扫描码。
这里重要的是报告可用的键保留在键盘缓冲区中。您在 AL
和 AH
中获得的信息只是预览而不是实际密钥(在某种意义上)。这解释了您的观察结果:
... but if any other key was pressed before that the controls frees ...
解决办法是从键盘缓冲区中删除键。这就是 BIOS.ReadKeyboardCharacter 所做的。如果一个键正在等待,它会很快 return 并从缓冲区中删除该键。如果没有可用的密钥,它将等到一个可用,然后 return 从缓冲区中删除该密钥。
_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 来确定
AL
和AH
中的信息是否有效。 - 数字 1Bh (ESC) 是一个 ASCII 代码,必须从
AL
开始检查,但所有其他代码 48h (UP)、50h (DOWN)、4Bh (LEFT) 和 4Dh (RIGHT) ) 是扫描码,因此必须从AH
. 进行检查