从未知扫描码到有用按键:在 Linux (NixOS) 上映射神秘按键
你是否遇到过这种情况:你的键盘上有一个按键(尤其是笔记本电脑上的特殊功能键),但无论你怎么按,系统都毫无反应?标准的按键测试工具,如 evtest
或 wev
,似乎也完全忽略了它的存在。这可能令人沮丧,但别担心,通常有办法解决!
最近我就遇到了这样的问题(小米笔记本上的”小爱”键),通过一系列步骤成功让这个“沉默”的按键恢复了功能。
症状
evtest
sudo evtest /dev/input/by-path/platform-i8042-serio-0-event-kbd
1 |
|
wev
毫无反应
倾听内核的声音 (dmesg
)
当一个按键按下后系统没有明显反应时,底层的内核驱动可能已经注意到了什么。检查内核环形缓冲区日志是我们的首要任务。打开终端,输入:
1 |
|
或者,如果你使用 systemd journal:
1 |
|
然后,按下那个没有反应的按键。如果幸运的话,你可能会看到类似下面的信息(这正是我当时看到的):
1 |
|
atkbd serio0
: 表明这是来自 AT/PS2 键盘驱动(atkbd
)在主键盘端口(serio0
)的信息。Unknown key pressed/released
: 内核驱动收到了按键按下和释放的信号,但它不认识这个信号代表哪个键。code 0xf2
: 这是硬件发送的原始**扫描码 (scancode)**。Use 'setkeycodes e072 <keycode>' to make it known.
: 这是关键线索!内核直接告诉我们,这个未知的按键对应的扫描码是e072
(0xf2
经过处理后的形式),并且我们可以使用setkeycodes
命令来给它分配一个 Linux 内核**键码 (keycode)**。
Scancode & Keycode & Keysym
扫描码 (Scancode)
最底层、最原始的信号,由你的键盘硬件直接产生。当你按下或松开一个键时,键盘会发送一个或多个代表该物理按键位置或动作(按下/松开)的数字代码。这个代码是硬件相关的,不同的键盘型号对于同一个物理按键可能发送不同的扫描码。内核的底层键盘驱动程序首先接收并处理这些原始扫描码。
用sudo showkey -s
可以观测
键码 (Keycode)
内核键盘驱动接收到原始的扫描码后,会查询一个内部映射表,将其翻译成一个标准的、数字形式的键码。键码是 Linux 内核用来识别一个特定 物理按键 的抽象标识符,与该按键当前的功能或字符无关(例如,它代表“空格键这个物理按键”,而不是“空格字符”)。这个键码层级相对稳定,不直接受键盘布局影响,是 setkeycodes 命令操作的对象,也是 evtest 工具显示的代码。
用sudo evtest /dev/input/eventX
可以观测
内核头文件: include/uapi/linux/input-event-codes.h
按键符号 (Keysym)
最高层级的表示,代表按键的实际 含义 或 功能。图形环境中的 XKB 系统(或类似系统)接收来自内核的键码,然后根据当前选择的键盘布局(如美式、法式)以及是否按下了 Shift、Ctrl、Alt 等修饰键,将键码翻译成一个按键符号。
wev
观测
选择一个合适的键码
我们需要为扫描码 e072
选择一个目标键码。这个键码决定了系统将如何“看待”这个按键。为了避免与现有功能冲突,并方便后续自定义,最好选择一个相对“空闲”或“特殊”的键码。
以下是一些不错的选择:
- 可编程/通用功能键:
KEY_PROG1
(键码 148),KEY_PROG2
(149),KEY_PROG3
(202) 等。这些键码设计上就是用于用户自定义的。 - 扩展功能键:
KEY_F13
(键码 183) 到KEY_F24
(194)。大多数键盘没有这些物理按键,因此它们的键码通常是空闲的。
笔者使用了 KEY_PROG1
(148) 。
临时映射与测试
现在,我们可以使用内核提示的 setkeycodes
命令进行临时映射。打开终端,执行(这里以映射到 KEY_PROG1
为例):
1 |
|
映射完成后,我们需要验证它是否生效。使用 evtest
监控你的键盘设备(你需要先找到键盘对应的 eventX 设备,通常路径中包含 kbd):
1 |
|
现在按下那个之前无效的按键。如果一切顺利,你应该能在 evtest
的输出中看到类似这样的事件:
1 |
|
这表明内核现在已经能够识别这个按键了!
永久化设置 (NixOS)
setkeycodes
命令的效果是临时的,重启后就会失效。我们需要将这个设置固化到 NixOS 的配置中。有两种主要方法:
使用 udev 规则
这是健壮的方式,它会在系统检测到你的键盘时自动应用设置。编辑你的 /etc/nixos/configuration.nix
文件:
1 |
|
${pkgs.kbd}/bin/setkeycodes
使用 Nix 管理的setkeycodes
程序路径。
rebuild switch
以后记得 重启电脑。
最终验证
重启后,再次使用 evtest
检查那个特殊按键,确认它依然能够被正确识别为你映射的键码。
使用你的新按键!
现在,这个按键在内核层面已经被赋予了生命(一个键码)。接下来,XKB 系统(无论在 Xorg 还是 Wayland 下)会根据你的键盘布局将这个内核键码翻译成一个**按键符号 (Keysym)**,例如 F13
或 XF86Launch1
。
由于应用/WM(Hyprland)读取的是Keysym
,可以使用 xev
(Xorg) 或 wev
(Wayland) 来查看按下这个键时产生的具体 Keysym
。
1 |
|