一个蛋疼的场景
你打开一个 FPS 游戏,按住 Ctrl 蹲下,同时按下 Space 准备跳起来爆头。结果——输入法切换出来了,游戏里的角色纹丝不动。
更烦人的是,不只是 Ctrl+Space。Ctrl+Shift 切输入法、Win+Space 切输入法、Alt+Tab… 这些 Windows 系统快捷键在游戏里一个比一个碍事。
市面上不是没有拦截工具,但绝大多数都一个粗暴逻辑:检测到快捷键,直接 return 1 把按键吞掉。输入法是不切了,但游戏也收不到按键了——按住 Ctrl 的时候按 Space,游戏根本不认为你按了跳跃。
这就很离谱:我要的是输入法别切,不是游戏也别收到。
解决思路
ShortcutBlocker 的做法分两层:
- 阻断系统层:用 Windows 全局低级键盘钩子(
WH_KEYBOARD_LL)在按键到达 IME 之前拦截,return 1让 IME 完全不知道这个按键的存在 - 透传应用层:用
PostMessage把按键消息直接塞进游戏窗口的消息队列,不走系统键盘管道,IME 碰不到,游戏的消息循环能正常收到
为什么不用 SendInput?
第一次实现我试了 SendInput 重新注入按键,但这条路走不通:
SendInput注入的事件还是会走系统键盘管道,而 Ctrl 是物理按下的,系统又把它当成Ctrl+Space交给 IME 处理了- 部分游戏不认
SendInput注入的事件
改用 PostMessage 之后,消息直接投递到目标窗口的队列里,绕过了整个系统输入管道,IME 完全没有机会劫持。
功能概览
两种阻断模式
- 所有快捷键模式:拦截一切
Ctrl/Alt/Win + 任意键的组合 - 自定义模式:只拦截你指定的组合,支持黑名单(Block)和白名单(Allow)
录制快捷键
点击录制按钮,按下任意组合键(比如 Ctrl+Shift+F1),自动添加到列表。每条记录可以切换 Block(阻断)和 Allow(放行)类型。
全局白名单
即使在全阻断模式下,白名单里的快捷键也能正常通过。比如你希望 Ctrl+C 复制在任何情况下都能用,加到白名单就行。
实时日志
窗口右侧有实时日志面板,记录每一次阻断、放行和模式切换,支持按类型筛选和导出为文本文件。
动态岛通知
状态变更时(开启/关闭阻断),窗口顶部滑入一个浮层提示,2 秒后自动消失。
系统托盘
点关闭按钮不会退出程序,而是最小化到系统托盘,右键菜单可以快速开关阻断或完全退出。
中英文界面
一键切换语言,English / 中文。
使用方法
从 GitHub Releases 下载 ShortcutBlocker.exe,直接运行:
1 | 1. 运行 ShortcutBlocker.exe |
如果需要自定义规则,点击 [REC] 录制快捷键,或者直接编辑 %TEMP%\ShortcutBlocker\shortcuts.cfg。
技术实现
关键代码在 LowLevelKeyboardProc 这个钩子回调里:
1 | if (IsKeyBlocked(vkCode, ctrl, alt, sh, win)) |
对于 keyup 也是同样的处理,保证游戏收到一对平衡的 keydown + keyup。
这种方案有一个局限:依赖窗口消息队列的游戏能完美工作;使用 Raw Input 或 DirectInput 的游戏,还需要看它们的输入循环实现。好在大多数主流游戏引擎(Unity、Unreal)同时监听从消息队列和 Raw Input,PostMessage 的 keydown/keyup 足以触发跳跃判定。
写在最后
这个工具本身很小,一个 cpp 文件编译出来不到 600KB,但解决的是一个特别具体又特别烦人的痛点——系统快捷键和游戏操作的冲突。
如果你也遇到过类似的问题,欢迎到 GitHub 下载试用,提 issue 或 PR。
说些什么吧!