文档 · 随安装包分发
排障与兼容性
真实踩过的坑、设备兼容矩阵、已知问题。
目的:把每次实测踩到的坑,变成下一位 AI 的检查项。 维护规则:每做一个新任务,回填一条「现象 / 根因 / 规避 / 证据」;配方级的步骤同步进 给 AI 的操作手册。 最后更新:2026-10-23(新增 §2.2 语音桥) 相关:给 AI 的操作手册(操作手册)·
control/README.md(控制层与 §7 坑位,源码仓库)· 接入 AI(MCP)(接入)
0. 开工 30 秒检查
status() → device / screen / calibrated
screenshot() → 当前页、列、键盘状态、是否有弹窗
screen=false:等 2 s 再看一次;仍 false 就请人重开「屏幕镜像」,不要反复重试。calibrated=false:不要盲点,先跑校准。- 截图可能晚一帧:每个动作后多截一张再判断,否则会把「已提交」看成「还在输入」。
- 主屏有多页、每页列数不同:同一坐标在不同页可能是不同 App,先看截图再点。
iPhone 端两个总开关(每次新设备/换机必查,埋得很深) 1. 辅助触控必须开:
设置 → 辅助功能 → 触控 → 辅助触控。不开就没有鼠标指针, 所有 click/move 都像“没反应”。 2. 鼠标键「使用主键盘」必须关:设置 → 辅助功能 → 触控 → 辅助触控 → 指针设备 → 鼠标键 → 使用主键盘。开着时键盘被当成鼠标:i j k l m o u 7 8 9 .不落屏、 回车不换行而是弹菜单、指针乱跳。这是 2026-10-22「11 个字符永不落屏」的真正原因, 关掉立即恢复,不需要重启手机。
反模式:别自己发明流程(会浪费大量时间,而且不可靠) - ❌ 手改
calib.json/ 自己补像素偏移 / “这次先 +0.02 试试”——校准错了就calibration_request; - ❌ 不用click_text而靠目测坐标反复盲点;不用scroll(fine)而自己拼拖拽; - ❌ 连续changed=false不换目标、不查日志,闭眼重试; - ❌ 绕过 MCP 直接curl /api/raw或写脚本操作手机(排障例外,要说明); - ❌ 自己跑校准向导(必须用户点「开始」); - ❌ 遇到问题先怀疑固件/重装 App,而不是先看status/app_logs。 先翻 AI_GUIDE §1.0 的工具表,再动手。摸索 10 分钟不如查表 10 秒。
0.1 新设备 / 新场景:先建立基线
用户可能换 iPhone / iPad、换 iOS 版本、换指针大小、换网络。同一套坐标、滚动距离、返回手势不要跨设备复用。
第一次接触一台设备或一个 App,先记下:
| 项 | 怎么取 |
|---|---|
| 设备 / 系统 | 用户告知,或从屏幕「关于本机」看 |
| 指针大小 | 设置 → 辅助功能 → 触控 → 辅助触控 → 指针控制 |
| 镜像分辨率 | status() 的 aspect、截图尺寸 |
| 校准 | calibrated + control/calib.json 里对应的 profiles 键 |
| 投屏延迟 | 校准向导第一步会测(这台 0.53 s) |
| BLE | status 里 connected/encrypted/sub/kb/ms |
然后用计算器 7+8=15 验证这张表是否适合当前设备。不要凭“上次也是 iPhone”就直接操作。
基线写进 §6.1,任务中的新发现写进对应小节;下一个 AI 先翻这里,再动手。
1. 屏幕源(AirPlay)
| 现象 | 根因 | 规避 |
|---|---|---|
| App 打开后画面变横屏、随后冻结,点击/滚动帧 hash 不变 | 部分第三方 App 的投屏保护(实测) | 换 App;或用 UVC 采集绕过;不要重校准(不是坐标问题) |
使用上述 App 期间 screen=false 两次,其中一次 UxPlay 被看门狗重启 | 投屏会话被 App 带崩 | 等 / 请人重投屏;不要连续操作 |
同局域网多台 Mac 的投屏名都叫 Quileg | 接收端名写死 | 现为 Quileg - <电脑名> (4位ID),每台唯一;BLE 名本身带 MAC 后缀 |
| 画面静止时取不到新帧 | AirPlay 只在画面变化时发帧 | 用「画面变化」判断,不要用「帧新鲜度」 |
| 长距离移动时 409 | BLE + Wi-Fi 共存抖动 | 409 后 ensure_ble() + 重试;画图/校准都要包重试 |
| 横屏 App 下点击系统性偏移 | 校准表是竖屏的,宽高比从 0.463 变 1.778 | 不要硬点;换竖屏页或重新校准 |
所有工具突然 connection refused | App 被 ⌘Q 退出(0.5.0 起关窗只是隐藏) | 让用户看 Dock / 重开 App;不要重投屏 |
2. 输入(中文 / 英文 / 标点)
- 九宫格不可用:硬件键盘连接时 iOS 隐藏软键盘,九宫格点不到;即使能显示,每键 4–7 s。用全键盘。
- 候选选择用数字键
1–9;空格只移动高亮,不提交。 - 候选顺序不固定:
荀彧是第 3 个、使是第 4 个、至是第 4 个。按数字前先看候选内容。 - 英文候选是标签符号:拼音模式下打
abc,选ABC/abc插入的是灰色胶囊(退格整块删除),不是普通文本。要普通英文先ctrl+space切英文输入法。 - 标点宽度不统一:输入
123,456.789!实际得到123,456.789!(逗号/句点半角、感叹号全角)。不要假设 1:1。 - 整句拼音可行:
woxihuanbeijing→ 「我喜欢北京」;nihao→ 「你好」。名句命中率高,冷门内容要分段。 - 生僻字用组词法:
xunyu→荀彧→←退格→⌘→;caojianrenming→草菅人命→删字→⌘→。 - 删字后必须回行尾:退格只删字符不移动光标;不
⌘→就继续输入会插到目标字前面(实测9菅vs菅8)。 - 软键盘不显示 ≠ 没聚焦:看蓝色边框/光标,或用
Tab切焦点。 type_text仅接受 ASCII:中文通道已移除;中文改用拼音 + 截图/OCR 判断候选 +click_text点选,不依赖任何外部服务器。- 切 App:iPhone 上没有
cmd+tab(2026-10-22 实测cmd+tab/shift+cmd+tab都无反应,iPadOS 未验证)。 用cmd+h回主屏 →cmd+space搜名字打开;cmd+h本轮 2/2 生效。App 内标签可试cmd+1–cmd+9。 Tab会被中文输入法吃掉:弹出候选栏,不是焦点导航;先ctrl+space切英文。Enter常只提交候选词,不激活界面元素;Spotlight/备忘录里失败时改用click_text。type_text含非 ASCII 会直接报错:这是预期行为;先改写拼音,再用 OCR 点候选。
2.1 部分字符不落屏 / 回车弹菜单:鼠标键「使用主键盘」被打开(2026-10-23 更正)
现象:type_text、App 软键盘、POST /api/raw {"text":"type i"} 三条路都一样——在备忘录/Spotlight 里 下面 11 个字符从不落屏,其余字母数字、大小写、标点、顺序全部正常:
i j k l m o u 7 8 9 .
usage: 0x0C 0x0D 0x0E 0x0F 0x10 | 0x12 | 0x18 | 0x24 0x25 0x26 | 0x37
同时还有两个伴随症状:回车不换行,而是弹出功能选项/菜单;指针有时自己乱跳。
根因(2026-10-23 用户定位):iPhone 的 设置 → 辅助功能 → 触控 → 辅助触控 → 指针设备 → 鼠标键 → 使用主键盘 被打开了。 键盘被系统当成鼠标:i/j/k/l 移动、u/o 点击、7/8/9 方向、. 等,Return 被当作点击。 这 11 个正好是鼠标键的键位——不是固件坏,也不是 HID 键位状态坏。
恢复:把 使用主键盘 关掉(不需要时把 鼠标键 也关掉),立即恢复; 不需要重启 iPhone、不需要重配对。
前置:辅助触控 必须开着,否则 iPhone 上根本没有鼠标指针(见 §0)。
为什么之前误判:2026-10-22 那次靠「重启 iPhone」恢复了,于是归因为“HID 键位状态坏了”; 实际是设置开关的问题(重启/重配后开关被重置或后续被关掉)。现在以开关状态为准。
同一块板 + 同一固件,只换宿主(当时的证据,结论仍成立——手机侧设置问题):
| 宿主 | 结果 |
|---|---|
| macOS(Sublime Text) | ✅ aib ijklm 789. 14 个字符全落屏 |
| iPadOS 18(备忘录) | ✅ hijklm 全部进入拼音组合 |
| 这台 iPhone(iOS 18) | ❌ 11 个全丢(当时鼠标键开着) |
已排除(别重复走这几步):
| 假设 | 实测结果 |
|---|---|
固件 kLayout 写错 / 出厂镜像旧 | 源码表与 app-16m.bin、factory-16m.bin 逐字节一致;key i 返回 ok(不是 err unknown key),说明运行时映射非零 |
| 按压时长太短、被 iOS 合并 | type(10 ms)与 key(40 ms)同样丢 |
| 大小写 / Shift / ⌘ 组合 | 小写、大写、⌘I 全丢;同一修饰键下 ⌘B(0x05)正常 |
| 报告槽位(第 1 槽被特殊处理) | key h+i(同一报告 keys[0]=0x0B, keys[1]=0x0C)只出 h,i 在槽 2 也丢 |
| 中文输入法 / 硬件键盘布局 | 删除中文输入法、确认「英语(美国)/ ANSI」后现象不变 |
| 文本替换(自定义短语) | 列表只有 1 条正常替换,无空映射 |
| 绑定 / 描述符缓存 | 忽略设备重配后现象不变(当时重启才“恢复”,实为开关状态变化) |
排查顺序(以后照这个走,别先怀疑固件):
type_text("aib")自检,确认是「部分字符」还是「完全打不进去」;- 换宿主(Mac 或 iPad)打同一串:换了就好 = 手机侧问题,不要动固件、不要重校准;
- 先查手机两个开关:辅助触控 = 开;指针设备 → 鼠标键 → 使用主键盘 = 关;
- 仍不行再:重启 iPhone → 重新配对 → 还原键盘词典 → 第二台 iPhone 对照。
2.2 语音桥:Mac 朗读 → 手机听写(2026-10-23 实测)
用途:中文输入最慢的是点候选;让 Mac 用 speak() 朗读、手机输入法听写,直接上屏。 speak → /api/speech → 系统 say。
起停方式:双击 Control 开始,单击 Control 停止(不需要点屏幕麦克风)。 MCP 调用:dictation("start") / dictation("stop")(0.6.0 起)。 它会先按一次 Shift 唤醒 HID 键盘,再双击/单击 Control —— iOS 会吞掉空闲后的第一次按键, 直接 key(combo="ctrl", repeat=2, gap_ms=60) 常常只算一次 Control,听写起不来(2026-10-23 实测)。
- 前提:手机
设置 → 通用 → 键盘 → 听写 → 听写快捷键 = Control(选项只有 Control / Command / 无); - 实测两次按下间隔 60 ms 有效;150 / 350 / 500 ms 都没反应,固定用 60 ms;
- 光标必须在文本框里;软键盘开或关都行(关了也能起);
- 正在听的样子:状态栏橙点 + 光标旁黄色小麦克风 + 键盘右下角麦克风变深色停止键; 黄色小麦克风很小、容易被忽略——它是“正在听”的唯一提示。
三个坑
| 现象 | 根因 | 规避 |
|---|---|---|
| 只落前几个字,后面没有 | 转写延迟 1.5–3 s,截图/OCR 太早 | 说完等 2–3 s 再验收;同一句多截一帧,第二帧才完整 |
| 小麦克风变“暂停态”后再说话没反应 | 误以为暂停 = 停止 | 暂停态照常收音,直接说下一句即可;真停了会连橙点一起消失 |
| Spotlight 搜索框说完什么都不进 | 搜索框不走同一条转写路径(实测 2/2 空白) | 用备忘录 / 短信等真实文本框验收 |
其他实测:F5(Apple 键盘听写键)无效且会收起软键盘;Mac 音量 56% 够用; 自动标点(, 。)和自动换行由 iOS 加,不是 speak 加的;单会话约 30 s 无话音自动结束。
与拼音点选的关系:语音桥快,但依赖扬声器/麦克风/环境噪声;关键内容仍要 OCR 复核, 听写不可用时回退 §2 的拼音 + 候选点选。
证据:操作员 2026-10-23 实测(iPhone iOS 18 / 固件 0.7.0 / App 0.9.25): 听写快捷键设置、两句连续落屏、单击 Control 停止的截图。
3. 坐标与点击
- 布局会漂移:信息 App 新建按钮实测
y 0.885 → 0.935;每次按最新截图取坐标。 changed=true不代表成功:hover 只有约 90 px;真实界面变化通常 > 1000 px。用min_change_px(click_text默认 500)。- 顶部 6% 是
Device.changed()的盲区(避状态栏时钟):TL/TR 停车点在 y≈3%,校准里不能用它判变化,要用_diff_pixels。 - 边缘够不到:BR/TL 停车点离边约 3–10%,
x>0.96的按钮可能点不到;必要时换角或截图确认。 - 底部 6% 精度下降(
y>0.94):点控件上沿,或用键盘。 - 圆角不可达带:iOS 把指针中心夹在圆角内,
x<0.15 且 y>0.97一带物理点不到;重试无意义。 现在有几何模型:control/corners.py+ 实测档案control/corner_profiles.json(源:宽x高→ inset / 半径 R),click会返回predicted落点供对照; 换手机/分辨率先用python control/measure_corners.py --device "…"量一份。见 §6.2。 - 点击默认 aim=True:会先找指针纠偏,多花 1–2 s;返回里的
pointer_err可判断这次准不准。pointer_err突然从个位数变成 ~110 px 说明校准表已经不对(2026-10-22 遇到过一次),别硬补偏移,重校。 - 右键(
click 2,固件 0.6.1+)是应用相关的:备忘录列表能弹菜单,部分第三方列表不响应。 换原生文本/列表界面验证,别拿单个 App 判断固件好坏。 - MCP 已暴露右键(2026-10-23 实测):
click(x, y, button="right")→ 固件click 2。 实测 N16R8 + iPhone 备忘录列表弹出「共享 / 移动 / 删除 / 置顶 / 锁定 / 复制」(changed_px=14753)。 注意:工具 schema 要宿主重启 MCP 进程才会出现button(control/mcp_server.py0.3.1)。 - 关闭上下文菜单别点看起来“空白”的地方:iOS 的菜单项是整格命中,不是点文字才生效。 2026-10-23 复核:右键备忘录列表第一条 → 菜单顶部一行三格「共享 / 移动 / 删除」(删除在右上格), OCR 中心
删除=(0.834, 0.406),面板右缘到x≈0.95;当年误点的(0.88, 0.42)虽然看起来像面板右上的空白,却正好落在删除格里(该格约x 0.73–0.95, y 0.36–0.47), 所以当场删掉一条备忘录是真的(已按 §5 的“文件夹移动法”恢复)。 关闭菜单用esc(本轮实测可关)或点远离面板的空白(如最下方y>0.85); 不要点面板内部/边缘的任何“空白”。 - aim 会误判,别迷信
pointer_err≈0:底部区域实测实际落点比目标低约 30 px, 但pointer_err只有 1.0 px——它把界面里的灰色圆/阴影当成了指针。y>0.9、小图标、或同一目标连续changed=false时,把目标上移 0.02–0.03 再点,并重新截图核对。 - 滚轮其实能用(2026-10-22 实测,iPhone iOS 18 / 内嵌网页文章):
scroll N 0会让页面动, 但每份报告只走约 4–8 px(图像对齐实测:5 次 ≈ 42 px),且 N 的大小被忽略 (-1 / -5 / -20 位移一样),连发才累加。好处是没有惯性,发完停 0.25 s 就能截图。 所以:整屏翻页仍用分段拖拽(dy);微调走scroll(fine=N)。旧文档「iOS 不认滚轮」是错的。 - 滚轮方向与
dy相反(已修):固件scroll +N实际是「页面向下」——设置列表和内嵌网页列表 都验证过(2026-10-22 复测)。工具层已把scroll(fine=…)取反,与dy统一为「正数 = 更早/向上」。 个别表面(视频、部分 WebView)若方向相反,用 设置 → 交互 → 滚轮方向 翻转,别改代码。 - 滚轮跟着指针走:iOS 只滚「指针下方」的滚动视图。指针停在底部工具栏/空白处时,滚轮一份报告都不生效 (实测
moved_px=0);scroll(fine=...)会先把指针停到屏幕中央再滚。自己发scroll命令时别忘了这步。 - 拖拽/滚动松手前必须停住:抬手那一刻 iOS 会按最近的速度结算惯性,边走边松会被当成甩动, 页面再滑一段,截图和坐标就全偏了。
drag/scroll现在松手前停SETTLE_PAUSE(1.30 s), 并且drag先快后慢(ease-out)、末尾三小步减速(0.55 s 实测仍会被判成甩动), 松手后先放 0.8 s,再按像素差连续 2 次无位移才截图(_settle_shot,最多约 3 s)。 别用字节比对——同一画面重编码后 JPEG 字节也不同,会一直等不到「相等」;自己写脚本时别省这两步。
4. 校准
- 校准前先测投屏延迟(实测中位 223–355 ms),等待时间不短于「延迟 + 80 ms」。
- 网格测试页(静态、高对比、无 hover)是最好的校准画布。
- 校准表只有一个权威文件:
~/Library/Application Support/HIDBridge/calib.json; GUI、MCP、CLI 都读它(HIDBRIDGE_CALIB可覆盖),仓库里的只是种子。 - 动作前会自动按 mtime reload;
calibration_status.stale=true说明文件比内存新,调calibration_reload。 - 校准完成后不需要重启 MCP(会自动 reload),但用
calibration_status确认measured_at已变。 实测(2026-10-22):向导写完文件后 MCP 里仍是旧表(stale=true、measured_at还是上一次), 调一次calibration_reload才生效;这次校准 latency 206 ms、点击pointer_err6–33 px。 status.calibrated以控制层calib.json的corners为准;legacy 的server_calibrated另算。
4.5 UVC 采集卡(HDMI 有线投屏)
| 现象 | 根因 | 规避 |
|---|---|---|
| 整屏绿色雪花、画面隐约可见 | 采集卡发 UYVY(2vuy),AVFoundation 的 BGRA/NV12 转换在这块 Hagibis(MACROSILICON) 上是错的 | 取原生 2vuy,自己按 UYVY 解释;ffmpeg 用 -pixel_format uyvy422 |
| 找黑边全失败,整帧都被当成画面 | 2vuy 是 Cb Y Cr Y,亮度 Y 在奇数字节 | 扫描 p[y*bpr + x*2 + 1],不要读第一个字节 |
| OCR 在 888×1920 上反而更差 | Apple Vision 对大字号不敏感 | 送 OCR 前缩到 ~600 宽;坐标仍归一化 |
| 画面横过来了 | 采集卡的「竖屏模式」把竖屏内容旋转 90° 塞进 1920×1080 | 不要只靠宽高比(真横屏 App 也是 2.17)。按「文字行横竖 + 时钟在不在上半屏」判定:uvc-frame --rotate ocr 自动转,orientation() 可复核 |
| OCR 四个方向都能读出字 | Apple Vision 对旋转文字有一定识别力 | 用 bbox 的宽>高 判横排、HH:MM 的 y<0.5 判正立,别用「文字总量」当方向分 |
| 第一帧有撕裂/上半屏噪声 | 刚 startRunning 时的半帧 | 丢掉前 2 帧再发 |
| 拔掉采集卡后画面变成「摄像头看到的房间」 | 旧逻辑取「第一个外部摄像头」兜底,iPhone 连续互通相机也是 external,被当成了采集卡 | 只认 modelID 含 uvc 的外部设备,并排除 FaceTime / iPhone / iPad;找不到就报错退出,不申请权限、不回退摄像头 |
同一个 key 在 Windows 上行为不对 | cmd 在 Windows 是 Win 键;策略按平台区分 | 统一写 gui,先 keymap_check(platform="windows"),别用 iOS 经验套 |
| F1–F12/Home/End 发不出去 | 固件 < 0.6.0 没有这些键 | 升级到 0.6.0(本机已升级);老固件会返回 firmware_unsupported,不要重试 |
| 换视频源后点击整体偏 | 不同源的画面尺寸/裁切不同,旧档案是按分辨率存的 | 档案键改为 源:分辨率(airplay:500x1080、uvc:888x1920),切源时按 X-Video-Source 自动启用;没有对应档案就不会乱用别的源 |
| 双开时只有一路有实时画面 | iOS 同一时间只维护一个外接显示/镜像会话:接了 HDMI 再开 AirPlay 镜像,另一路会停在最后一帧(或反之)。live 只代表 UVC 有 TCP 连接,不代表有帧 | 所以不做自动切换:手动选源,另一路只做监视。界面按内容变化标「实时 / 无更新 Ns」,冻结的格子边框变琥珀色。 |
| 采集卡插着但 HDMI 没接,AI 仍把它当画面 | 采集卡会输出纯色/「无信号」底图,live 仍为 true | 缩略图灰度标准差 < 6 连续 3 秒 → signal=false 并提示;不会自动换源(需用户手动切) |
| 拔卡后插回不恢复 | 旧 helper 进程不退出,AVCaptureSession 跟着设备一起死了 | 看门狗:5 秒无帧且 isConnected=false → 退出码 3;服务端每 10 秒重试,插回后自动重建(实测 10 秒恢复) |
日志里出现两套 AirPlay receiver started / UVC capture started | GUI 刚启动、:8890 还没监听时,MCP 宿主拉起 --mcp,旧逻辑会自己再起一套服务端 | 0.9.4 起用 server.lock + 先等 2 秒;抢不到锁就等对方的 API |
| App 请求相机不弹窗、直接拒绝 | hardened runtime 的 App 缺 com.apple.security.device.camera 权限,TCC 的规则是「缺少权限就不弹窗」 | entitlements.plist 加 camera;Info.plist 加 NSCameraUsageDescription,两者缺一不可 |
实测日志(2026-10-21):
service: kTCCServiceCamera requires entitlement com.apple.security.device.camera but it is missing … Policy disallows prompt … access denied
5. 数据安全(真实踩过)
- 误删备忘录:
文件夹 → 最近删除 → 编辑 → 选中 → 文件夹图标 → 备忘录可恢复(30 天内)。 iOS 17 的“最近删除”没有单独的「恢复」按钮(只有 移动/删除),别去找;实测 2026-10-23 这条路径有效(abc123 27 → 26 → 27,最近删除 2 → 1)。 - 不要凭截图判断文本被改:长行会软换行,看起来像被回车拆开;让用户确认或选中复制比对。
- 修改用户数据(笔记、联系人、设置)前先得到明确同意;测试内容写在自己的测试笔记里。
- 不要长按敏感页面(备忘录/密码/邮件):iOS 的预览卡片会明文展开正文,截图会进模型上下文。
6. App 兼容矩阵(持续更新)
| App | 投屏 | 点击/输入 | 备注 |
|---|---|---|---|
| 信息 | ✅ | ✅ | 收件人要点建议项变成 +86 标签;Tab 切正文 |
| 备忘录 | ✅ | ✅ | 绘图入口 = 底部圆形「A」;画布内 press → move → release 画线 |
| 计算器 | ✅ | ✅ | 按键大,适合验证坐标 |
| 设置 | ✅ | ✅ | 键盘布局在「通用 → 键盘」 |
| 相机 | ✅ | 未测 | |
| 网格测试 App | ✅ | ✅ | 适合校准画布 |
6.2 圆角参数(按屏幕,实测后填)
python control/measure_corners.py --device "设备 / 系统"会把结果写进control/corner_profiles.json;下表只做人读汇总。不同手机不要互相套用。
| 设备 / 系统 | 源:分辨率 | 四边 inset (px) | 圆角 R (px) | 实测时间 |
|---|---|---|---|---|
| iPhone (iOS 18) | airplay:500x1080 | L 7.36 / R 8.14 / T 7.22 / B 8.16 | 61.35 | 2026-10-23 13:14 |
| (待实测) | uvc:888x1920 |
这一份的 TL/BR 实测停车点与几何模型只差 1.7 / 0.5 px(模型可信); TR 偏 39 px、BL 没测到——那两个角落在状态栏电池/底部按钮的 hover 区, 检测被污染。所以档案里的四个角停车点按模型生成(inset + 0.293R),实测值只用来算半径。
6.1 设备基线(每台设备一行,实测后填)
| 设备 | 系统 | 指针 | 分辨率 | 校准档案 | 延迟 | 备注 |
|---|---|---|---|---|---|---|
| iPhone 16e | iOS 18 | 小/中 | 500×1080 | 500x1080 | ~0.2–0.35 s | — |
| iPad Air 11" M3 | iPadOS 18 | 小/中 | 500×1080(letterbox) | 500x1080 | ~0.2–0.35 s | 端到端跑通 |
| iPhone SE 3 | iOS 18 | 小/中 | 500×1080 | 500x1080 | — | Lightning 适配器供电不足 |
| 新设备 | 先按 §0.1 建基线,再补这一行 |
表里只放实测过的;换手机、换指针大小、换分辨率都要新起一档,不要拿旧行的坐标硬套。
2026-10-22 补记(2026-10-23 更正根因):有一台 iPhone(iOS 18)出现过「11 个字符永不落屏」 (
i j k l m o u 7 8 9 .)和「回车弹菜单」,同板同固件在 macOS / iPadOS 上正常。 真正原因是 辅助触控 → 指针设备 → 鼠标键 → 使用主键盘 被打开;关掉即恢复,不需要重启。详见 §2.1。
7. 一次实验的记录模板
任务:
设备/系统/指针/分辨率:
前置:status / screenshot(附路径)
动作:每一步的命令 + 前后截图
结果:成功 / 失败(现象)
根因:
规避:可复用的规则
证据:artifacts/xxx.jpg
回填:本文对应小节 + 给 AI 的操作手册 的配方/故障表。
9. 便宜板(ESP32-S3-N16R8):XMC Flash 的坑(2026-10-22 实测)
背景:XIAO ESP32S3 Plus 较贵,改用 YD ESP32-S3-COREBOARD V1.4(N16R8,¥20 级)做实验。 固件改用统一的
s3_16m_universal(见firmware/hid_bridge/src/board.h)。
9.1 烧官方 16M 镜像后无限重启
- 现象:串口每 ~0.3 s 刷一次
E bootloader_flash: XMC flash startup fail/failed when running XMC startup flow, reboot!,BLE 名不广播,App 看不到板子。 - 根因:IDF 5.4+ 的
bootloader_flash_xmc_startup()用白名单判 XMC(MFID0x40/0x41/0x50); 这颗 XM25QH128A 是 MFID0x70/ CPID0x18,不在名单里 → 被强制跑一轮复位序列 → 跑完仍认不出 → 重启。原厂固件(老 IDF,无此逻辑)能启动,可用来排除硬件问题。 Espressif 官方表态不修(esp-idf#18947)。 - 规避:
firmware/tools/patch_xmc_bootloader.py(build.sh的 16M profile 自动调用) 把该函数改成"立即返回 OK"(等价老 IDF 行为),并按 esptool 规则重算 checksum + SHA256。 对非 XMC/白名单内的芯片是恒等变换。 - 判断命令:
esptool flash-id看到Manufacturer: 20 / Device: 7018即可确认。
9.2 用 App 刷机会报串口噪声
- 现象:
Invalid head of packet (0x81/0x30): Possible serial noise。 - 根因:这块板的 CH343 链路在 460800/921600 下不稳。
- 规避:刷机用 230400(
app/core/firmware.py已改默认值;115200 也稳)。
9.3 NVS 配置写不进去(已解决,2026-10-23)
- 现象:串口
cfg<...>回ok saved、cfg?当场能读回,但重启后配置丢失, Wi-Fi 不会自动连。表现为"配了网,一断电就没了"。 - 根因:Flash 模式不匹配。Arduino-ESP32 核心默认按 QIO 编译;这颗 XMC 的 状态寄存器写不进去(启动日志
Failed to set QIE bit, not enabling QIO mode), bootloader 把 MMU 回退到 DIO,但运行期esp_flash_read仍按 QIO 发读命令 → 读数据分区一律返回0xFF。写是好的,所以"写成功、读不到"——NVS 的 CRC 校验失败, 键等于不存在。 - 判定方法:在固件里
esp_partition_write64 字节后立刻esp_partition_read, 比较是否一致(match=0+back=ffffffffffffffff即是本问题); 同一地址用 esptool 读却是对的 → 证明"写没问题,固件读路径坏了"。 - 规避:16M 通用镜像显式用
FlashMode=dio编译(firmware/build.sh已固定)。 注意:只给 esptool 加--flash-mode dio改镜像头不够,必须重编译 bootloader。 - 验证:
flashprobe→match=1;probe→ 同句柄/重开句柄都能读回;cfg写 → 重启 →cfg?仍在。 - 顺带修掉:
ConfigStore::save()原先不检查put*返回值,写失败也回ok saved(App 会显示"已保存")。现在写后回读校验,失败返回err nvs write used=.. free=..。
8. 待解问题
- 多设备/多分辨率下,如何自动判断“这张校准表不适用”(目前靠计算器验证 + 人工判断)
- UVC 采集接入后,AirPlay 相关的坑是否全部消失
- App 投屏保护能否自动探测(打开后 2 s 内帧是否更新)
- 长按/拖拽的边界(分享面板、输入框选区)
本页内容与安装包内文档同源,版本见 VERSION.txt。未在页面上展示的细节,可在 Releases 页下载的 DMG 中找到完整原文。