 # 让西伯利亚 T7 GT 拿起即切耳机,放回即切音响 我用的是带充电底座的西伯利亚 T7 GT。平时用音响,玩游戏时戴耳机,总要手动切换 Windows 的播放设备。于是想做一个小功能:拿起耳机自动切到耳机,放回底座自动切回音响。 真正需要解决的问题,是电脑怎么知道耳机被拿起来了。 最先想到的是监听设备连接和断开,但实测发现,耳机放回底座后,Windows 里的音频设备依然在线。电脑看到的是持续连接的 USB 设备,不能直接用它是否存在来判断耳机的位置。 继续检查后,发现这台耳机除了 USB 音频接口,还提供了厂商自定义的 HID 接口。HID 常见于鼠标、键盘,也可以用来传输设备自定义的数据。这里不需要安装额外驱动,Windows 自带的 HID 驱动就能读取报告。 接下来就是对比数据:先让耳机保持在底座上,再分别拿起、放回,记录收到的 HID 报告。这里踩了一个坑:只观察动作瞬间,会把某个变化的字节误认成位置状态。最初的判断会在拿起约 10 秒后错误切回音响,直到保持耳机离开底座持续采样,才发现同一个值也出现在周期报告里。 重新将拿起、放回各保持至少 30 秒后,找到了更可靠的对应关系:状态报告长度为 64 字节,前缀是 `55 10 01 0B 01`,用第 8 个字节,也就是从 0 开始的偏移 `7` 的最高位 `0x80`,判断充电标志。 | 实际状态 | 报告片段(偏移 6、7) | 对应操作 | | ---------------------- | --------------------- | ------------ | | 刚拿起耳机 | `28 64` | 切换到耳机 | | 保持离开底座,周期上报 | `36 64` | 保持耳机输出 | | 放回底座充电 | `36 E4` | 切换到音响 | 判断逻辑可以简化为: ```python def parse_state(report: bytes) -> str | None: # 只处理本机实测过的状态报告,忽略其他数据。 if len(report) != 64 or not report.startswith(bytes.fromhex("55 10 01 0B 01")): return None if report[6] not in (0x28, 0x36): return None return "speakers" if report[7] & 0x80 else "headset" ``` 这套映射来自本机实测,用充电标志推断底座状态,不是通用的 HID 标准,也没有厂商协议文档保证其他型号、固件或充电方式使用相同含义。换一款耳机,需要重新采样验证。 识别出状态后,剩下的就是切换音频。我用 Python 的 `ctypes` 调用 Windows 原生接口:通过 Core Audio 获取播放设备,通过 PolicyConfig 接口设置默认播放设备。脚本只切换默认播放和多媒体播放角色,保留原有的通信播放设备与麦克风设置。PolicyConfig 并非公开稳定的接口,换 Windows 版本时仍需测试兼容性。 整个过程就是:**监听 HID 报告 → 识别拿起或放回 → 状态改变时切换播放设备**。重复的状态不反复切换,未知数据直接忽略,USB 断开后等待重连。 为了让重启后也能恢复输出,我又在脚本目录加入了 `headset_state.json`。每次确认新的耳机状态,就把它保存到文件;启动时读取上次记录,恢复对应的播放设备。写入采用临时文件加原子替换,避免异常退出时直接破坏原记录。 实测拿起、放回时,Windows 的默认播放设备和实际声音输出都会跟着切换,进程重启也能恢复记录对应的设备。不过,保存的是历史状态:关机期间移动耳机,仍要等下一次有效事件来修正;首次没有记录时,也需一次拿起或放回。游戏如果固定选择了某个输出设备,需要改成使用系统默认设备。 Loading...  # 让西伯利亚 T7 GT 拿起即切耳机,放回即切音响 我用的是带充电底座的西伯利亚 T7 GT。平时用音响,玩游戏时戴耳机,总要手动切换 Windows 的播放设备。于是想做一个小功能:拿起耳机自动切到耳机,放回底座自动切回音响。 真正需要解决的问题,是电脑怎么知道耳机被拿起来了。 最先想到的是监听设备连接和断开,但实测发现,耳机放回底座后,Windows 里的音频设备依然在线。电脑看到的是持续连接的 USB 设备,不能直接用它是否存在来判断耳机的位置。 继续检查后,发现这台耳机除了 USB 音频接口,还提供了厂商自定义的 HID 接口。HID 常见于鼠标、键盘,也可以用来传输设备自定义的数据。这里不需要安装额外驱动,Windows 自带的 HID 驱动就能读取报告。 接下来就是对比数据:先让耳机保持在底座上,再分别拿起、放回,记录收到的 HID 报告。这里踩了一个坑:只观察动作瞬间,会把某个变化的字节误认成位置状态。最初的判断会在拿起约 10 秒后错误切回音响,直到保持耳机离开底座持续采样,才发现同一个值也出现在周期报告里。 重新将拿起、放回各保持至少 30 秒后,找到了更可靠的对应关系:状态报告长度为 64 字节,前缀是 `55 10 01 0B 01`,用第 8 个字节,也就是从 0 开始的偏移 `7` 的最高位 `0x80`,判断充电标志。 | 实际状态 | 报告片段(偏移 6、7) | 对应操作 | | ---------------------- | --------------------- | ------------ | | 刚拿起耳机 | `28 64` | 切换到耳机 | | 保持离开底座,周期上报 | `36 64` | 保持耳机输出 | | 放回底座充电 | `36 E4` | 切换到音响 | 判断逻辑可以简化为: ```python def parse_state(report: bytes) -> str | None: # 只处理本机实测过的状态报告,忽略其他数据。 if len(report) != 64 or not report.startswith(bytes.fromhex("55 10 01 0B 01")): return None if report[6] not in (0x28, 0x36): return None return "speakers" if report[7] & 0x80 else "headset" ``` 这套映射来自本机实测,用充电标志推断底座状态,不是通用的 HID 标准,也没有厂商协议文档保证其他型号、固件或充电方式使用相同含义。换一款耳机,需要重新采样验证。 识别出状态后,剩下的就是切换音频。我用 Python 的 `ctypes` 调用 Windows 原生接口:通过 Core Audio 获取播放设备,通过 PolicyConfig 接口设置默认播放设备。脚本只切换默认播放和多媒体播放角色,保留原有的通信播放设备与麦克风设置。PolicyConfig 并非公开稳定的接口,换 Windows 版本时仍需测试兼容性。 整个过程就是:**监听 HID 报告 → 识别拿起或放回 → 状态改变时切换播放设备**。重复的状态不反复切换,未知数据直接忽略,USB 断开后等待重连。 为了让重启后也能恢复输出,我又在脚本目录加入了 `headset_state.json`。每次确认新的耳机状态,就把它保存到文件;启动时读取上次记录,恢复对应的播放设备。写入采用临时文件加原子替换,避免异常退出时直接破坏原记录。 实测拿起、放回时,Windows 的默认播放设备和实际声音输出都会跟着切换,进程重启也能恢复记录对应的设备。不过,保存的是历史状态:关机期间移动耳机,仍要等下一次有效事件来修正;首次没有记录时,也需一次拿起或放回。游戏如果固定选择了某个输出设备,需要改成使用系统默认设备。 最后修改:2026 年 10 月 18 日 © 允许规范转载 打赏 赞赏作者 赞 1 如果觉得我的文章对你有用,请随意赞赏