前言

最近因为有移动办公的需求,买了个ATK的无线机械键盘(感叹机械键盘市场真卷,200不到的键盘做的比我一年半之前花将近2000买的好)。选ATK一个很重要的点就是他们有支持Linux的网页面板驱动。

到手之后有线连接,打开浏览器,提示只支持Chrimium内核的浏览器。正常,Chromium提供的开发接口确实比Firefox多。

切到Chromium,点击新增设备,左上角弹出的窗口中选中ATK键盘,确定。随后我就傻眼了:在屏幕中间显示的键盘是正确的,但是状态是“休眠”,无法进行设置。

原因

网上搜索了一通,发现我想要说的前人们都说过了有人已经踩过坑了:

Linux 下配置udev来实现chrome对于蜻蜓R1鼠标的访问

按照里面的修改USB/HID设备权限部分临时测试了一下,发现确实是设备权限的问题,修改为可写之后就能正常使用了,于是准备用里面提供的方法来将配置持久化。然而,进行到添加当前用户到plugdev组这一步时,我发现我当前的ArchLinux并没有plugdev这个组。抱着怀疑的心态查了一下ArchWiki,果然发现有问题:

OWNER、GROUP 和 MODE udev 值可用于提供访问权限,但会遇到如何使设备对所有用户可用而不使用过于宽松的模式的问题。Ubuntu 的方法是创建一个 plugdev 组,并将设备添加到该组中,但这种做法不仅不被 systemd 开发者推荐,而且在 Arch 的 udev 规则中被视为错误(FS#35602),并且从 systemd 258 开始已损坏。

(这次我查的ArchWiki是archlinux.org.cn,因为archlinuxcn.org的这一部分没有汉化。)

非systemd用户,或者systemd-logind被禁用的情况下此方法无效。

原帖作者用的是基于Arch衍生的Manjaro,采取的却是这种不被建议的做法,因此我认为有必要予以纠正。

适用于Arch系Linux的方法

对于 systemd 系统,现代推荐的方法是使用 MODE 660 来允许组使用设备,然后附加一个名为 uaccess 的 TAG。这个特殊的标签会使 udev 将一个动态用户ACL应用到设备节点上,该节点与 systemd-logind(8) 协调,以便让已登录用户可以使用该设备。有关实现此目的的 udev 规则示例,请参见:

1
ACTION!="remove", SUBSYSTEMS=="usb", ATTRS{idVendor}=="vendor_id", ATTRS{idProduct}=="product_id", MODE="0660", TAG+="uaccess"

为了使任何添加 uaccess 标签的规则生效,其定义所在文件的名称必须在字典顺序上先于 /usr/lib/udev/rules.d/73-seat-late.rules。简单而言,.rules文件开头的数字必须是小于73的两位数(建议为71或70)。

Wiki提供的配置和我们的目标大差不差,只需要将里面的vendor_id和product_id(均为字符串)改为ATK设备对应的即可。这两个参数可以通过lsusb命令来获取。

1
2
3
$ lsusb
# 命令输出中应当有你的ATK USB设备,格式大致如下:
Bus 004 Device 011: ID 576f:112e HFD ATK A87Pro

ID后面以冒号分隔的两段十六进制字符串,前者是vendor_id,后者是product_id。因此,最终的配置文件大致如下。记得把vendor_id和product_id都替换成你实际设备的对应信息,文件名也是。

1
ACTION!="remove", KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="vendor_id", ATTRS{idProduct}=="product_id", MODE="0660", TAG+="uaccess"

在最终的配置文件中,我们添加了KERNEL和SUBSYSTEM两个额外匹配条件,这样可以避免匹配到别的什么设备上。

立即生效:

1
sudo udevadm control --reload-rules && sudo udevadm trigger

至此,就可以在开机后直接使用ATK网页驱动了。

Wine客户端?

有人可能会尝试使用wine来运行ATK HUB客户端,直接连接到键盘,但是我实际测试之后发现不行。Windows和Linux的USB设备API是截然不同的,Wine没有向应用程序暴露HID接口,更没有尝试模拟Windows的USB设备API,而这正是ATK HUB识别和操作设备的基础。因此,ATK HUB会直接找不到任何ATK设备。

为任意设备添加uaccess标签

当你有很多设备需要放开该权限时,逐个为设备添加这个规则就太繁琐了。幸好,我们有一个方法能够在几乎不损害任何安全性的情况下放开所有设备的hidraw权限。

1
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", TAG+="uaccess"

此处取消了上文的ID限制,表示为允许当前物理机登录的桌面用户访问所有hidraw子系统的设备。这些设备还包括支持hidraw的蓝牙设备,实测罗技的无线鼠标也能正常识别。

安全性与工作原理

关于为什么这种方式仍然能够保证安全性,ArchWiki讲的可能不够直白。

udev规则的唯一作用是,给符合上述规则的设备打一个标签,内容是uaccess。systemd-logind在用户触发会话更改(例如,从登录界面进入桌面)时,扫描了所有的udev设备。如果设备有uaccess这个标签,那么检查会话属性是否完全满足下列要求:

  • Class == user:这只有在桌面用户已经登录的情况下才会符合。如果在登录界面,值则是greeter;锁屏时是lock-screen(注意不同的DE/WM可能会有不同的锁屏行为);对于后台会话是background。
  • Remote == no:排除了ssh会话。
  • State == active:在几个虚拟终端(指VT或tty,不包括pty)之间切换时,logind会自动将移出的那个VT会话设置为inactive。

这共同保证了,只有严格满足“本地桌面环境/VT用户已登录且未锁屏”的条件,该用户才会被logind通过ACL授予权限。