refactor: simplify webui labels, unify layer naming, and polish readme

This commit is contained in:
cuicuiV5 committed 2026-09-05 21:10:41 +08:00
1 parent 029766c174
commit 735652b34f
4 files changed
+400 -537

No files matched your search

+144 -266
View File
@@ -1,326 +1,204 @@
# RemoteMapper-ESP32 · 小米蓝牙遥控器 2 Pro (RC003) ➔ USB 复合硬件桥接器
# RemoteMapper-ESP32
> 🎯 **基于 ESP32-S3 (N16R8 / N8R2 / N4R2) 的硬件级中间人协议桥接方案**
> 彻底解决 Windows 内核驱动丢弃「音量+ / 音量- / 返回键」的顽疾,告别 VB-Cable 虚拟声卡依赖,实现真·即插即用!
> ⚠️ **硬件型号限定**:目前固件**仅支持「小米蓝牙遥控器 2 Pro(型号:RC003)」**,暂不支持其他型号遥控器。
基于 ESP32-S3 的小米蓝牙遥控器 2 Pro (RC003) 转 USB 复合设备硬件桥接方案。
将遥控器信号直接转换为标准免驱的 USB 输入设备(UAC 1.0 麦克风 + HID 键盘 + 媒体控制),解决 Windows 系统下特定按键被丢弃和音频输入依赖虚拟声卡的问题。
注:当前固件仅支持**小米蓝牙遥控器 2 Pro(型号:RC003)**,暂不支持其他型号。支持 ESP32-S3 N16R8、N8R2、N4R2 等主流硬件版本。
---
## 💡 为什么需要这个硬件项目?(背景与痛点)
## 背景与解决的问题
市面上的**小米蓝牙语音遥控器 2 Pro(型号:RC003)**采用精致的银色铝合金金属外壳,按键手感清脆、布局经典,并内置麦克风与拾音孔,非常适合作为 PC / HTPC 的全局多功能遥控器与 AI 语音助手控制器。
在 Windows 系统下直接使用小米蓝牙遥控器 2 Pro 时,存在两处系统级限制:
此前,开源社区作者 QL-4 等曾开发过基于 C# 的纯软件方案([QL-4/RemoteMapper](https://github.com/QL-4/RemoteMapper)),通过 Windows BLE API 读取按键与音频。
1. **部分物理按键被系统丢弃**:
遥控器的「音量+ (0x80)」、「音量- (0x81)」、「返回 (0xF1)」采用非标准 HID 键码。Windows 自带的蓝牙键盘驱动(`kbdhid.sys`)会在内核层将其直接过滤丢弃,应用层(包括全局 Hook、RawInput、AutoHotkey 等)无法截获这三个按键。若通过编写 Windows 内核过滤驱动来捕获,必须开启系统测试签名模式,存在系统崩溃风险且易被游戏反作弊程序拦截。
2. **语音功能依赖虚拟声卡**:
遥控器传输的是私有 ATVV 协议编码音频。在纯软件方案中,解码后的音频需要借助第三方虚拟声卡(如 VB-Cable)进行二次路由,输入法才能采集,配置繁琐且存在额外延迟。
但经过大量跨平台测试发现了一个非常核心的事实:
* 🍏 **在 macOS 与 🐧 Linux 系统下**:操作系统原生蓝牙 HID 协议栈极其开放,**完全没有所谓的按键屏蔽限制**,所有按键都能被正常捕获与映射,体验非常爽快!
* 🪟 **唯独在 Windows 系统下**:微软官方的蓝牙键盘驱动对非标 HID 做了极为死板的内核层过滤,导致纯软件方案在 Windows 上遭遇了无法逾越的系统级绝症——**必须依靠我们的硬件中转桥接器才能完美解决!**
### Windows 平台下纯软件方案的致命局限:
1. **三个核心按键被 Windows 驱动直接丢弃(无法映射)**:
* **音量+(`0x80`)**、**音量-(`0x81`)**、**返回键(`0xF1`)**:这三个按键在 RC003 遥控器固件中采用的是 Android 专属非标 HID 编码;
* 当遥控器直接与 Windows 电脑蓝牙配对时,微软官方蓝牙键盘驱动 `kbdhid.sys` 在内核层将其识别为未知非法键码并**直接丢弃**!
* 结果就是:应用层(无论通过全局 Windows Hook、RawInput 还是 AutoHotkey)**完全收不到任何按键消息**,这三个键在 Windows 下彻底沦为“死键”。
2. **纯软件若想在 Windows 捕获,必须付出惨痛代价(内核级驱动风险)**:
* 要在 Windows 层面拦截未进入 `kbdhid.sys` 的原始 HID 报文,唯一的软件途径是编写 Windows 内核过滤驱动(Kernel Filter Driver);
* 这要求操作系统必须永久开启**「测试签名模式(Test Mode)」或「禁用驱动程序签名强制」**;
* **严重负面后果**:直接导致主流游戏反作弊系统(如腾讯 ACE、拳头 Vanguard、Easy Anti-Cheat、BattlEye)判定系统存在内核作弊隐患并封禁游戏;同时破坏 Windows 内核完整性,带来极高的蓝屏(BSOD)与系统崩溃风险。
3. **语音输入强依赖第三方虚拟声卡(VB-Cable)**:
* 虽然纯软件可以通过 Windows GATT API 接收 ATVV 语音流并解码为 PCM,但要让输入法(微信输入法、讯飞等)识别,用户**必须额外安装第三方虚拟声卡(如 VB-Cable)**;
* 繁琐的虚拟音频管道配置、难以避免的缓冲区延迟、偶尔出现的采样率抖动与破音,严重影响了语音输入的优雅体验。
本项目采用 ESP32-S3 作为硬件中间人:
* 上游直连遥控器蓝牙,在空口完整接收所有 13 个按键的原始报文并解码音频;
* 下游通过芯片原生 USB 向电脑模拟标准的免驱硬件(UAC 1.0 麦克风与标准 HID 键盘/多媒体设备);
* 电脑端即插即用,无需安装任何驱动或后台软件,不修改系统内核,不影响游戏反作弊。
---
## ⚡ 硬件桥接的基本原理
**软件在操作系统层无法优雅解决的问题,交给硬件中间人来做。**
本项目通过一颗极低成本的 **ESP32-S3** 芯片充当**硬件中间人(Hardware Bridge)**:
## 系统拓扑
```text
┌────────────────────────┐ Bluetooth LE 5.0 (HOGP + ATVV) ┌────────────────────────┐
│ │ ───────────────────────────────────────► │ │
│ 小米蓝牙语音遥控器 │ │ ESP32-S3 N16R8 │
│ (Peripheral 端) │ ◄─────────────────────────────────────── │ (Central 主机端) │
└────────────────────────┘ 双向配对握手与私有音频协商 └───────────┬────────────┘
│
│ USB 2.0 Full-Speed
│ (TinyUSB 硬件复合设备)
▼
┌────────────────────────┐
│ PC 宿主机 (Win/Mac) │
│ │
│ • 标准 UAC 1.0 麦克风 │
│ • 标准 USB HID 键盘 │
│ • 标准 Consumer 多媒体 │
└────────────────────────┘
┌────────────────────────┐ BLE 5.0 (HOGP + ATVV) ┌────────────────────────┐
│ │ ──────────────────────────────► │ │
│ 小米蓝牙遥控器 2 Pro │ │ ESP32-S3 │
│ (RC003) │ ◄────────────────────────────── │ (Central 主机) │
└────────────────────────┘ └───────────┬────────────┘
│
│ USB 2.0 Full-Speed
│ (原生 USB OTG 复合设备)
▼
┌────────────────────────┐
│ PC 宿主机 │
│ │
│ • 标准 UAC 1.0 麦克风 │
│ • 标准 USB HID 键盘 │
│ • 标准 Consumer 媒体键 │
└────────────────────────┘
```
1. **上游接管**:ESP32-S3 作为 BLE Central 主机端直连小米遥控器,在蓝牙空中信道原始层完整接收 HOGP 报文与私有 ATVV 协议,**绕过微软 `kbdhid.sys` 的过滤,100% 捕获包括「音量+、音量-、返回键」在内的全部 13 个物理按键**;
2. **边缘 DSP 音频处理**:遥控器传出的 4-bit IMA-ADPCM 压缩音频流,在 ESP32 内部实时解码为 16kHz 16-Bit PCM,并完成 Declip 防破音、FIR 低通滤波与动态 AGC 增益平滑;
3. **下游模拟物理硬件**:ESP32-S3 原生 USB OTG 直接向电脑模拟出符合 USB-IF 标准的**标准免驱硬件设备**:
* 将 `0x80` / `0x81` 映射为标准 USB Consumer 键码 `0x00E9` / `0x00EA`(原生调节系统音量);
* 将 `0xF1` 映射为标准 USB Consumer 键码 `0x0224`(网页与播放器原生后退);
* 将解码后的音频通过标准 UAC 1.0 Isochronous 管道实时推送给电脑;
4. **对电脑而言**:PC 认为接入的就是一个**正规的物理 USB 麦克风和物理 USB 键盘**,**无需安装任何驱动,无需配置虚拟声卡,无内核侵入,不触发反作弊,绝对稳定安全**。
---
## 核心特性
1. **免驱 USB 物理麦克风(UAC 1.0)**
* 基于 TinyUSB 协议栈,模拟 16kHz 16-Bit 单声道标准输入设备。
* 实时解码遥控器 IMA-ADPCM 音频流。
* 包含音频前处理:按下瞬间立即注入输入法快捷键,并在音频前段插入 150ms 静音区(抑制按键微动物理杂音并留出输入法唤起窗口),消隐期结束施加 10ms 微平滑淡入(消除电平跳变爆音),结合 AGC 软启动避免拾取环境底噪。
2. **5 层独立映射系统**
* 提供 5 个独立按键配置层(默认层、层1 ~ 层4)。
* 每个按键均支持单击、长按(200~2000ms 可调)、双击(100~600ms 可调)。
* 支持三种层级生命周期:
* 永久停留层:手动切入后持续生效,直至再次切换。
* 一次性层:触发任意按键后自动返回默认层。
* 超时返回层:闲置达到设定秒数(3~300 秒)后自动返回默认层。
* 穿透继承:非默认层未单独配置的按键自动沿用默认层的设置。
* 自动防呆反转:若当前已在目标层,再次触发切入该层的按键时,会自动返回默认层。
* 支持为不同层级指定不同的板载 RGB 指示灯颜色。
3. **标准媒体与系统按键支持**
* 支持映射为音量调节、静音、播放/暂停、曲目切换、系统休眠等标准 USB Consumer 键码,系统级原生响应。
4. **内置 Web 管理后台**
* 固件集成 Web 服务器,通过浏览器即可完成可视化按键映射配置、蓝牙配对、网络设置与日志查看。
* 支持 AP 热点配置与 STA 局域网接入。
* 配置数据持久化保存在 ESP32 的 NVS 分区中,掉电不丢失。
---
## 🌟 项目核心特性
## 默认出厂按键映射
### 1. 🎙️ 真·免驱 USB 物理麦克风(UAC 1.0)
* 基于 TinyUSB 栈模拟标准 USB Audio Class 1.0 设备,16kHz 16-Bit Mono 原生输入;
* **按住语音键说话,松开自动静音**,无缝对接 Windows 语音听写(`Win+H`)、豆包 AI、微信语音与各类会议软件;
* 独创 **bInterval=2 / wMaxPacketSize=64** 降频缓冲设计,彻底解决 DWC2 硬件 USB 缺失 SOF 中断导致的 500Hz 丢帧魔咒,音频平滑无底噪;
* 🔇 **独创「150ms 消隐区 + 10ms 微平滑 + AGC 软启动」三阶抑噪技术**:
* **150ms 前置消隐区**:按下语音按键瞬间(0ms)即刻向电脑注入输入法热键,同时在音频流前段强制填入 150ms 数字全 0 静音,彻底抹除微动开关物理按压的“咯噔”敲击声,并为电脑端输入法留足唤出录音窗口的缓冲时间;
* **10ms 微平滑淡入(Micro Fade-In)**:消隐期结束瞬间施加 10ms(160 采样点)快速微平滑过渡,短于人耳感知阈值,既完美消除硬切边界引起的阶跃冲激电流爆音,又彻底杜绝了调幅效应产生的“沙沙”底噪;
* **AGC 软启动(Soft-Start)**:增益从 1.0x(0dB)平稳起步,并在消隐期冻结增益爬升,彻底避免开局将环境底噪放大引发输入法误识别出“嗯、啊、额”等杂音字。
### 2. 🎚️ 极客客制化 5 大独立层级系统 (Multi-Layer Architecture)
* **打破 12 键硬件上限**:内置 **5 个完全独立的按键映射层(Layer 0 ~ Layer 4)**,配合单击、长按、双击,带来多达 **180+ 动作维度**;
* 🔄 **智能自翻转双向切层 (Auto-Toggle on Same Target)**:
* 当触发“切入 Layer X”时,若当前已经在 Layer X,系统**自动翻转回退至 Layer 0 (默认主层)**;
* 结合穿透继承,双击/长按同一按键即可自然进出目标层,**无需专门占用宝贵的按键去配置返回键**!
* ⏱️ **三种完备的层级生命周期类型**:
* **🔒 永久停留层 (Persistent)**:驻留在目标层,直到手动再次切层;
* **⚡ 一次性瞬态层 (One-Shot)**:执行该层内任意按键后,瞬间自动退回 Layer 0;
* **⏳ 超时自动返回层 (Timeout)**:持续使用保持在该层,一旦闲置超过预设秒数(3~300秒自定),硬件自动静默回退回 Layer 0;
* 🔗 **按键穿透继承 (Layer Transparency)**:Layer 1~4 中未单独覆盖的按键自动穿透继承 Layer 0,免除重复配置;
* 🟣 **板载 WS2812 RGB 状态指示灯**:各层支持自定义独立 RGB 状态灯色彩(Layer 0: 绿色, 1: 青色, 2: 紫色, 3: 黄色, 4: 白色等),切层瞬间伴随高光呼吸闪烁,当前所在层级一目了然;
* 🎮 **完备的手势触发**:所有 12 个可编辑按键全部支持 **单击(Click)、长按(Long Press, 200~2000ms 可调)、双击(Double Click, 100~600ms 可调)**。
### 3. 🎵 原生标准 USB Consumer 多媒体控制
* 音量增加(`0x00E9`)、音量减少(`0x00EA`)、静音(`0x00E2`)、播放/暂停(`0x00CD`)、曲目切换与系统休眠;
* 完美兼容 Windows、macOS 与 Linux 原生全局音量与媒体控制。
### 4. 🔢 全链路 16 进制 / 10 进制双模智能引擎
* WebUI 所有选项、按键下拉菜单与微调输入框全面标清 `0x...` 标准 16 进制键码;
* 支持直接粘贴标准 16 进制键码(如 `0x2C`)或传统十进制数值,双向智能兼容。
### 5. 🛡️ 生产级 NVS 存储容灾与开机自愈
* 紧凑型 JSON 序列化存储,所有配置写入仅占用 Flash NVS 扇区不足 35%;
* 采用局部原子事务,写入后立刻调用 `nvs_flash_commit()`,彻底杜绝异常断电丢数据;
* 具备开机自愈校验机制:若检测到 Flash 扇区数据损坏或非法修改,自动无缝降级回出厂安全配置,杜绝系统崩溃变砖。
### 6. 🌐 免客户端嵌入式 Web 可视化后台
* 自带双模 Wi-Fi 管理器:
* **热点模式(AP)**:无需电脑连接局域网,手机或电脑直连热点 `RemoteMapper-AP`(192.168.4.1)并通过 Captive Portal 自动弹窗配置;
* **局域网模式(STA)**:连接家中 Wi-Fi,随时随地在浏览器中访问管理;
* 内置 1:1 遥控器真机动态交互面板、实体键盘敲击即录制改键、实时高频运行日志流与 Flash NVS 纯文本高级编辑器。
---
## 📋 预置按键映射表(出厂默认配置)
| 遥控器按键 | 物理键码 | 单击行为 (Click) | 长按行为 (Long Press) | 双击行为 (Double Click) |
| 按键 | 物理键码 | 单击行为 | 长按行为 | 双击行为 |
| :--- | :--- | :--- | :--- | :--- |
| **电源键** | `0x66` | `Alt + F4` (关闭窗口) | 🌙 系统休眠 (`0x0032`) | — |
| **语音键** | `0x04` | 🎙️ UAC 麦克风推流 + `Alt + ,` (AI语音助手) | 🎙️ 按住持续录音 | — |
| **方向上** | `0x52` | 键盘 `↑` (Arrow Up) | — | — |
| **方向下** | `0x51` | 键盘 `↓` (Arrow Down) | — | — |
| **方向左** | `0x50` | 键盘 `←` (Arrow Left) | — | — |
| **方向右** | `0x4F` | 键盘 `→` (Arrow Right) | — | — |
| **确定键** | `0x28` | 键盘 `Enter` (回车) | — | — |
| **返回键** | `0xF1` | 多媒体返回 (`0x0224` AC Back) | — | — |
| **主页键** | `0x24` | `Win + D` (显示/隐藏桌面) | — | — |
| **菜单键** | `0x5D` | 键盘 `Space` (空格 / 播放暂停) | — | — |
| **音量+** | `0x80` | 🔊 音量增加 (`0x00E9` Vol+) | — | — |
| **音量-** | `0x81` | 🔉 音量减少 (`0x00EA` Vol-) | — | — |
| **电视键** | `0xC0` | 键盘 `F8` | — | — |
| **电源键** | `0x66` | `Alt + F4` (关闭窗口) | 系统休眠 (`0x0032`) | — |
| **语音键** | `0x04` | 麦克风音频推流 + `Alt + ,` | 按住持续录音 | — |
| **方向上** | `0x52` | 方向键上 (`↑`) | — | — |
| **方向下** | `0x51` | 方向键下 (`↓`) | — | — |
| **方向左** | `0x50` | 方向键左 (`←`) | — | — |
| **方向右** | `0x4F` | 方向键右 (`→`) | — | — |
| **确定键** | `0x28` | 回车 (`Enter`) | — | — |
| **返回键** | `0xF1` | 多媒体返回 (`0x0224`) | — | — |
| **主页键** | `0x24` | 显示桌面 (`Win + D`) | — | — |
| **菜单键** | `0x5D` | 空格 (`Space`) | — | — |
| **音量+** | `0x80` | 音量增加 (`0x00E9`) | — | — |
| **音量-** | `0x81` | 音量减少 (`0x00EA`) | — | — |
| **电视键** | `0xC0` | `F8` | — | — |
*注:以上按键均可在 Web 后台任意修改、互换或自定义为任何按键/多媒体功能。*
*注:以上按键均可在 Web 后台自由修改、重新分配或清除。*
---
## 🚀 完整使用教程(从零上手)
## 硬件连接
整个使用流程简单清晰,分为以下六个核心步骤:
### 步骤 1:硬件采购与接线
1. **采购开发板**:购买任意 **ESP32-S3-DevKitC-1** 主控板(淘宝约 18~35 元):
* 🌟 **全系列主流型号无缝兼容**:
* **N16R8**(16MB Flash + 8MB Octal PSRAM):旗舰大容量配置,出厂默认目标;
* **N8R2**(8MB Flash + 2MB Quad PSRAM):性价比极高的高频主流款,内存与存储极为充裕;
* **N4R2**(4MB Flash + 2MB Quad PSRAM):极简低成本版,固件极致精简后仅 1.16MB,仍完整保留 A/B 双分区 OTA 升级能力!
2. **准备遥控器**:小米蓝牙遥控器 2 Pro(型号: RC003)
3. **关键数据线连接**:
* ESP32-S3 开发板通常有两个 Type-C 口:一个标注为 **`UART`**(或 COM),另一个标注为 **`USB`**(或 **`OTG`**);
* **⚠️ 日常使用必须将数据线插在 `USB / OTG` 接口**(直连芯片原生内部 USB 控制器,才能免驱模拟物理麦克风与键盘;UART 口仅用于串口日志调试,无法模拟 USB 输入外设)。
1. **开发板要求**:
任意 ESP32-S3 开发板,推荐配置:
* **N16R8**(16MB Flash, 8MB PSRAM):默认构建目标。
* **N8R2**(8MB Flash, 2MB PSRAM):主流常见规格。
* **N4R2**(4MB Flash, 2MB PSRAM):极简规格,编译产物约 1.2MB。
2. **遥控器**:
小米蓝牙语音遥控器 2 Pro(型号:RC003)。
3. **接口接线**:
ESP32-S3 通常带有两个 Type-C 接口:
* **`USB`(或 `OTG`)口**:必须连接到电脑。该接口直通 ESP32-S3 原生 USB 控制器,用于模拟 UAC 麦克风与 HID 设备。
* **`UART` 口**:仅用于烧录与查看串口日志,日常使用无需连接。
---
### 步骤 2:固件编译与一键烧写(多型号支持)
## 固件编译与烧录
将 ESP32-S3 开发板通过数据线连接至电脑,根据开发板型号选择对应的烧录方式:
连接开发板至电脑,按需选择以下任一方式:
#### 方式 1:双击批处理脚本(最简便)
在本项目根目录下运行:
* **默认烧写 N16R8**:直接双击运行 `flash.bat`
* **命令行指定型号烧写**:
```cmd
flash.bat n8r2 # 烧录至 N8R2 开发板
flash.bat n4r2 # 烧录至 N4R2 开发板
flash.bat n16r8 # 烧录至 N16R8 开发板
```
### 方式 1:使用批处理脚本
#### 方式 2:PlatformIO 命令行精确构建与烧录
在本项目根目录下打开终端,可直接使用以下命令进行编译与烧写:
项目根目录下提供了预置脚本:
```cmd
flash.bat n16r8 :: 烧录至 N16R8 开发板(默认)
flash.bat n8r2 :: 烧录至 N8R2 开发板
flash.bat n4r2 :: 烧录至 N4R2 开发板
```
### 方式 2:使用 PlatformIO 命令行
在终端中执行对应型号命令:
```bash
# ========================================================
# 1. 旗舰版 N16R8 (16MB Flash, 8MB Octal PSRAM)
# ========================================================
# 仅编译固件
python -m platformio run -e esp32s3_n16r8
# 编译并烧录至开发板
python -m platformio run -e esp32s3_n16r8 -t upload
# N16R8
pio run -e esp32s3_n16r8 -t upload
# ========================================================
# 2. 性价比版 N8R2 (8MB Flash, 2MB Quad PSRAM)
# ========================================================
# 仅编译固件
python -m platformio run -e esp32s3_n8r2
# 编译并烧录至开发板
python -m platformio run -e esp32s3_n8r2 -t upload
# N8R2
pio run -e esp32s3_n8r2 -t upload
# ========================================================
# 3. 极简版 N4R2 (4MB Flash, 2MB Quad PSRAM)
# ========================================================
# 仅编译固件
python -m platformio run -e esp32s3_n4r2
# 编译并烧录至开发板
python -m platformio run -e esp32s3_n4r2 -t upload
# N4R2
pio run -e esp32s3_n4r2 -t upload
```
> 💡 **烧录排错小贴士(Boot 模式)**:
> 若提示连接开发板超时或无法识别 COM 口,可按住开发板上的 **`BOOT` 按键不放**,点按一下 **`RST` 复位键**(或重新拔插一次 USB 线),松开 `BOOT` 按键即可强制开发板进入 ROM Download 下载模式,然后再执行上述烧录命令。
若连接超时或无法进入下载模式,可按住开发板上的 `BOOT` 键,点按一次 `RST` 键后再松开 `BOOT` 键,即可强制进入下载模式。
---
### 步骤 3:开机配网(连接家里 Wi-Fi)
1. 固件初次启动时,会自动广播一个开放式配置热点:
* **Wi-Fi 热点名称**:`RemoteMapper-AP`
* **热点默认密码**:无密码(直接连接)
2. 拿起手机或电脑,搜索并连接 `RemoteMapper-AP`;
3. 连接后系统通常会自动弹出强制门户配置页面;若未弹出,直接在浏览器中打开后台地址:
```text
http://192.168.4.1/
```
4. 切换到底部的 **「📶 Wi-Fi 与系统配置」** 选项卡,点击「🔍 搜索 Wi-Fi」,在列表中选定家里的 2.4GHz Wi-Fi 并输入密码,点击「💾 保存并连接 Wi-Fi」;
5. ESP32 连接成功后,以后只要电脑或手机在同一局域网下,直接在浏览器中访问分配的 IP(例如 `http://192.168.2.179`)或直接输入域名访问:
```text
http://remotemapper.local/
```
## 使用指南
### 1. 配网
固件首次启动后会开启配置热点:
* 热点名称:`RemoteMapper-AP`(无密码)
* 浏览器访问:`http://192.168.4.1/`
* 进入「Wi-Fi 与系统配置」页面,扫描并连接局域网 Wi-Fi。连接成功后,可在局域网内直接通过分配的 IP 地址访问后台。
### 2. 配对遥控器
1. 打开 Web 后台的「蓝牙配对管理」标签页。
2. 拿起遥控器,**同时按住「主页键」与「菜单键」3 秒**,待指示灯快闪进入广播配对状态。
3. 在网页上点击「扫描蓝牙设备」,找到对应设备并点击连接。
4. 绑定成功后,设备信息会持久化保存,后续开机或遥控器休眠唤醒均会自动重连。
### 3. 按键与层级设置
1. 进入「按键映射和层级设置」页面。
2. 点击上方层级选项卡切换配置层(默认层、层1 ~ 层4)。
3. 点击遥控器模型上的按键进入编辑弹窗,可独立设置单击、长按、双击触发的行为(键盘按键、多媒体控制或层级切换)。
4. 保存配置后即刻生效并写入 Flash。
### 4. 输入法语音配置
固件出厂默认在按住语音键时注入 `Alt + ,` 快捷键(微信输入法默认语音热键)。
1. 打开电脑输入法设置,将麦克风输入源选择为系统新增的硬件设备:`RemoteMapper Mic`。
2. 确认输入法的语音输入快捷键与遥控器语音键配置的快捷键一致。
3. 按住遥控器语音键说话,松开按键即完成输入。
---
### 步骤 4:遥控器蓝牙配对与绑定
1. 在 Web 控制台顶部进入 **「📡 蓝牙配对管理」** 选项卡;
2. 拿起实体小米遥控器,**同时按住「主页键」与「菜单键」3 秒**,听到滴声或看到遥控器指示灯快闪,进入蓝牙配对广播状态;
3. 在网页上点击 **「🔍 扫描附近蓝牙设备」**,列表中会出现 `Xiaomi Voice Remote`(或 `小米蓝牙语音遥控器`);
4. 点击对应的 **「连接此设备」** 按钮,连接成功后遥控器 MAC 地址将自动写入 ESP32 Flash NVS;
5. **持久化自动回连**:绑定成功后,后续无论设备断电重启,还是遥控器深度休眠,按任意键即可在 **2~3 秒内秒级无感回连**!
## 进阶:与 PC 伴侣程序联动
---
若需要让按键触发打开特定软件、运行脚本或系统命令,可以使用项目附带的 `pc_companion` 辅助程序:
### 步骤 5:按键映射与手势自定义
1. 进入 **「🎮 遥控器与改键测试」** 选项卡;
2. 随意按下实体遥控器的任意按键,屏幕上的 1:1 仿真遥控器模型会实时点亮高光绿框,并显示实时触发动作;
3. 点击模型上的任意按键卡片(例如点击「菜单键」或「电源键」),即可弹出改键弹窗;
4. 每个按键均可独立配置三个手势标签页:
* **单击(Click)**:瞬时点按或按下保持(Hold);
* **长按(Long Press)**:可自定 200ms ~ 2000ms 触发时长,长按自动阻止短按,互不干扰;
* **双击(Double Click)**:可自定 100ms ~ 600ms 双击判定间隔;
5. **改键极为简单**:
* **敲击即录制**:直接在物理电脑键盘上敲击目标按键(如敲一下 `Space` 或 `Ctrl+C`),网页自动捕捉录制;
* **快捷下拉选择**:菜单中预置了修饰键、F1~F24 专用键、快捷组合键(`Win+D` 回桌面、`Alt+Tab` 任务切换),以及原生多媒体功能(音量增减、静音、播放/暂停、休眠等);
6. 点击「💾 保存映射」,修改即刻生效并持久化至 Flash,断电不丢失。
---
### 步骤 6:配置语音输入法(让语音键满血工作)
遥控器的语音键出厂默认配置为:**按住时启动 UAC 麦克风音频推流,并注入快捷键 `右Alt + 逗号`**(这是微信输入法的默认语音快捷键)。
要让语音输入在 Windows 上完美工作,只需简单设置你的输入法(以微信输入法为例,搜狗、讯飞同理):
1. 打开输入法设置 ➔ 找到 **麦克风/音频输入源**,在下拉菜单中选择:
```text
RemoteMapper Mic (设备管理器中免驱的原生物理麦克风)
```
2. 查看并确认输入法的 **语音输入唤醒快捷键** 与 ESP32 语音键派发的快捷键一致(默认即为 `右Alt + 逗号`;如果使用讯飞或搜狗,可把输入法快捷键设为 `F8` 或 `Ctrl+Shift+V`,并在 Web 后台同步修改语音键快捷键);
3. **开始体验**:
* 拿起遥控器,**按住语音键直接说话,说完松开按键**;
* 麦克风录音与快捷键完美无缝衔接,文字瞬间自动上屏打出!
---
## 🎮 进阶可玩性:PC 本地伴侣程序 (`pc_companion`) 深度联动
> 💡 **解决痛点**:普通 USB 键盘只能模拟按键,无法执行「一键启动指定应用」、「一键运行复杂批处理」、「一键切换显示器信号源」或「一键运行 Python 脚本」。
我们随项目附带了极简、高性能的 PC 端伴侣后台服务:**`pc_companion`**。
### 🌟 核心原理:利用 F13 ~ F24 零冲突键码
* Windows 原生支持 `F13` 到 `F24` 虚拟键码(VK_F13 ~ VK_F24),但现代实体键盘几乎没有这些按键;
* 本项目将遥控器动作映射为 `F13 ~ F24`,PC 伴侣通过原生 Win32 `RegisterHotKey` 监听,**待机 CPU 占用绝对 0.0%,内存占用仅几 MB,无任何钩子冲突与延迟**!
### 🛠️ 快速配置与玩法示例:
1. **在 ESP32 Web 后台**:将任意遥控器按键(如双击 TV 键)映射为 `F13` 或 `F14`;
2. **在 PC 端编辑配置**:打开 `pc_companion/config.json`,为每个 F 键绑定任意本地动作:
1. 将遥控器指定手势映射为 `F13` ~ `F24` 等空闲功能键。
2. 在 `pc_companion/config.json` 中为对应键位定义执行命令:
```json
{
"F13": {
"name": "一键打开抖音网页版",
"command": "start https://www.douyin.com/",
"enabled": true
},
"F14": {
"name": "一键切换显示器信号源到 PS5",
"command": "C:\\Scripts\\切到ps5.bat",
"enabled": true
},
"F15": {
"name": "运行自定义 Python 自动化脚本",
"command": "python scripts/demo_task.py",
"name": "打开浏览器",
"command": "start https://www.google.com",
"enabled": true
}
}
```
3. **启动与常驻**:
* **调试运行**:双击 `pc_companion/start_companion.bat`(前台黑框输出执行日志);
* **静默常驻**:双击 `pc_companion/silent_start.vbs`(无弹窗后台静默运行);
* **开机自启**:双击 `pc_companion/enable_autostart.bat`(自动注入 Windows 用户注册表启动项);
* **独立打包**:运行 `pc_companion/build_exe.bat`,即可一键打包生成独立的单文件绿色可执行程序 `RemoteMapperHost.exe`(无需安装 Python 环境)。
3. 运行 `pc_companion/silent_start.vbs` 即可在后台静默监听触发。
---
## 💖 鸣谢与致敬开源项目 (Special Thanks)
## 致谢
本项目的诞生离不开开源社区先行者的无私探索与灵感启发,特此向以下优秀开源项目致以诚挚敬意:
* [QL-4/RemoteMapper](https://github.com/QL-4/RemoteMapper):启发了小米遥控器在 PC 端增强控制的应用场景,提供了宝贵的 Windows C# 软件实现方案与 ATVV 协议参考;
* [godarrenw/mi_remote_control](https://github.com/godarrenw/mi_remote_control):深入剖析了小米遥控器的蓝牙通信、逆向工程与 Linux 驱动底层细节,为本项目的协议实现提供了重要参考。
* [QL-4/RemoteMapper](https://github.com/QL-4/RemoteMapper):提供了 Windows C# 软件方案与 ATVV 协议参考。
* [godarrenw/mi_remote_control](https://github.com/godarrenw/mi_remote_control):提供了遥控器蓝牙协议分析与逆向参考。
---
## 🤝 欢迎贡献 (Contributing & Roadmap)
## 开源协议
本项目完全开源,代码模块化且结构清晰,热烈欢迎各位极客与开发者提交 Issue 和 Pull Request!
我们非常期待社区共同完善以下方向:
* 📡 **支持更多遥控器型号**:扩展适配更多小米老款遥控器、天猫魔盒遥控器、Apple TV 遥控器、Google Chromecast 遥控器等;
* 🎚️ **多层功能触发层 (Multi-Layer / Fn Chording)**:引入 Leader Key 前导键机制,实现按键层级切换;
* 📲 **WebUI 在线 OTA 固件升级**:免插拔数据线,直接在浏览器一键上传 `.bin` 固件无感更新。
* 等等更多功能
---
## 📖 深入阅读与底层源码参考
* 📘 [开发者手册与系统技术全景文档 (DEVELOPMENT.md)](./DEVELOPMENT.md)
* 🐛 [蓝牙与 USB 复合设备稳定性深度修复报告](./BLE_HID_UAC_BUGS_POSTMORTEM.md)
* 🎧 [USB UAC 1.0 与 DWC2 驱动优化报告](./USB_UAC_BUG_POSTMORTEM.md)
---
## 📄 开源许可证
本项目遵循 [MIT License](./LICENSE) 开源许可协议。
本项目采用 [MIT License](./LICENSE) 协议开源。
+6 -6
View File
@@ -201,10 +201,10 @@ void key_engine_load_defaults(key_mapper_engine_t *engine) {
engine->last_activity_time = 0;
// ----------------------------------------------------
// Layer 0: 默认主层 (Default Layer)
// Layer 0: 默认层
// ----------------------------------------------------
key_layer_t *l0 = &engine->layers[0];
strncpy(l0->name, "默认主层", sizeof(l0->name) - 1);
strncpy(l0->name, "默认层", sizeof(l0->name) - 1);
l0->type = LAYER_TYPE_PERSISTENT;
l0->timeout_sec = 0;
l0->led_color = 0x00FF00; // Green
@@ -354,25 +354,25 @@ void key_engine_load_defaults(key_mapper_engine_t *engine) {
// ----------------------------------------------------
// Preset Layers 1 ~ 4 (Inherit Layer 0 by default)
// ----------------------------------------------------
strncpy(engine->layers[1].name, "影音娱乐", sizeof(engine->layers[1].name) - 1);
strncpy(engine->layers[1].name, "层1", sizeof(engine->layers[1].name) - 1);
engine->layers[1].type = LAYER_TYPE_TIMEOUT;
engine->layers[1].timeout_sec = 15;
engine->layers[1].led_color = 0x06B6D4; // Cyan
engine->layers[1].binding_count = 0;
strncpy(engine->layers[2].name, "游戏模式", sizeof(engine->layers[2].name) - 1);
strncpy(engine->layers[2].name, "层2", sizeof(engine->layers[2].name) - 1);
engine->layers[2].type = LAYER_TYPE_PERSISTENT;
engine->layers[2].timeout_sec = 0;
engine->layers[2].led_color = 0xA855F7; // Purple
engine->layers[2].binding_count = 0;
strncpy(engine->layers[3].name, "快捷宏层", sizeof(engine->layers[3].name) - 1);
strncpy(engine->layers[3].name, "层3", sizeof(engine->layers[3].name) - 1);
engine->layers[3].type = LAYER_TYPE_ONESHOT;
engine->layers[3].timeout_sec = 0;
engine->layers[3].led_color = 0xEAB308; // Yellow
engine->layers[3].binding_count = 0;
strncpy(engine->layers[4].name, "办公演示", sizeof(engine->layers[4].name) - 1);
strncpy(engine->layers[4].name, "层4", sizeof(engine->layers[4].name) - 1);
engine->layers[4].type = LAYER_TYPE_PERSISTENT;
engine->layers[4].timeout_sec = 0;
engine->layers[4].led_color = 0xFFFFFF; // White
+1 -1
View File
@@ -80,7 +80,7 @@ typedef enum {
} layer_type_t;
typedef struct {
char name[MAX_LAYER_NAME_LEN]; // e.g. "默认主层", "影音娱乐"
char name[MAX_LAYER_NAME_LEN]; // e.g. "默认层", "层1"
layer_type_t type; // LAYER_TYPE_*
uint16_t timeout_sec; // 3 ~ 300s (for LAYER_TYPE_TIMEOUT)
uint32_t led_color; // RGB 0x00RRGGBB (e.g. 0x00FF00)
+249 -264
View File
File diff suppressed because it is too large. Load diff