惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Help Net Security
MyScale Blog
MyScale Blog
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
小众软件
小众软件
大猫的无限游戏
大猫的无限游戏
Martin Fowler
Martin Fowler
Vercel News
Vercel News
S
SegmentFault 最新的问题
M
MIT News - Artificial intelligence
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
云风的 BLOG
云风的 BLOG

依云's Blog

Wayfire支持不缩放Xwayland啦 - 依云's Blog 使用wayvnc远程访问无头Wayfire会话 - 依云's Blog pacfiles: 高速的 pacman -F 替代品 用 Android 手机当电脑的话筒 - 依云's Blog 使用 ffmpeg 对音频文件进行响度归一化 - 依云's Blog 使用 nftables 屏蔽大量 IP - 依云's Blog YubiKey 初体验 - 依云's Blog fcitx5 码表同步方案 - 依云's Blog 我正在使用的火狐扩展(2024年版) - 依云's Blog 使用 PipeWire 实现自动应用均衡器 如果你发现你的 OOM Killer 在乱杀进程 使用 atuin 管理 shell 命令历史 btrfs 元数据满了怎么办 btrfs 翻车记 在 nspawn 里运行 docker Linux 上的字体配置与故障排除 新的 PaddleOCR 部署方案 使用 EasyEffects 调整 Bose 音箱的体验 让离线软件真正离线 我所讨厌的网页行为 tmux 状态栏优化 Google Chrome 中的字体设置 从 getmail6 到 offlineimap 微信消息通知的困扰 Qt 的字体渲染问题 Wayfire 迁移进展(四):不那么 high 的 DPI Wayfire 迁移进展(二):Xwayland HiDPI 以及 waybar Wayfire 迁移进展 不同情况下的图形效果 Wayland 初体验
倾听蓝牙耳机的按键事件
依云 · 2021-08-26 · via 依云's Blog

缘起

我的蓝牙耳机有简单的多媒体按键:上一曲、下一曲、播放、暂停。这几个按键在 Android 手机上是开箱即用的,然而在 Arch Linux 上,尤其是我的 Awesome 桌面环境上,并不那么自动。

其实按键事件都能收到的啦。可以收到 XF86AudioPrev, XF86AudioNext, XF86AudioPlay, XF86AudioPause 这么几个按键。给它们绑定热键,去调用 MPRIS 就好了。我使用的是 playerctl 工具。mpv 的 MPRIS 支持用的是 mpv-mpris。火狐自动就支持了,不用做什么。

看起来这样就好了?我也以为如此,直到我离电脑远了一些……

问题

躺在床上玩手机时也可以用电脑听歌啦~你问我为什么不用手机听歌?因为我的电脑没有 NFC 功能,耳机切到手机碰一下就可以了,可是切到电脑上是要打命令抢连接的!所以就不切来切去啦,反正手机上的曲库和电脑上是同步的。

可是!耳机多媒体按键怎么不管用了呢?我瞟了一眼电脑,哦,它怎么屏幕还亮起来了?反复几次之后,我终于搞明白了——锁屏的时候按键事件全被锁屏软件给挡下来啦……

那怎么办呢?

我有看到 acpid 那边也收到了些事件,比如「cd/prev / CDPREV」和「cd/next / CDNEXT」。但是不是很稳定,时有时无,也没看到播放和暂停。再加上从作为系统服务的 acpid 将指令传到用户会话比较麻烦,就放弃了。

后来想到,既然能收到按键事件,那么应当有个输入设备在。xinput 看了一下,果然有个「WH-1000XM2 (AVRCP)」,用 evtest 在 /dev/input/ 也能找到对应的设备文件。那直接读这个设备文件不就好了?

解决

好是好,但是没权限啊。不过像/dev/video*之类的文件就有权限,是 systemd 拿 udev 规则给加上的。我之前也给 i2c 设备加过权限,只是那次是直接 chmod 了,这次想试试更优雅的方案——uaccess tag。

这个 uaccess tag 是 systemd 用来给当前会话的用户设备权限的,切换用户会话的时候权限会自动变化。不过没有文档 QAQ,所以只好自己研究了。最终的结果是这样:

SUBSYSTEM=="input", ATTRS{name}=="WH-1000XM2 (AVRCP)", TAG+="uaccess"

这个规则的序号需要小于70,不然赶不上处理 uaccess 的逻辑。sudo udevadm control --reload-rules 然后再 sudo udevadm trigger,就可以看到对应的 /dev/input/event* 文件上已经有 ACL 给我的用户权限了。不过多了写权限,问题不大。

然后就可以开始愉快地找设备文件、读取事件啦。我用 Rust 写的,日常练习嘛,顺便用用前不久看到的 eyre 和 tracing。有个 input-linux 库,不用自己拿 libc 调用 ioctl、定义 C 结构体了。不过这个库不支持从按键名到按键枚举值的转换,所以我 fork 了一下。蓝牙耳机说来来、说走走,所以 inotify 也是少不了的啦。然后还用 toml 整了个配置文件,好放出来给有需要的人用~

啊对了,程序里一上来就把对应的输入设备用 xinput 给禁用了。这样桌面环境就不会收到事件,不会唤醒屏幕,也不会有重复操作了。(不过它退出的时候并没有把设备重新启用,懒~)

代码