以下是使用 GetAsyncKeyState 实现自定义热键检测的完整方案,可以解决游戏全屏模式下热键失效的问题:
.版本 2
.支持库 shellEx
.支持库 spec
.程序集 窗口程序集_启动窗口
.程序集变量 当前键码, 整数型
.程序集变量 功能开关, 逻辑型
.子程序 __启动窗口_创建完毕
时钟1.时钟周期 = 50 ' 每50ms检测一次按键
.子程序 _编辑框1_按下某键, 逻辑型
.参数 键代码, 整数型
.参数 功能键状态, 整数型
' 记录用户按下的键码(排除功能键)
.如果真 (键代码 ≠ #Ctrl键 且 键代码 ≠ #Alt键 且 键代码 ≠ #Shift键)
当前键码 = 键代码
编辑框1.内容 = 取键名 (键代码)
.如果真结束
返回 (假) ' 禁止默认处理
.子程序 取键名, 文本型
.参数 键代码, 整数型
.判断开始 (键代码 = #F1键)
返回 ("F1")
.判断 (键代码 = #F2键)
返回 ("F2")
' ... 其他功能键省略
.判断 (键代码 = #A键)
返回 ("A")
.判断 (键代码 = #B键)
返回 ("B")
' ... 其他字母键省略
.默认
返回 ("[" + 到文本 (键代码) + "]")
.判断结束
.子程序 _时钟1_周期事件
.如果真 (当前键码 = 0)
返回 ()
.如果真结束
' 使用API检测按键状态
.如果真 (GetAsyncKeyState (当前键码) ≠ 0)
.如果真 (功能开关 = 假)
功能开关 = 真
调试输出 ("功能开启")
' 这里执行你的功能代码
.如果真结束
.否则
.如果真 (功能开关)
功能开关 = 假
调试输出 ("功能关闭")
.如果真结束
.如果真结束
' ====== API声明 ======
.DLL命令 GetAsyncKeyState, 整数型, "user32.dll", "GetAsyncKeyState"
.参数 键码, 整数型
方案说明
-
实现原理:
- 使用
GetAsyncKeyState API实时检测按键状态(即使窗口失去焦点)
- 通过时钟周期性地检查按键状态
- 用户只需在编辑框按下想要的键即可完成绑定
-
优势:
- ✅ 全屏游戏下可用
- ✅ 无需注册热键,避免冲突
- ✅ 支持组合键检测(需额外处理)
-
扩展组合键支持:
如果需要支持Ctrl/Alt/Shift 组合键,修改时钟事件:
.子程序 _时钟1_周期事件
.局部变量 组合键按下, 逻辑型
' 检测组合键状态
组合键按下 = (GetAsyncKeyState (#Ctrl键) ≠ 0 或 (GetAsyncKeyState (#Alt键) ≠ 0 或 (GetAsyncKeyState (#Shift键) ≠ 0
.如果真 (当前键码 ≠ 0 且 (GetAsyncKeyState (当前键码) ≠ 0) 且 组合键按下 = 假)
' 触发功能...
.如果真结束
-
键码对照表: |
易语言常量 |
实际键位 |
#F1键 |
F1 |
#A键 |
A |
#空格键 |
空格 |
#Esc键 |
ESC |
用户操作流程
- 点击编辑框
- 按下想要绑定的按键(如F12)
- 程序自动显示键名并开始检测
- 在游戏/其他程序中按下该键即可触发功能
注意事项
-
如果仍无效,尝试:
- 降低时钟周期(如20ms)
- 检查杀毒软件拦截
- 游戏是否屏蔽了普通按键(某些游戏只响应DirectInput)
-
更完善的实现可以参考:
' 在_时钟1_周期事件中加入防抖处理
.如果真 (取启动时间 () - 上次触发时间 > 200) ' 200ms内不重复触发
上次触发时间 = 取启动时间 ()
' 执行功能...
.如果真结束
如果需要处理更复杂的游戏输入场景,可以考虑使用DirectX 或Raw Input 方案。
|