如何获取特定时刻按住的按键?怎样检查单个按键按压状态?
嘿,我完全懂你的需求——要实时掌握所有正在按住的按键状态,还得能单独查某个键是按下去还是抬起来,关键是程序不能卡在等待输入的循环里,得一直跑对吧?之前用int 16h和in al, 60h踩了多键识别的坑,那咱们来聊聊靠谱的解决办法。
如果你是在纯DOS环境写汇编,int 16h确实没法处理多键同时按住的情况,因为它只能读取键盘缓冲区里的单个按键。但in al, 60h这个端口读取方法其实是能搞定多键的,只是你需要自己维护一个按键状态数组来跟踪每个键的通码/断码:
核心思路
键盘控制器会通过端口60h发送两种扫描码:
- 通码:值小于
80h,表示某个按键被按下 - 断码:值等于对应通码加
80h,表示某个按键被松开
你可以创建一个大小为256的数组key_state,每个元素对应一个扫描码的状态(1表示按住,0表示抬起)。然后在程序的主循环里,定期检查键盘控制器状态端口64h(第0位为1时表示60h端口有数据),读取扫描码并更新数组。
示例代码
; 定义按键状态数组,初始全为0 key_state db 256 dup(0) main_loop: ; 检查键盘控制器是否有数据待读取 in al, 64h test al, 01h jz skip_key_process ; 没数据就跳过处理,继续执行程序其他逻辑 ; 读取扫描码 in al, 60h mov bl, al ; 判断是按下还是松开 test bl, 80h jnz key_released ; 按键按下:标记状态为1 mov byte ptr [key_state + bx], 1 jmp skip_key_process key_released: ; 按键松开:去掉断码的80h标记,标记状态为0 and bl, 7Fh mov byte ptr [key_state + bx], 0 skip_key_process: ; 这里写你程序的核心逻辑,比如绘图、计算等 ; ... jmp main_loop ; 循环执行,保持程序持续运行
检查特定按键状态
比如要查A键,它的扫描码是1Eh,直接读取数组对应位置即可:
; 检查A键是否按住 mov al, [key_state + 1Eh] test al, 1 jz a_key_up ; 这里写A键按住时的逻辑 jmp check_done a_key_up: ; 这里写A键抬起时的逻辑 check_done:
如果是在Windows环境开发,不管是用C/C++还是汇编,直接调用系统API会更简单,不用自己处理端口和扫描码。GetAsyncKeyState函数就是专门干这个的:
核心用法
GetAsyncKeyState接收一个虚拟键码参数(比如VK_A代表A键,'A'也可以),返回值的**最高位(第15位)**为1时,表示该按键当前正被按住;为0则表示已抬起。而且这个函数不会阻塞程序,完全符合你“持续运行”的需求。
C语言示例代码
#include <windows.h> #include <stdio.h> int main() { while (1) { // 检查A键的状态 if (GetAsyncKeyState('A') & 0x8000) { printf("A键正在按住\n"); } else { printf("A键已抬起\n"); } // 检查Shift键的状态(虚拟键码VK_SHIFT) if (GetAsyncKeyState(VK_SHIFT) & 0x8000) { printf("Shift键正在按住\n"); } Sleep(100); // 加个小延迟,避免占用过多CPU } return 0; }
批量获取所有按键状态
如果要一次性获取所有按键的状态,可以循环遍历所有虚拟键码(0到255),逐个调用GetAsyncKeyState检查,把状态存在数组里就行,逻辑和DOS下的状态数组类似,但不用处理底层端口了。
内容的提问来源于stack exchange,提问作者yaya1711




