记录一次修复Linux下键盘网页驱动能识别却连不上的问题(迈从K99 V2)
tl;dr
简单来说及时手里的迈从K99 V2这个键盘在Windows上用网页驱动一切正常,换到Linux后,键盘没啥问题,但是在web driver中无法连接到键盘。浏览器弹窗能列出接收器,但选中设备后页面就一直转圈。
最后发现:接收器的配置接口默认只允许root访问,普通用户跑的Chrome没有权限访问。加一条udev规则,给当前桌面用户放行该接口的读写权限就可以了。
其他用WebHID的键盘、鼠标如果遇到类似现象,也能用如下的方案修复。
注:只适用于2.4g usb dongle或者usb直连的键盘,如果用蓝牙的不行
排查过程
先看一下看看设备的硬件 ID:
lsusb
我这边看到的是:
Bus 001 Device 002: ID 41e4:2001 Compx MCHOSE 2.4G Wireless
其中 41e4 是厂商 ID(VID),2001 是产品 ID(PID)。不同的键盘会有不同的值且不同的连接方案拿到的值也不一样,所以实际操作的时候以你为准
然后检查hidraw节点的USB属性:
for device_node in /dev/hidraw*; do
[ -e "$device_node" ] || continue
printf '\n%s\n' "$device_node"
udevadm info --query=property --name="$device_node" |
grep -E '^(ID_VENDOR_ID|ID_MODEL_ID|ID_MODEL|ID_USB_INTERFACE_NUM)='
done
可以发现,我的接收器对应了两个节点,分别是
| 设备节点 | USB 接口编号 | 用途(猜测) |
|---|---|---|
/dev/hidraw0 | 00 | 普通键盘输入接口 |
/dev/hidraw1 | 01 | 包含厂商配置通道 |
/dev/hidraw0
ID_MODEL=MCHOSE_2.4G_Wireless
ID_MODEL_ID=2001
ID_VENDOR_ID=41e4
ID_USB_INTERFACE_NUM=00
/dev/hidraw1
ID_MODEL=MCHOSE_2.4G_Wireless
ID_MODEL_ID=2001
ID_VENDOR_ID=41e4
ID_USB_INTERFACE_NUM=01
查看/sys/class/hidraw/hidraw1/device/report_descriptor,可以发现其中包含厂商自定义用途页0xff02字节 06 02 ff),并同时声明了输入和O输出,所以推测接口01就是用做配置的接口
python3 - <<'PY'
from pathlib import Path
for name in ('hidraw0', 'hidraw1'):
path = Path('/sys/class/hidraw') / name / 'device/report_descriptor'
print(name)
print(path.read_bytes().hex(' '))
PY
部分内容如下
| 描述符字节 | HID 项目 | 含义 |
|---|---|---|
06 02 ff | Usage Page | 用途页为 0xff02,属于厂商自定义范围;数值按小端序存储 |
09 02 81 00 | Usage + Input | 声明设备向电脑发送的 Input Report |
09 02 91 00 | Usage + Output | 声明电脑向设备发送的 Output Report |
接下来查看权限
# 查看基础权限和 ACL
ls -l /dev/hidraw1
getfacl -p /dev/hidraw1
00:35:39 $ ls -l /dev/hidraw1
getfacl -p /dev/hidraw1
crw-rw----+ 1 root root 240, 1 Oct 20 00:08 /dev/hidraw1
# file: /dev/hidraw1
# owner: root
# group: root
user::rw-
# 如果你没有权限,下面这一行应该是没有的
user:aynakeya:rw-
group::---
mask::rw-
other::---
你也可以通过这段代码检查自己有没有权限,如果没有权限应该会爆出PermissionError,如果出现这个错误,那么基本就是权限问题了
python3 - <<'PY'
import os
device_node = '/dev/hidraw1' # 替换为刚才确认的节点
fd = os.open(device_node, os.O_RDWR | os.O_NONBLOCK)
os.close(fd)
print('当前用户可以读写打开该接口')
PY
添加udev规则修复
创建或者编辑一个udev文件,你可以写在一起也可以分开写,其中41e4,2001啥的替换成你自己的id
/etc/udev/rules.d/70-webhid-keyboard.rules
这条规则会匹配该VID下面的所有hidraw接口,如果你不确定哪个interface是配置接口的话。
ACTION!="remove", SUBSYSTEM=="hidraw", KERNEL=="hidraw*", ATTRS{idVendor}=="41e4", ATTRS{idProduct}=="2001", TAG+="uaccess"
如果你知道,可以把interface也给加上。
ACTION!="remove", SUBSYSTEM=="hidraw", KERNEL=="hidraw*", ATTRS{idVendor}=="41e4", ATTRS{idProduct}=="2001", ENV{ID_USB_INTERFACE_NUM}=="01", TAG+="uaccess"
保存之后,重载一下udev,然后你就可以正常连接了,理论上不需要重新插拔usb
sudo udevadm control --reload-rules
Reference
- Linux Kernel HIDRAW - Raw HID Device Interface
- Chrome for Developers: Access HID devices on the Web (Dev Tips)
- MDN Web Docs: WebHID API
- systemd source: udev-builtin-uaccess.c
- freedesktop.org: udev — Dynamic device management
- systemd rules: 73-seat-late.rules.in
- udev Rules Matching Keys (ATTRS hierarchy)
- Flatpak Documentation: Sandbox Permissions
- Chrome WebHID Security and Privacy