<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>无线麦 on 我的博客</title><link>https://blog.5616760.com/tags/%E6%97%A0%E7%BA%BF%E9%BA%A6/</link><description>Recent content in 无线麦 on 我的博客</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Thu, 08 Oct 2026 17:00:00 +0800</lastBuildDate><atom:link href="https://blog.5616760.com/tags/%E6%97%A0%E7%BA%BF%E9%BA%A6/index.xml" rel="self" type="application/rss+xml"/><item><title>无线麦：把蓝牙遥控器改造成 Windows 的按键与语音入口——一座 BLE/HID/音频三链合流的本地桥</title><link>https://blog.5616760.com/0038.html</link><pubDate>Thu, 08 Oct 2026 17:00:00 +0800</pubDate><guid>https://blog.5616760.com/0038.html</guid><description>&lt;p&gt;电视遥控器是天然的「远距离输入设备」：拿在手里、按一下就有反馈、不需要桌子。但把它接到电脑上用，很快就撞到现实——Windows 会把一部分按键当成 HID 键盘收下，另一部分直接在键盘栈里丢掉；而遥控器上的麦克风，走的是 BLE 上一条叫 ATVV 的私有通道，Windows 根本不会把它暴露成一个普通麦克风。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;code&gt;windows-remote-mic-app&lt;/code&gt;（无线麦 Win 版）想做的就是把这个断层补上：让米家蓝牙语音遥控器 2 Pro 和谷歌 Chromecast 遥控器，同时成为 Windows 的按键外设和语音入口。&lt;/strong&gt; 它是 GPL-3.0-only 的开源项目，Python + PySide6/QML 实现，发布形式是免安装 ZIP，无需安装器。&lt;/p&gt;&#10;&lt;p&gt;这篇不写安装教程，而是把它&lt;strong&gt;拆开看&lt;/strong&gt;：为什么它必须是「一座桥」而不是「一个映射器」、Frida 到底拦在了哪里、音频是怎么从遥控器一路走到输入法的、以及那套近乎苛刻的验证与隐私边界是怎么设计的。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;数据说明&lt;/strong&gt;：本文信息来自项目 GitHub 仓库（&lt;code&gt;ZSTDJan/windows-remote-mic-app&lt;/code&gt;）的 README、架构台账（&lt;code&gt;WINDOWS-ARCHITECTURE-LEDGER.md&lt;/code&gt;）、性能记录、验证规则与 &lt;code&gt;bugs/&lt;/code&gt;、&lt;code&gt;CHANGELOG.md&lt;/code&gt;，数据快照时间为 &lt;strong&gt;2026-10-08&lt;/strong&gt;。项目仍在快速迭代（当前正式版 &lt;code&gt;1.0.87&lt;/code&gt;，约 51 次提交、48 star），具体行为请以你所用版本与仓库最新文档为准。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="目录"&gt;目录&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%b8%80%e5%ae%83%e5%88%b0%e5%ba%95%e6%98%af%e4%bb%80%e4%b9%88" &gt;它到底是什么&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%ba%8c%e4%b8%ba%e4%bb%80%e4%b9%88%e5%bf%85%e9%a1%bb%e6%98%af%e5%ba%a7%e6%a1%a5" &gt;为什么必须是「一座桥」&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%b8%89%e8%bf%90%e8%a1%8c%e6%8b%93%e6%89%91%e4%b8%a4%e6%9d%a1%e7%8b%ac%e7%ab%8b%e6%95%b0%e6%8d%ae%e9%93%be%e7%9a%84%e6%b1%87%e5%90%88" &gt;运行拓扑：两条独立数据链的汇合&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%9b%9b%e6%8c%89%e9%94%ae%e9%93%be%e4%bb%8e-hid-%e5%88%b0-wudfhost-%e6%8b%a6%e6%88%aa" &gt;按键链：从 HID 到 WUDFHost 拦截&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%ba%94%e8%af%ad%e9%9f%b3%e9%93%beatvvadpcm-%e4%b8%8e%e8%99%9a%e6%8b%9f%e5%a3%b0%e5%8d%a1" &gt;语音链：ATVV、ADPCM 与虚拟声卡&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%85%ad%e6%8c%89%e4%bd%8f%e8%af%b4%e8%af%9d%e7%9a%84%e7%8a%b6%e6%80%81%e6%9c%ba%e5%a5%91%e7%ba%a6" &gt;按住说话的状态机契约&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%b8%8313-%e9%94%ae%e8%b7%a8%e6%9d%a5%e6%ba%90%e5%8e%bb%e9%87%8d%e5%90%8c%e4%b8%80%e6%ac%a1%e6%8c%89%e4%b8%8b%e5%8f%aa%e8%83%bd%e6%98%af%e4%b8%80%e6%ac%a1%e5%8a%a8%e4%bd%9c" &gt;13 键跨来源去重：同一次按下只能是一次动作&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%85%ab%e8%b7%a8%e5%b9%b3%e5%8f%b0%e9%80%82%e9%85%8d%e5%b0%8f%e7%b1%b3-a-%e6%ac%be%e4%b8%8e%e8%b0%b7%e6%ad%8c-ab-%e6%ac%be" &gt;跨平台适配：小米 A 款与谷歌 A/B 款&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%b9%9d%e5%85%83%e7%b4%a0%e5%af%bc%e8%88%aaorthofocus-%e4%b8%8e%e6%ad%a3%e4%ba%a4%e9%a2%86%e5%9c%b0%e7%bd%91%e6%a0%bc" &gt;元素导航：OrthoFocus 与正交领地网格&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%8d%81%e6%80%a7%e8%83%bd%e5%b7%a5%e7%a8%8b%e5%85%88%e8%af%81%e6%98%8e%e7%93%b6%e9%a2%88%e5%86%8d%e6%94%b9%e4%bb%a3%e7%a0%81" &gt;性能工程：先证明瓶颈，再改代码&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%8d%81%e4%b8%80%e9%85%8d%e7%bd%ae%e6%97%a5%e5%bf%97%e4%b8%8e%e9%9a%90%e7%a7%81%e8%be%b9%e7%95%8c" &gt;配置、日志与隐私边界&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%8d%81%e4%ba%8c%e9%aa%8c%e8%af%81%e5%88%86%e7%ba%a71920-%e9%a1%b9%e6%b5%8b%e8%af%95%e8%83%bd%e8%af%81%e6%98%8e%e4%bb%80%e4%b9%88" &gt;验证分级：1920 项测试能证明什么&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%8d%81%e4%b8%89%e6%88%90%e7%86%9f%e5%ba%a6%e8%af%84%e4%bc%b0%e4%b8%8e%e9%80%82%e7%94%a8%e5%9c%ba%e6%99%af" &gt;成熟度评估与适用场景&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%8d%81%e5%9b%9b%e7%bb%93%e8%af%ad" &gt;结语&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;img alt="图：小米蓝牙语音遥控器 2 Pro（RC003）实物" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.5616760.com/img/0038-001.png"&gt;&lt;/p&gt;&#10;&lt;h2 id="一它到底是什么"&gt;一、它到底是什么&#10;&lt;/h2&gt;&lt;p&gt;一句话定义：&lt;strong&gt;无线麦是一个运行在 Windows 上的本地桥接程序，把蓝牙语音遥控器的实体按键转成 Windows 快捷键与动作，同时把遥控器的麦克风转成输入法可用的虚拟麦克风。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;它要用户接受的产品形态很朴素——设置窗口 + 通知区域图标：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;给遥控器的 13 个实体按键配置&lt;strong&gt;单击 / 双击 / 长按&lt;/strong&gt;三种手势，动作可以是方向、确认、音量、组合快捷键、鼠标操作，或触发 Quicker 动作；&lt;/li&gt;&#10;&lt;li&gt;按住遥控器的话筒键说话，文字通过&lt;strong&gt;搜狗、微信、豆包输入法&lt;/strong&gt;上屏；&lt;/li&gt;&#10;&lt;li&gt;关掉设置窗口只是隐藏到通知区域，桥接服务继续跑；真正退出要从托盘选「完全退出」。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;img alt="图：无线麦设置界面的四个主要页面" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.5616760.com/img/0038-003.jpg"&gt;&lt;/p&gt;&#10;&lt;p&gt;它支持的遥控器有两类，定位差别明显：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;遥控器&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;参考价&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;语音能力&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;语音模式&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;小米蓝牙语音遥控器 2 Pro（RC003）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;约 65–99 元，Type-C 充电&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;有固件限制&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;仅&lt;strong&gt;按住型&lt;/strong&gt;，单次约 60 秒内&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;谷歌 TV Chromecast 遥控器（图示款）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;约 15 元&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;无限制&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;按住型 &lt;strong&gt;+ 开关型&lt;/strong&gt;，可超 60 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;作者特别提醒：谷歌遥控器版本很多，购买时务必比对电池仓内的型号差异，否则可能买来用不了；图示款仅为型号参考，无利益关联。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="二为什么必须是一座桥"&gt;二、为什么必须是「一座桥」&#10;&lt;/h2&gt;&lt;p&gt;理解这个项目，关键是要理解它&lt;strong&gt;面对的不是一个技术问题，而是三个&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR&#10; subgraph P["问题：遥控器与 Windows 之间的断层"]&#10; direction TB&#10; A1["① 按键断层&lt;br/&gt;部分 HID usage&lt;br/&gt;在键盘栈中被丢弃"] &#10; A2["② 语音断层&lt;br/&gt;ATVV 私有音频流&lt;br/&gt;Windows 不暴露为麦克风"]&#10; A3["③ 注入断层&lt;br/&gt;Windows 没有&lt;br/&gt;可用的遥距输入来源"]&#10; end&lt;/pre&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;按键断层&lt;/strong&gt;：Windows 键盘栈会丢掉&lt;strong&gt;返回、音量加、音量减&lt;/strong&gt;等部分 usage，这些键映射不出来；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;语音断层&lt;/strong&gt;：遥控器麦克风走 BLE GATT 上的 ATVV 服务，Windows 不会把它变成一个录音设备；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;注入断层&lt;/strong&gt;：即使拿到了按键和音频，也要把它们变成宿主（输入法）能识别的快捷键与音频端点。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;任何只解决一个问题的方案都会失败。这也是项目文档里反复强调的一句话：&lt;strong&gt;这不是简单的「快捷键映射器」，而是一座同时连接 BLE 语音、HID 按键、Windows 输入注入和音频端点的本地桥。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;与之对应的，项目明确划出了&lt;strong&gt;四条非目标&lt;/strong&gt;（这在一人主导的开源项目里很少见，但对读者判断边界非常有价值）：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;不推倒重写已经存在的 BLE、ATVV、Raw Input、Frida、SendInput 和音频链；&lt;/li&gt;&#10;&lt;li&gt;不把 Quicker 变成核心依赖，也不做双向深度集成；&lt;/li&gt;&#10;&lt;li&gt;不自动改变系统默认音频设备，&lt;strong&gt;不静默提权、不安装驱动、不绕过安全软件&lt;/strong&gt;；&lt;/li&gt;&#10;&lt;li&gt;不把未签名候选或自动测试的结果描述成「发布验收通过」。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="三运行拓扑两条独立数据链的汇合"&gt;三、运行拓扑：两条独立数据链的汇合&#10;&lt;/h2&gt;&lt;p&gt;整个系统的数据流，可以用一张图讲清楚。注意这里有&lt;strong&gt;两条相互独立&lt;/strong&gt;的链，只在解析为语音动作时汇合：&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB&#10; RC["RC003 / 谷歌遥控器"]&#10; RC --&gt;|"BLE GATT / ATVV"| ATVV["ATVV 语音链"]&#10; RC --&gt;|"Windows HID 键盘栈 → Raw Input"| RAW["Raw Input 按键链"]&#10; RC --&gt;|"HidOverGatt → WUDFHost + Gadget"| TAP["HID tap 按键链"]&#10;&#10; ATVV --&gt; APP["RemoteMicRC003.exe&lt;br/&gt;桌面主进程"]&#10; RAW --&gt; APP&#10; TAP --&gt; APP&#10;&#10; APP --&gt;|"按键动作"| SI["SendInput / 应用启动"]&#10; APP --&gt;|"ADPCM → PCM"| PA["PortAudio"]&#10; PA --&gt; CAB["CABLE Input"]&#10; CAB --&gt; VB["VB-CABLE 虚拟声卡"]&#10; VB --&gt; HOST["宿主输入法&lt;br/&gt;搜狗 / 微信 / 豆包"]&lt;/pre&gt;&lt;p&gt;图上有一个容易被忽略的细节：&lt;strong&gt;实体话筒键的按下，可能同时从 ATVV、Windows F5、Raw Input 和 HID tap 四条路径到达&lt;/strong&gt;。四条路径报的是同一个物理动作，但程序必须把它&lt;strong&gt;合并成一次动作&lt;/strong&gt;——否则用户按一下话筒键，会同时触发语音和一次按键映射，或者干脆触发两次。&lt;/p&gt;&#10;&lt;p&gt;这就是第 7 节要讲的去重问题，也是整个项目里最难缠的一类 bug。&lt;/p&gt;&#10;&lt;p&gt;再看进程模型。整个程序只有一个用户入口 &lt;code&gt;RemoteMicRC003.exe&lt;/code&gt;，靠参数切换角色；另有一个&lt;strong&gt;只供安装器与权限修复调用&lt;/strong&gt;的窄职责助手 &lt;code&gt;RemoteMicRC003HidHelper.exe&lt;/code&gt;，藏在 &lt;code&gt;_internal&lt;/code&gt; 目录里，不作为用户入口暴露：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;入口&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;角色&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;是否长期持有硬件&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;无参数 / &lt;code&gt;--settings&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Qt Quick 桌面主程序&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;是（窗口、托盘、桥接 worker）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;--background&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;隐藏启动同一个主程序&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;同上&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;--request-exit&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;隐藏的维护入口，只写一次性退出请求&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;否&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;--rc003-hid-injector&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;受限注入子进程&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;短暂持有目标进程句柄&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HID 助手 &lt;code&gt;--inject&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;计划任务按需启动的管理员注入&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;短暂持有已核验的 WUDFHost 句柄&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;「桥接 worker 不是一个独立进程」&lt;/strong&gt;，这一点很关键：它是桌面主进程内的一条工作线程，持有 BLE、按键和音频资源。单实例靠 per-session Windows named mutex 保证——重复双击只恢复已有窗口，绝不会再开一套 &lt;code&gt;BLE + Raw Input + HID + 音频&lt;/code&gt; 竞争同一份硬件。&lt;/p&gt;&#10;&lt;h2 id="四按键链从-hid-到-wudfhost-拦截"&gt;四、按键链：从 HID 到 WUDFHost 拦截&#10;&lt;/h2&gt;&lt;p&gt;这是全项目技术含量最高的一段。要理解它，先要理解一个「双层报告」问题：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;同一个按键，可能被 HID tap 和 Windows 原生键盘路径同时上报。&lt;/strong&gt; 如果两条路径都继续传播，用户就会同时得到「原生字符/功能」和「自定义映射动作」——表现为按键被触发两次，或者输入框里莫名出现一段日期时间。&lt;/p&gt;&#10;&lt;p&gt;项目的正式解法不再依赖「通用低层键盘钩子」（那看不到设备身份），而是把拦截点&lt;strong&gt;下沉到已核验的 RC003 宿主进程内部&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB&#10; K["内核已完成 UMDF 输出缓冲区复制"] --&gt; E["Frida Gadget onEnter&lt;br/&gt;NtDeviceIoControlFile"]&#10; E --&gt; M{"精确匹配报告特征？&lt;br/&gt;IOCTL 0x80018483&lt;br/&gt;8 字节元数据&lt;br/&gt;operation=2 / selector=1&lt;br/&gt;9 字节报告"}&#10; M --&gt;|"是"| C["保存原始报告&lt;br/&gt;清空 usage"]&#10; M --&gt;|"否"| SKIP["放行，不干预"]&#10; C --&gt; R{"调用成功返回？"}&#10; R --&gt;|"是"| PY["交给 Python&lt;br/&gt;手势去重 → 映射 → 动作"]&#10; R --&gt;|"否"| RB["恢复源缓冲区&lt;br/&gt;且不派发该报告"]&lt;/pre&gt;&lt;p&gt;几个设计要点值得单独拎出来：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;① 拦截必须发生在 &lt;code&gt;onEnter&lt;/code&gt;，不能是 &lt;code&gt;onLeave&lt;/code&gt;。&lt;/strong&gt; 因为内核在调用返回前已经把源缓冲区复制走了；在 &lt;code&gt;onLeave&lt;/code&gt; 清空已经太晚，挡不住原始键。这是踩过坑之后才定下来的时序约束，文档里只留了一句结论。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;② 安全边界极其保守。&lt;/strong&gt; HID 助手&lt;strong&gt;不接受调用方传入的 PID、程序路径或配置路径&lt;/strong&gt;——它只从当前账号的正式配置入口读取并严格校验设备选择摘要。计划任务没有真实触发器，只能运行 Program Files 里的固定助手和固定 &lt;code&gt;--inject&lt;/code&gt; 参数。文档明确写着：助手、任务、哈希或 Gadget 连接&lt;strong&gt;任一项不符合预期，tap 就明确失败，绝不回退为未经核验的注入&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;③ 承认依赖的是非公开接口。&lt;/strong&gt; 文档原话：这个方案「依赖已经验证的 Windows 内部复制语义，不是微软承诺稳定的公开接口」。而且——&lt;strong&gt;蓝牙版本号本身不能判定兼容&lt;/strong&gt;，异机必须核对 Windows/驱动链和真实报告，不支持的指令或接口布局一律安全拒收。这种坦白在开源项目里不多见。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;④ 失败时要「补齐松键」。&lt;/strong&gt; tap 从 &lt;code&gt;READY&lt;/code&gt; 变为失联时，应用会在同一个输入仲裁锁内先取消活动手势，&lt;strong&gt;补齐所有已认领按键的松键&lt;/strong&gt;，再撤销 tap 所有权。否则最后一次按下没有对应抬起，会造成连发、半个组合键或状态卡死。&lt;/p&gt;&#10;&lt;h3 id="降级规则宁可少做不可重复做"&gt;降级规则：宁可少做，不可重复做&#10;&lt;/h3&gt;&lt;p&gt;当 tap 未能接管时，程序的策略非常明确：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;全部自定义按键映射停用，只保留 Windows 原始按键操作。&lt;/strong&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;这是「避免原始操作和自定义操作同时执行」的必然选择——功能少一半，好过行为错乱。同理，只有&lt;strong&gt;方向、退格、音量、滚轮&lt;/strong&gt;这类语义动作允许按住重复；自定义组合键无论放在哪个键上，都只执行一次完整点按。&lt;/p&gt;&#10;&lt;h2 id="五语音链atvvadpcm-与虚拟声卡"&gt;五、语音链：ATVV、ADPCM 与虚拟声卡&#10;&lt;/h2&gt;&lt;p&gt;语音链回答的是那个「断层」问题：遥控器的麦克风，怎么变成一个能被输入法读到的麦克风？&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB&#10; RC["遥控器麦克风"] --&gt;|"BLE GATT / ATVV"| TX["TX 特征：capabilities / MIC_OPEN / MIC_CLOSE"]&#10; RC --&gt;|"设备主动上报"| CTRL["CONTROL 特征：麦克风按钮&lt;br/&gt;音频开始 / 停止"]&#10; RC --&gt;|"设备主动上报"| AUD["AUDIO 特征：ADPCM 帧"]&#10; AUD --&gt; DEC["atvv_protocol 解码&lt;br/&gt;IMA / DVI ADPCM"]&#10; DEC --&gt; SES["atvv_session&lt;br/&gt;session id / decoder reset / 晚到音频保护"]&#10; SES --&gt; FIFO["64 帧有界 FIFO"]&#10; FIFO --&gt; PA["PortAudio 输出端点"]&#10; PA --&gt; CI["CABLE Input"]&#10; CI --&gt; VB["VB-CABLE"]&#10; VB --&gt; CO["CABLE Output"]&#10; CO --&gt; IME["输入法读取为麦克风"]&lt;/pre&gt;&lt;p&gt;链路上有三个设计决策直接决定了它「能不能用」：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;① 控制队列和音频队列必须分开。&lt;/strong&gt; 控制事件（比如关麦）走有界队列，音频帧走另一个有界队列。&lt;strong&gt;控制队列溢出被视为协议状态不可证明的硬错误&lt;/strong&gt;，直接停止 worker 并请求重连；而音频队列满时&lt;strong&gt;只丢最旧的音频并计数&lt;/strong&gt;——绝不能让音频洪峰把「关麦」这种控制事件挤出去。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;② &lt;code&gt;AUDIO_STOP&lt;/code&gt; 不能越过已经收到的音频。&lt;/strong&gt; 这是一个典型的顺序陷阱：如果 decoder 先关闭，那么已经收到但还没处理的尾包会被误判成「晚到数据」而丢弃，用户听到的就是&lt;strong&gt;尾音被切掉&lt;/strong&gt;。所以 &lt;code&gt;AUDIO_STOP&lt;/code&gt; 必须先排空同一连接代、序号更早的音频。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;③ 输出端点有严格的枚举规则。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;拒绝 &lt;code&gt;Windows WDM-KS&lt;/code&gt;（PortAudio 报阻塞 API 不受支持，流会在收到 PCM 前就打开失败——这是 &lt;code&gt;BUG-001&lt;/code&gt; 的真实根因）；&lt;/li&gt;&#10;&lt;li&gt;同名端点&lt;strong&gt;优先 WASAPI，其次 DirectSound&lt;/strong&gt;；&lt;/li&gt;&#10;&lt;li&gt;保存设置前先做一次真实的 &lt;code&gt;open/start/stop/close&lt;/code&gt; 预检；&lt;/li&gt;&#10;&lt;li&gt;16 kHz 单声道 PCM 按端点能力转换采样率和声道。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;至于为什么必须用 VB-CABLE 这类虚拟声卡：因为输入法要的是&lt;strong&gt;一个录音端点&lt;/strong&gt;。程序把解码后的 PCM 写到 &lt;code&gt;CABLE Input&lt;/code&gt;，虚拟声卡把它暴露成 &lt;code&gt;CABLE Output&lt;/code&gt; 供输入法读取。&lt;strong&gt;方向不能互换&lt;/strong&gt;——写错一侧就是「气泡弹出但没有声音」。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;关键约束：软件&lt;strong&gt;不会静默安装驱动&lt;/strong&gt;。设置页只能在用户明确确认后，启动随包、哈希校验通过的厂商安装程序。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="六按住说话的状态机契约"&gt;六、按住说话的状态机契约&#10;&lt;/h2&gt;&lt;p&gt;「按住说话」看着简单，实际上是整个项目里状态最多、边界最锋利的一块。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;voice_controller.py&lt;/code&gt; 的职责边界被切得很干净：&lt;strong&gt;它只决定实体按住状态，不直接操作 Windows。&lt;/strong&gt; 话筒键按下产生逻辑 key-down，物理松手产生逻辑 key-up；如果 Windows 没有提供松手边沿，则由设备的 &lt;code&gt;AUDIO_STOP&lt;/code&gt; 作为同一个结束边沿的兜底。&lt;/p&gt;&#10;&lt;p&gt;真正复杂的是 &lt;code&gt;app.py&lt;/code&gt; 里那条&lt;strong&gt;强制顺序&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;sequenceDiagram&#10; participant User as 用户&#10; participant Dev as 遥控器&#10; participant App as app.py 状态机&#10; participant Host as 宿主输入法&#10;&#10; User-&gt;&gt;Dev: 按下话筒键&#10; Dev-&gt;&gt;App: 四路来源（ATVV/F5/RawInput/HID tap）&#10; App-&gt;&gt;App: ① 验证 BLE session 存在&#10; App-&gt;&gt;App: ② 释放任何历史遗留热键&#10; App-&gt;&gt;App: ③ 打开并验证播放端点&#10; App-&gt;&gt;Host: ④ 交付语音快捷键 key-down&#10; Note over Host: 只有第 ④ 步成功后&#10; App-&gt;&gt;Dev: ⑤ 才允许发送 MIC_OPEN&#10; User-&gt;&gt;Dev: 松开话筒键&#10; Dev-&gt;&gt;App: 松手边沿 / AUDIO_STOP 兜底&#10; App-&gt;&gt;Host: 释放快捷键 key-up&lt;/pre&gt;&lt;p&gt;顺序为什么要这么严？因为&lt;strong&gt;每一条都可能失败，而失败必须可回滚&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;第 ④ 步是先给宿主快捷键。如果宿主没收到 key-down 就去开麦，遥控器开始传音但输入法没在听，录音就白录了；&lt;/li&gt;&#10;&lt;li&gt;第 ⑤ 步只有宿主 key-down 成功后才执行。这是「&lt;strong&gt;绝不产生部分会话&lt;/strong&gt;」的硬约束；&lt;/li&gt;&#10;&lt;li&gt;松手时，快捷键释放失败只保留&lt;strong&gt;一个退避重试&lt;/strong&gt;；新会话开始前必须先处理旧的「欠松」。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;还有一个容易被低估的设计：&lt;strong&gt;运行时保存本次实际发送的快捷键与后端&lt;/strong&gt;。如果用户在录音中途改了设置，旧会话的 key-up 绝不能发到新的组合键上去——否则就会漏掉一个按键，或者卡住一个修饰键。&lt;/p&gt;&#10;&lt;p&gt;至于「开关型持续语音」，项目已经&lt;strong&gt;正式撤下&lt;/strong&gt;。原因是真机诊断证明：协商成功后仍收不到实体 &lt;code&gt;START_SEARCH&lt;/code&gt;，遥控器不提供点按持续语音。文档保留了完整的失败调查证据（&lt;code&gt;BUG-017&lt;/code&gt;），并把结论写进产品边界（&lt;code&gt;BUG-021&lt;/code&gt;）——这比悄悄删掉功能要诚实得多。&lt;/p&gt;&#10;&lt;h2 id="七13-键跨来源去重同一次按下只能是一次动作"&gt;七、13 键跨来源去重：同一次按下只能是一次动作&#10;&lt;/h2&gt;&lt;p&gt;回到第 3 节那个问题。实体话筒键的一次按下可能从四条路径抵达，而四条路径的&lt;strong&gt;到达顺序是不确定的&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB&#10; P["一次物理按下"] --&gt; S1["ATVV 语音事件"]&#10; P --&gt; S2["Windows F5"]&#10; P --&gt; S3["Raw Input"]&#10; P --&gt; S4["HID tap"]&#10; S1 --&gt; G["app.py 跨来源手势门闩"]&#10; S2 --&gt; G&#10; S3 --&gt; G&#10; S4 --&gt; G&#10; G --&gt; D{"有界保护期内&lt;br/&gt;折叠为一次动作"}&#10; D --&gt;|"合并成功"| A["执行：语音 或 用户映射动作"]&#10; D --&gt;|"迟到来源"| L["丢弃，不当作下一次点击"]&lt;/pre&gt;&lt;p&gt;难点在两个方向：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;来源边沿可能重叠&lt;/strong&gt;（四路几乎同时到）→ 必须折叠；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;来源边沿可能迟到&lt;/strong&gt;（首个来源已释放后才到）→ 也必须在有界保护期内折叠，&lt;strong&gt;不能误判为下一次点击&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;更隐蔽的一条：语音会话由「已识别的遥控器输入」和「ATVV 音频状态」共同仲裁——&lt;strong&gt;不能把普通实体键盘的 F5 当成遥控器语音授权&lt;/strong&gt;。来源必须成对匹配对应的按下与抬起，游离边沿一律拒绝。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;历史包袱：旧实现曾用全局 F5 钩子处理原生话筒键，结果是「桥接运行期间所有实体 F5 都被吞掉」。文档明确要求&lt;strong&gt;不能再这样描述当前合同&lt;/strong&gt;——现在只有标记过的注入边沿会被处理。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="八跨平台适配小米-a-款与谷歌-ab-款"&gt;八、跨平台适配：小米 A 款与谷歌 A/B 款&#10;&lt;/h2&gt;&lt;p&gt;谷歌 Chromecast 遥控器版本繁杂，项目为此做了相当细的兼容分层：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;层级&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;内容&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A 款（旧）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8 字节内部键码；依赖已核验的驱动布局&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A 款（新版驱动）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;按驱动文件的&lt;strong&gt;精确摘要&lt;/strong&gt;选择布局；其它摘要通过匹配的微软符号和完整构造函数前缀确认地址位置&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;B 款&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;2 字节 Consumer usage&lt;/strong&gt;，经 &lt;code&gt;remote_layout.CHROMECAST_CONSUMER_USAGES&lt;/code&gt; 转换成既有内部格式&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;B 款的适配过程很能说明「真机验证」为什么不可替代。&lt;code&gt;CHANGELOG&lt;/code&gt; 里有一串候选版本（&lt;code&gt;.75&lt;/code&gt; → &lt;code&gt;.87&lt;/code&gt;）逐版推进：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;.75&lt;/code&gt;：在 HID 宿主内做只读计数诊断，但长度字段解释有误；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;未打包修正&lt;/strong&gt;：发现驱动复制调用成功且缓冲区长度为 3 时应当读取并统计，移除了对 &lt;code&gt;IO_STATUS_BLOCK.Information&lt;/code&gt; 的错误长度要求——&lt;strong&gt;用户日志中该值一直为 0，旧实现因此根本没读到缓冲区&lt;/strong&gt;；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;.78&lt;/code&gt;：修复 B 款两字节信号被 8 字节格式限制拒绝的问题，支持 14 个已知普通按键；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;.79&lt;/code&gt;：直接语音接收改为&lt;strong&gt;按遥控器实际返回的接口识别&lt;/strong&gt;，不再要求 B 款与 A 款使用相同接口编号；&lt;/li&gt;&#10;&lt;li&gt;实测反馈：一位 B 款用户确认普通按键与微信按住说话可用。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这段历史的价值在于：&lt;strong&gt;它证明了自动检查的盲区在哪里。&lt;/strong&gt; 旧实现的单元测试全绿，但真机上那个 &lt;code&gt;Information&lt;/code&gt; 字段就是 0——测试覆盖不到真机条件，必须靠用户日志回传才能定位。&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR&#10; A["自动检查&lt;br/&gt;状态机 / 异常路径 / 隐私契约"] --&gt; B["Windows API smoke&lt;br/&gt;ctypes ABI / Raw Input"]&#10; B --&gt; C["冻结 EXE smoke&lt;br/&gt;PyInstaller 依赖完整"]&#10; C --&gt; D["真实硬件验收&lt;br/&gt;当前候选在指定机器上的事实"]&#10; D -.-&gt;|"不能外推"| E["其它机器 / 休眠 / 长期 / 杀软兼容"]&lt;/pre&gt;&lt;h2 id="九元素导航orthofocus-与正交领地网格"&gt;九、元素导航：OrthoFocus 与正交领地网格&#10;&lt;/h2&gt;&lt;p&gt;项目里还有一个可以独立使用的子项目 &lt;strong&gt;OrthoFocus&lt;/strong&gt;——它把方向键、数字键盘或遥控器方向键变成&lt;strong&gt;接近鼠标点击的界面控制方式&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;普通 XY Focus 的老毛病是：直接比较距离和角度，于是出现斜跳、跳过中间项、细小控件变孤岛，或者「按上却跑到左上角」。OrthoFocus 的做法是在距离排序&lt;strong&gt;之前&lt;/strong&gt;先加一层稳定的界面结构：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;正交领地网格&lt;/strong&gt;：领地只横向或纵向扩张，边界用水平线和竖直线切分，不生成飞地；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;软行列骨架&lt;/strong&gt;：散乱的小控件归入相近行或列，但不会被强行吸到不合理的位置；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;投射优先、领地后备&lt;/strong&gt;：正前方有目标时先经过它，缺口和不规则布局再由领地邻接补足；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;细分元素优先&lt;/strong&gt;：能识别具体按钮或输入框时，不让无意义的大窗口外壳抢占导航。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;它的操作方式很直观：&lt;code&gt;Ctrl+Alt+N&lt;/code&gt; 进入/退出导航，方向键移动选区，&lt;code&gt;Enter&lt;/code&gt; 点击（连续触发可双击），菜单键右键，音量加减滚动，&lt;code&gt;PageUp/PageDown&lt;/code&gt; 切换同位置的父级/子级元素。&lt;/p&gt;&#10;&lt;p&gt;OrthoFocus 的技术底座是 Windows &lt;strong&gt;UI Automation + MSAA + 窗口几何&lt;/strong&gt;，不依赖遥控器、蓝牙、音频或主程序。它既可作为独立 EXE 运行，也被无线麦在桌面主进程内集成——&lt;strong&gt;两种用法共享同一份导航算法&lt;/strong&gt;。项目也诚实地标注了边界：不同软件公开的 UIA/MSAA 信息并不一致，真实软件中的可达性、点击结果和长期运行仍需人工验证。&lt;/p&gt;&#10;&lt;h2 id="十性能工程先证明瓶颈再改代码"&gt;十、性能工程：先证明瓶颈，再改代码&#10;&lt;/h2&gt;&lt;p&gt;性能文档（&lt;code&gt;PERFORMANCE.md&lt;/code&gt;）给人的第一印象是&lt;strong&gt;它先反对了一种常见冲动&lt;/strong&gt;：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;当前没有证据表明程序存在持续高 CPU、无界队列、明显内存泄漏或 Python 音频计算能力不足。已确认的问题集中在「&lt;strong&gt;阻塞工作放错线程&lt;/strong&gt;」和「&lt;strong&gt;启动阶段做得过早&lt;/strong&gt;」，不是需要更换语言或把全部代码重写成原生模块。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;先看测量结果——&lt;strong&gt;Python 根本不是瓶颈&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;项目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: right"&gt;实测结果&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;判断&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;240 样本 ADPCM 解码 + 滤波 + 增益&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;中位 &lt;strong&gt;0.246 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不是瓶颈&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;PCM 统计&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;中位 &lt;strong&gt;0.053 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不是瓶颈&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;48 kHz 重采样 + 双声道转换&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;中位 &lt;strong&gt;0.077 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不是瓶颈&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;PortAudio 流打开&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;真实日志 &lt;strong&gt;67–99 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一次性成本，持续观察&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;阻塞式 &lt;code&gt;stream.write()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;常见 &lt;strong&gt;14–31 ms&lt;/strong&gt;，历史最大约 &lt;strong&gt;57 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已转入独立 worker&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;PortAudio underflow&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;已核实日志为 &lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;音频连续性良好&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;真正的问题出在&lt;strong&gt;主线程被阻塞&lt;/strong&gt;上。审计发现并修复的 6 项（4 个 P2 + 2 个 P3）：&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB&#10; subgraph BEFORE["优化前"]&#10; B1["SettingsController 构造&lt;br/&gt;同步枚举音频端点 + 检查语音程序"]&#10; B2["阻塞式 PortAudio 写&lt;br/&gt;与 BLE 控制事件共用 worker"]&#10; B3["语音快捷键操作用&lt;br/&gt;嵌套 QEventLoop 等后台线程"]&#10; B4["窗口构造时立即跑&lt;br/&gt;全部系统诊断"]&#10; B5["三个 QML 页面&lt;br/&gt;首屏一次性全构造"]&#10; end&#10; subgraph AFTER["优化后"]&#10; A1["查询转入受控后台任务"]&#10; A2["独立有界播放 worker&lt;br/&gt;+ 停止屏障"]&#10; A3["串行异步状态机"]&#10; A4["首帧提交后再启动诊断"]&#10; A5["隐藏页首次访问才构造"]&#10; end&#10; B1 --&gt; A1&#10; B2 --&gt; A2&#10; B3 --&gt; A3&#10; B4 --&gt; A4&#10; B5 --&gt; A5&lt;/pre&gt;&lt;p&gt;数字最能说明效果——首屏构造 QObject 数从&lt;strong&gt;约 1273 个降到 262 个&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;项目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: right"&gt;审计基线&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: right"&gt;优化后&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;创建 &lt;code&gt;SettingsController&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;219–234 ms&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;&lt;strong&gt;2.87–3.19 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;加载设备页首屏 &lt;code&gt;main.qml&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;133–180 ms&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;&lt;strong&gt;62.71–79.59 ms&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;首屏 QObject 数&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;约 1273 个&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;&lt;strong&gt;262 个&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一次全量系统诊断&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;约 649 ms&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;后台执行，首帧之后再启动&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;注意最后一行：诊断本身的 649 ms &lt;strong&gt;没有被消除&lt;/strong&gt;，只是从「窗口构造时同步跑」改成「首帧提交后再后台跑」。这是典型的正确优化——&lt;strong&gt;不是让它变快，而是让它别挡路&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;顺带一提，&lt;code&gt;PERF-001&lt;/code&gt; 之所以被确认为真问题而非理论风险，是因为日志里出现了实证：&lt;code&gt;AUDIO_STOP&lt;/code&gt; 前观察到 &lt;strong&gt;1–21 个&lt;/strong&gt;尾部通知积压——共享 worker 确实会被阻塞的音频写卡住。&lt;/p&gt;&#10;&lt;h2 id="十一配置日志与隐私边界"&gt;十一、配置、日志与隐私边界&#10;&lt;/h2&gt;&lt;p&gt;配置和日志统一落在 &lt;code&gt;%LOCALAPPDATA%\RemoteMic\RC003&lt;/code&gt;，结构清晰：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;路径&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;内容&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;config.json&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;设备选择、增益、重试、按住说话快捷键、输出端点&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;key_bindings.json&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;主/次手势动作、可移植物理签名映射&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;logs\app.log&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;轮转运行日志（512 KiB / 1 备份）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;bridge-runtime-status-s&amp;lt;会话 ID&amp;gt;.json&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;桥接心跳、连接与输入通道状态（每 5 秒原子更新）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;key-detection\&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最多 30 秒有效的一次性按键检测 IPC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;updates\&amp;lt;版本号&amp;gt;\&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已校验的便携 ZIP，&lt;code&gt;.part&lt;/code&gt; 只在下载未完成时存在&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;两份 JSON 都用「临时文件 + flush + fsync + os.replace」原子替换。&lt;/strong&gt; 更讲究的是 &lt;code&gt;save_settings_pair()&lt;/code&gt;：两文件一起保存时，先验证两份结构和隐私字段，如果第二份失败，就把第一份按原始字节原子恢复——不会留下「半新半旧」的混合配置。&lt;/p&gt;&#10;&lt;p&gt;文档也没有粉饰边界：普通 NTFS 文件 API &lt;strong&gt;不提供两文件共同提交的断电原子性&lt;/strong&gt;，极端断电仍不等同于数据库事务；将来若需要真正的断电事务，应引入显式 journal，而不是继续堆临时文件技巧。&lt;/p&gt;&#10;&lt;p&gt;隐私这块是全项目最硬的一条线。&lt;strong&gt;日志允许记录&lt;/strong&gt;：固定状态名、异常类型、逻辑按钮名、PCM 帧数/时长/峰值、候选数量、退出码。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;日志禁止记录&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;蓝牙地址；&lt;/li&gt;&#10;&lt;li&gt;WinRT device id、HID/设备接口路径；&lt;/li&gt;&#10;&lt;li&gt;设备 token、原始 handle/address；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;用户语音内容或识别文本&lt;/strong&gt;；&lt;/li&gt;&#10;&lt;li&gt;原生异常中可能夹带的机器本地路径。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;而且这不是靠自觉：配置层有一个&lt;strong&gt;递归隐私守卫&lt;/strong&gt;，对地址、设备 ID、设备路径、接口 ID、token 等字段大小写不敏感地拒绝；持久日志 handler 还会&lt;strong&gt;移除 traceback&lt;/strong&gt;，并把作为日志参数传入的异常替换为「异常类型」——这是第二道防线，文档强调调用点仍必须使用隐私安全字段。&lt;/p&gt;&#10;&lt;p&gt;还有一个细节值得记下来：&lt;strong&gt;设备身份只存 SHA-256 摘要&lt;/strong&gt;。&lt;code&gt;remote_selection&lt;/code&gt; 只保存已添加设备的 ContainerId 摘要、支持的 profile 和 active key，原始身份不落盘；导出日志也明确不含录音、输入正文和用户配置。&lt;/p&gt;&#10;&lt;h2 id="十二验证分级1920-项测试能证明什么"&gt;十二、验证分级：1920 项测试能证明什么&#10;&lt;/h2&gt;&lt;p&gt;项目最值得学习的可能不是代码，而是它那套&lt;strong&gt;验证分级规则&lt;/strong&gt;（&lt;code&gt;VALIDATION-AND-DELIVERY.md&lt;/code&gt;）。&lt;/p&gt;&#10;&lt;p&gt;核心原则是一句话：&lt;strong&gt;四项判断互不代替，不得从一项自动推出另一项。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR&#10; A["① 功能影响&lt;br/&gt;L1 / L2 / L3"] &#10; B["② 验证深度&lt;br/&gt;定向 / 受影响范围 / 完整"]&#10; C["③ 交付级别&lt;br/&gt;不制作产物 / 本地测试包 / 正式候选 / 正式发布"]&#10; D["④ Git 状态&lt;br/&gt;普通提交 / 检查点待实测"]&#10; A -.-&gt;|"不自动推出"| B&#10; B -.-&gt;|"不自动推出"| C&#10; C -.-&gt;|"不自动推出"| D&lt;/pre&gt;&lt;p&gt;也就是说：&lt;strong&gt;L3 不等于正式发布；完整自检不等于构建候选或 ZIP；本地 ZIP 不等于正式候选；「测试项很多、任务很长」也不构成升级交付级别的理由。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;这套规则还配了一张「证据能力表」——明确写出每一层能证明什么、&lt;strong&gt;不能&lt;/strong&gt;证明什么：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;层级&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;能证明&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;不能证明&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;unittest&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;状态机、异常路径、资源所有权、隐私/构建契约&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;真实蓝牙、驱动、输入法行为&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Windows API smoke&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ctypes ABI、Raw Input/SendInput/托盘生命周期&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;每个 usage 和长期稳定性&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;QML 离屏加载&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;QML 可创建、布局关键契约&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;用户机器显卡/缩放/主题组合&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;冻结 EXE smoke&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;PyInstaller 依赖完整、入口可运行&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;BLE/音频/权限真机成功&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;真实硬件验收&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;当前候选在指定机器上的按键和语音事实&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;其他机器、休眠、长期、杀软兼容&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;当前源码的自动化基线是：&lt;strong&gt;1920 项 unittest 通过，7 项按平台或安全条件跳过&lt;/strong&gt;，日志中无 &lt;code&gt;ResourceWarning&lt;/code&gt;、未关闭事件循环或 socket；&lt;code&gt;compileall&lt;/code&gt;、源码 &lt;code&gt;--dry-run&lt;/code&gt;、公开边界扫描（508 个文件）、&lt;code&gt;pip check&lt;/code&gt;、&lt;code&gt;git diff --check&lt;/code&gt; 均通过。&lt;/p&gt;&#10;&lt;p&gt;但文档紧接着提醒：&lt;strong&gt;这批结果只证明当前源码的自动化基线，不证明冻结 EXE、安装器、计划任务或真机链路已经通过。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;这种「自己给自己的证据降级」的写法，是一人项目里难得的工程纪律。它还体现在一条总原则上：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;引用代表所有权。&lt;/strong&gt; 线程仍活、handle 未关闭、stream 未关闭或 key-up 未确认时，对象引用不能清成 &lt;code&gt;None&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;以及一条资源规则：清理必须&lt;strong&gt;尝试所有独立步骤&lt;/strong&gt;，最后聚合失败——不能因为某一步报错就跳过其他清理，也不能在旧资源存活时开始新一代连接。&lt;/p&gt;&#10;&lt;h2 id="十三成熟度评估与适用场景"&gt;十三、成熟度评估与适用场景&#10;&lt;/h2&gt;&lt;p&gt;拉回现实层面，客观看一下它的成熟度：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;维度&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;现状&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;版本&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;正式版 &lt;strong&gt;1.0.87&lt;/strong&gt;（2026-10-03 发布），迭代节奏约 1–3 天一个候选&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;活跃度&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;约 51 次提交 / 创建于 2026-09-01，48 star、6 fork、9 个开放 issue&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;代码规模&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;单文件体量偏大（&lt;code&gt;qt_settings_app.py&lt;/code&gt; 约 437 KB，&lt;code&gt;app.py&lt;/code&gt; 约 275 KB），含大量补丁式注释&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;测试&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1920 项 unittest（含多项 ABI/契约级测试），测试代码量与源码相当&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;许可&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;GPL-3.0-only，第三方组件（PySide6/Frida/PortAudio/NumPy/VB-CABLE）分别通知&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;分发&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;免安装 ZIP，&lt;strong&gt;未签名&lt;/strong&gt;，首次运行会有 SmartScreen 提示&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;已经验证过的（截至文档时的异机结果）&lt;/strong&gt;：多候选中可选出唯一可用的 RC003、全部普通按键可在映射页识别、记事本映射有效、按住语音能得到非零 PCM 和识别文字、F5 不再向输入框泄漏日期时间。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;仍待真机验证的&lt;/strong&gt;：方向键单次触发与长按复测、HID 失联补松、HOLD 短流尾音、断连重连、休眠恢复、长期运行、权限与杀软兼容、以及异机差异。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;现实风险&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;程序&lt;strong&gt;未签名&lt;/strong&gt;，且公开版当前按临时说明以管理员身份运行，受管理的公司电脑可能禁止 UAC、按键组件或虚拟音频安装；&lt;/li&gt;&#10;&lt;li&gt;游戏或反作弊软件&lt;strong&gt;可能把模拟按键识别为自动化操作&lt;/strong&gt;，需按目标软件规则使用；&lt;/li&gt;&#10;&lt;li&gt;依赖 Windows 内部复制语义（非公开接口），系统更新可能影响兼容性；&lt;/li&gt;&#10;&lt;li&gt;输入法的联网、识别结果和文字润色由输入法自身决定。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;适合谁用&lt;/strong&gt;：想把客厅/投影/远距离场景下的遥控器接到 Windows、需要「躺着也能输入文字」的个人用户；能接受未签名程序、能自己处理 UAC 和虚拟声卡的动手型用户。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;不太适合&lt;/strong&gt;：企业受管设备、追求即装即用的普通用户、以及需要长期无人值守稳定运行的场景。&lt;/p&gt;&#10;&lt;h2 id="十四结语"&gt;十四、结语&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;windows-remote-mic-app&lt;/code&gt; 最打动人的地方，不是它支持了多少按键，而是它面对「三个断层叠在一起」这个复杂度时的处理方式：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;该下沉的地方下沉&lt;/strong&gt;——把按键拦截做到宿主进程内部，而不是在通用钩子上凑合；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;该保守的地方保守&lt;/strong&gt;——tap 失联就停用全部自定义映射，宁可少功能不出错；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;该承认的地方承认&lt;/strong&gt;——明确写出「依赖非公开接口」「蓝牙版本号不能判定兼容」「自动测试不能外推真机结果」；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;该放弃的地方放弃&lt;/strong&gt;——开关型语音真机验证失败，就正式撤下并保留失败证据，而不是留给用户去踩。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;一个能说清自己&lt;strong&gt;在哪一步可能失败、失败了会怎样、以及为什么这么选&lt;/strong&gt;的项目，比一个声称「全面支持」的项目更值得信任。这份克制，是它最像样的工程特质。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;免责声明&lt;/strong&gt;：本文为个人学习性质的源码与文档解读，不构成对该软件的推荐、担保或安全评估。程序未签名且部分版本需管理员权限运行，请从项目官方仓库下载并核对 &lt;code&gt;SHA256SUMS.txt&lt;/code&gt;。涉及设备配对、驱动安装与 UAC 授权的操作，请自行评估风险。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;</description></item></channel></rss>