【实用工具】Win32API-使用低级键盘钩子屏蔽 NumLock 按键
在使用键盘进行大量文字输入工作时,经常会不小心按到 NumLock 按键(尤其是在笔记本电脑上,Backspace 离它太近了),带来了不小的麻烦。
本次编写的小工具可以帮助你临时禁用 NumLock 按键。
实现原理
实际上就是使用注册一个低级键盘钩子,来监听按键事件。
1 | HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0); |
其中,回调处理函数 LowLevelKeyboardProc
如下:
1 | LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) |
大致流程如下:
通过检查
wParam
的值,判断当前按键事件是哪一类(普通按键按下、普通按键弹起、系统按键按下、系统按键弹起)对于特定类型的事件进行处理。这里是捕获了
WM_KEYDOWN
和WM_SYSKEYDOWN
这两种,对“按键按下”的事件进行处理。在处理过程中,检查
p->vkCode
的值(键码)以确定被按下的是哪个按键。如果发现了需要屏蔽的目标键码,就将
fEatKeystroke
标志设置为TRUE
,否则设为FALSE
。在退出回调函数前,检查
fEatKeystroke
标志。如果为
TRUE
,说明此次按键的触发需要被屏蔽,我们就可以通过return 1
把这个消息截断,实现按键屏蔽;否则我们
return CallNextHookEx
,把消息继续传递,从而使此次按键事件能够被操作系统和其它程序继续处理。
这个函数中,下面这段代码是程序的关键,修改时一定要谨慎。
注释掉某一个 case
,或者是在某个 case
下添加了一个 break;
,都会让程序的行为有很大变化。
1 | switch (wParam) |
此外,为了使程序运行时 hook 钩子保持,在 main
函数中可以使用这样的结构:
1 | // Keep this app running until we're told to stop |
一旦获取到用户中止等信号,while 循环就能退出,同时执行
UnhookWindowsHookEx
。
(对于这一点我还是有点疑惑的,循环一退出是不是就开始执行
_exit
了,而不执行
Unhook?或者说,操作系统在进程结束后会自动执行
Unhook?当然,如果要捕获这些 SIGNAL,在程序退出前再进行一下 Unhook
的操作,使用一个叫 SetConsoleCtrlHandler
的函数也能解决。)
开发环境配置
这次试着使用了 CLion 开发环境,配合 MSVC Build Tools。环境配置过程中有些小坑,也一并记录一下。
要想顺利构建,需要进行如下配置:
- 打开
文件 - 设置 - 构建、执行、部署 - CMake
,添加几个配置文件,但要注意设置工具链为 “Visual Studio 20xx”,设置生成器为 ”Visual Studio 1x 20xx”。 - 默认编译出来的是64位程序,如果要编译 "x86"
目标,可以在配置文件这个页面中的 “CMake 选项” 追加填写
-A "Win32"
源码地址 & 二进制文件下载
链接:Github or Gitee
在相应的 Release
页面就可以下载构建好的可执行程序了。
其它的一些使用事项在上述源码页面中有说明。
2022.11.22 补充说明
突然发现,有时使用键盘钩子的方式,虽然能成功 Hook,键盘上 NumLock 的指示灯也不熄灭,但系统中, NumLock 按键还是被关闭了。
故又写了个无限循环版本,监测按键状态,如果被关闭则程序模拟点击,将 NumLock 开启。
代码也在上述仓库中,名为 loop_ver.c
。同时,在 Release
页面也有构建好的二进制文件。
如需隐藏窗口,将 ShowWindow(cmd_hwnd, SW_MINIMIZE);
改为
ShowWindow(cmd_hwnd, SW_HIDE);
然后再 Build。