GetKeyState()和GetAsynKeyState()的差异
书籍:《Visual C++ 2017从入门到精通》的2.4.2 MFC应用程序类型
环境:visual studio 2022
内容:【例2.40】通过按键消息显示用户按键的键值
说明:以下内容大部分来自腾讯元宝
GetKeyState() 和 GetAsyncKeyState() 是 Windows API 中用于检测按键状态的常用函数,其核心差异如下:
1. 工作机制
-
GetKeyState()
适用场景:需要在消息处理逻辑中同步获取按键状态(如响应快捷键)。
基于 消息队列 获取按键状态,仅反映 最后一次键盘消息处理时的按键状态。例如,在WM_KEYDOWN
消息处理函数中调用时,它返回生成该消息时的按键状态。 -
GetAsyncKeyState()
适用场景:需要实时检测按键(如游戏循环、后台监控)。
直接查询 硬件硬件中断 实时获取按键状态,不受消息队列影响。无论程序是否处于消息处理阶段,调用时立即返回当前按键状态。
2. 返回值结构
-
GetKeyState()
判断按键按下:
返回SHORT
类型(16位),最高位(第15位) 表示按键是否被按下(1=按下,0=抬起),最低位(第0位) 表示按键是否被触发(如 Caps Lock 灯状态)。if (GetKeyState(VK_CONTROL) & 0x8000) // 最高位为1表示按下
-
GetAsyncKeyState()
判断按键按下:
返回SHORT
类型,最高位 表示当前按键是否被按下,最低位 表示自上次调用后是否被触发过(1=触发过)。if (GetAsyncKeyState(VK_SPACE) & 0x8000) // 最高位为1表示按下
3. 使用限制与性能
-
GetKeyState()
- 只能在消息处理函数中使用,否则无法获取有效状态。
- 性能较高,适合频繁调用(如每帧检测)。
- 潜在陷阱:若在循环中直接使用(如
while(GetKeyState(...))
),可能导致死循环。
-
GetAsyncKeyState()
- 无消息队列依赖,可在任意位置调用。
- 性能较低,频繁调用可能影响性能。
- 物理按键检测:不受键盘映射影响(如
VK_LBUTTON
始终检测鼠标左键)。
4. 典型场景对比
场景 | 推荐函数 | 示例代码 |
---|---|---|
响应快捷键(如 Ctrl+S) | GetKeyState() | if (GetKeyState(VK_CONTROL) & 0x8000 && nChar == 'S') |
游戏循环实时检测按键 | GetAsyncKeyState() | if (GetAsyncKeyState(VK_SPACE) & 0x8000) |
检测物理按键状态(如外接键盘) | GetAsyncKeyState() | if (GetAsyncKeyState(VK_NUMPAD0) & 0x8000) |
5. 注意事项
- 组合键处理:
使用 GetKeyState() 时,需确保组合键(如 Ctrl+Alt+Delete)在消息队列中同时触发。 - 多线程环境:
GetAsyncKeyState() 可跨线程检测按键,但需注意焦点窗口问题(若其他窗口拥有焦点,可能返回 0)。 - Unicode 兼容性:
两者均支持 Unicode 编码的虚拟键码(如VK_RETURN
对应回车键)。
总结
维度 | GetKeyState() | GetAsyncKeyState() |
---|---|---|
数据来源 | 消息队列 | 硬件中断 |
实时性 | 非实时(依赖消息处理) | 实时(调用即返回) |
性能 | 高 | 较低 |
适用场景 | 消息驱动的按键响应 | 需要实时检测的复杂场景(如游戏、后台监控) |
通过合理选择函数,可优化程序响应速度与逻辑准确性。若需进一步了解虚拟键码列表,可参考微软官方网页。