源码:PaperStrike/HeadsetControlsPC
本人是一名新晋大学生,自从有了电脑,电脑开着 B 站手机刷消息就成为了本人闲时的挚爱。为了不影响舍友 / 家人的学习生活,受制于自己的经济能力,本人一直戴着有线耳机,并在躺着看电影时发现了这样一个恐怖的事情:
没有一家笔记本支持 3.5mm 有线耳机线控!
好吧可能还是有的,反正在本人的搜索中并没有找到。仅仅搜到有几个型号的台式机,支持中间的那个暂停 / 继续键。这有什么用? 不能调音量,不能调下一曲,而且,又不是我的台式机!😡 于是求助于在搜索关键词中添加万能的程序员专用字眼:github
,发现了这篇文章:
Hacking in Android headset button support for Windows | Christian Barth Roligheten
Perfect,同志们!里边详细介绍了帅哥 Christian Barth Roligheten 为自己的 PC 添加 暂停 / 继续 按键支持的过程,结合了详细的 Python 源码并提供了仓库链接(roligheten/AndroidMediaControlsWindows)。本人在 Roligheten 研究声道图的基础上进一步分析,在即将放弃希望之际,偶然中找到了分辨三个不同按键的方法。
原理
3.5mm TRRS 接口的有线耳机的麦克风与按钮并联,按钮按下时麦克风被短接,安卓设备通过检测电压差可以知道按下的按钮。
图中各按钮常见的对应功能如下:
按键 | 介绍 |
---|---|
A | 暂停 / 继续 |
B | 增加音量 |
C | 减少音量 |
D | Pixel 上唤起语音助手 |
多数 PC 设备无法获知电压差,但短接对麦克风两个声道产生的影响(虽然不知道为什么,但)有规律可循。这里本人从 sounddevice 的例子库中选择并轻修了一个 plot_input.py
,用于实时输出麦克风声道一的波形(橙线 Channel 1
)和两声道差值(蓝线 diff
,Channel 2
- Channel 1
)的波形,演示。
横轴表示时间,单位为毫秒(ms),纵轴表示声音的变化。
数据在不同设备上可能有所不同,另外,演示中排除了轻按的情况。
无声音时,两条波均呈现为一条直线。而极端噪声环境下,Channel 1
震动剧烈,diff
保持稳定:
短按按钮时,处于安静环境(0-1000ms)和处于噪声环境(1300-4000ms)的两条波呈现的变化中,有规律的至少有:
#1
:diff
在按下瞬间增长至 0.06(±0.05) 并持续 40(±30)ms,在松开瞬间下降。#2
:Channel 1
在按下瞬间,下降并保持在 -0.6 以下 100(±30)ms,经 30(±20)ms 增长至 0.45 以上并保持 230(±60)ms,经 30(±20)ms 下降至 -0.40(±0.05) 以下。
#3
:在另外的试验中注意到,按钮保持按下时,两条波几乎不受环境声音影响(,应该是短接的原因)。
短按(0-800ms)和长按(850-2400ms)时,两条波在上述规律基础上又呈现出了不同变化:
#4
:diff
在长按过程中在 -0.17-0.17 范围内随机波动,在长按松开瞬间再次拉升,后下降,详细见图,不再赘述。#5
:Channel 1
在长按过程中保持在 -0.30(±0.05) 以上,在长按松开瞬间再次拉升,后下降至 -0.40(±0.05) 以下,详细见图。
放大到纵轴 0.1 范围内,观察 diff
的变化。注意到不同按钮的按下瞬间 diff
呈的波动幅度有所不同:
#6
:按钮 A 按下瞬间(700-900ms)diff
波动峰值在 0.075 以上,按钮 B(1700-1900ms)为 0.025-0.075,按钮 C(3000-3200ms)为 0.016-0.025。
有兴趣的同志可以自己下载编辑 plot_input.py
,试验。
目前,项目使用 #1 && #2
条件判断按下,#5
条件判断松开,#6
条件判断不同按钮。
判断条件已经被本人换了好几次 以扩大适应的设备范围,但因为只有一台笔记本和一条耳机随我调用,不兼容我也没多少办法。你愿意当我的工具人吗?
安装,有兴趣吗?
以下两种方式都需要联网,会自动安装依赖包 keyboard
,numpy
和 sounddevice
。
PyPI
通过 PyPI 安装:
pip install trrsheadset
Clone
或者, 从 这里 下载在 GitHub 仓库中的压缩包,解压到一个记得住位置的地方。
这种安装方式目前有一个 bug(PIP doesn't read setup.cfg in UTF-8, which causes UnicodeDecodeError · Issue #8931 · pypa/pip),安装前需要根据你使用的命令行环境设置环境变量
PYTHONUTF8=1
:
- PowerShell:
$env:PYTHONUTF8=1
- Shell:
export PYTHONUTF8=1
- CMD:
set PYTHONUTF8=1
定位到解压文件夹中运行:
pip install .
然后,就可以把解压文件夹删掉。
使用
插入耳机后,在命令行中使用 Python 启动 trrsheadset
即可:
python -m trrsheadset [参数]
- 可以使用两种方式,一种是直接关闭命令行,一种是按下
ctrl+break
快捷键强制退出。- 选用
pythonw
启动可在命令行关闭后保持运行,可在任务管理器中找到Python 3.x (Windowed)
关闭。
重插耳机需要重新启动。
可选参数
-l
or --log
将运行日志保存至文件
--use-hotkey
开启键盘快捷键,见后文介绍
-h
or --help
输出此列表后退出
按键
耳机按键映射 & 键盘快捷键响应。基于 Python 库 keyboard 。
耳机
按键 | 短按 | 长按 | 双击 |
---|---|---|---|
A | 继续 / 暂停 | 继续 / 暂停 | 静音 / 取消静音 |
B | 音量+ | 下一首 | / |
C | 音量- | 上一首 | / |
D | / | / | / |
双击操作处于早期开发阶段
键盘
需在启动时使用 --use-hotkey
参数。
基础快捷键 ctrl+shift+h
,在基础快捷键触发后 1s 内按下以下按键可以触发相应操作:
p
暂停或继续
e
退出
!部分设备在开启上述快捷键后,检测不到右 shift、右 ctrl 的释放动作,此时可以按击键盘左边对应按键恢复。因此,此功能在默认情况下关闭。
注意哦
- 不要按得太快,招架不住。
- 有问题欢迎评论,也可以在 GitHub 提 issue 或进入讨论区(Discussions)交流。
- 如果放久后按钮辨别老错,可能是太久不放音乐了电压不高(?存疑,讨论欢迎)
- 感谢 Christian Barth Roligheten 大哥 👍
抓取日志
添加参数 -l
或 --log
启动可将运行时日志保存到运行时文件夹的 debug.log.1
和 debug.log
日志文件中。日志文件对定位 BUG 非常有帮助。
python run.py -l
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。