Files
StellarX-kaifa/开发记录/Fix/Fix-BUG-20261006-0002-阶段0B固定锚点原生键规则与无丢失采集修复.md
2026-10-07 04:09:36 +08:00

75 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fix-BUG-20261006-0002
> 适用场景:记录某个 BUG 的修复方案、影响评估、验证结果与落地信息。
## 关联信息
- Fix ID: Fix-BUG-20261006-0002
- 关联 BUG ID: BUG-20261006-0002
- 修复目标: 让阶段 0B 的真实 IME 实验具备可比较的位置基线、可命中的原生键规则和不因状态锁竞争主动丢记录的采集路径
- 状态:验证完成
- 负责人: Codex
- 分支 / 版本: `master`,未提交工作区
## 根因分析
- 根因 1: 0B 复用了只显示说明文字的 UiFixture 场景,没有把 0C 已验证的 caret point/line rect 写入当前 HWND 的 IME context。
- 根因 2: 规则按操作者语义配置为 `VK_ESCAPE`,但 IME 在 WndProc 前已处理组合态 KeyDown,窗口实际收到 `VK_PROCESSKEY`;scan code 1 才保留了本轮 Escape 的物理区分信息。
- 根因 3: 单环形缓冲在 safe-point 持锁复制,WndProc 为避免等待使用 `TryAcquireSRWLockExclusive`;宿主复制期间到达的原生消息会被主动丢弃。
## 修复方案
- 修复思路: 保持 0B 动作枚举只有 Forward/Consume 两值,仅修正诊断输入、位置基线和采集完整性,不新增生产路由行为。
- 关键改动:
- 0B 人工 runner 固定窗口为 `720×420`,传入客户区 caret `(225,282)` 与 line rect `(200,255)-(680,284)`。
- UiFixture 绘制与上述数值一致的 line region 和 caret marker,便于操作者判断候选 UI 是否仍落在窗口外。
- 在 `WM_SETFOCUS`、`WM_IME_SETCONTEXT`、`WM_IME_STARTCOMPOSITION`、`WM_IME_COMPOSITION` 观察点准备定位请求;锁外调用 `CFS_POINT` composition setter 与 `CFS_EXCLUDE` candidate setter,通过独立 `ime_position` 记录保存 context、两个 API 结果和坐标。
- Composition 请求 Consume 时,如果尚无一次两个 setter 同时成功的证据,立即 fail-open 为 `ime_position_unavailable`。
- 规则新增可选 `scanCode`。自动 F24 仍使用 any;人工 Escape 默认使用 `WM_KEYDOWN + VK_PROCESSKEY(229) + scanCode 1 + ComposingOnly`,界面指令仍要求操作者按 Escape。
- 分析器在指定 scan code 时同时过滤 WndProc 与 EasyX `EX_KEY`,并输出位置尝试/成功计数和 `imePositionReady`。
- 记录缓冲改为两个固定数组;safe-point 在锁内只交换 active buffer 和重置索引,文件写入在锁外完成。WndProc 使用极短阻塞临界区,不再因 `try-lock` 失败丢弃记录。
- 涉及文件 / 类 / 函数:
- `src/StellarX/SxInputProbe.cpp`
- `tests/UiFixture.cpp`
- `scripts/run-input-consume-probe.ps1`
- `scripts/run-input-consume-probe-manual.ps1`
- `scripts/analyze-input-probe.ps1`
- 影响的 API / 行为: 仅 `STELLARX_ENABLE_INPUT_PROBE` 且显式开启 0B 的诊断路径;公共 API 与默认生产窗口行为不变。
- 回滚点 / 开关: 不设置 `STELLARX_INPUT_PROBE_0B` 时不装载规则、不调用固定位置逻辑;默认构建不包含探测实现。
## 影响评估
- 正确性: scan code 消除同一 `VK_PROCESSKEY` 下字母、方向、Escape 等多类组合键的歧义;固定位置成功门槛防止把夹具定位失败算成消费副作用。
- 并发: 双缓冲消除宿主批量复制对 WndProc 的长时间占锁;文件写锁仍串行化多个 flush,状态锁序保持“文件写锁 → 状态锁”。
- 性能: WndProc 每条被观察消息增加一次短阻塞状态锁;Composition 生命周期增加有限的 IMM32 setter。两者只存在于诊断构建。
- 风险:
- 某些 IME 即使 setter 返回成功也可能自行调整候选 UI,因此仍需人工视觉确认。
- WndProc 阻塞临界区要求 safe-point 严禁在状态锁内做文件 I/O 或整批复制;后续维护若破坏此不变量可能重新引入卡顿。
- 首次人工复验发现持状态锁调用 IMM32 setter 会因同步重入 WndProc 自锁;已拆分为“锁内请求 → 锁外调用 → 锁内结果”并增加线程内递归定位保护,详见 `Fix-BUG-20261006-0003`。
- `VK_PROCESSKEY + scanCode 1` 是当前环境观察到的原生 Escape 形态,不得未经新证据外推到全部 IME/键盘布局。
## 验证结果
- 已完成:
- Debug x64 探测构建完成编译与链接;仅有 EasyX 头文件既有 C4201 警告。
- 失败截图已复制到对应忽略运行目录并记录 SHA-256。
- 默认 Debug x64 单元测试 15/15 通过。
- Windows PowerShell 5.1.22000.2538 与 PowerShell 7.6.5 对三份 0B 脚本均为 0 个 AST 解析错误。
- `git diff --check` 通过,仅输出仓库换行规范提示。
- 新分析器重放既有有效 F24 KeyDown A/B:Forward 仍为 `valid/present_once`,Consume 仍为 `valid/absent`,兼容未携带 `targetScanCode` 的既有 schema v2 日志。
- `BUG-20261006-0003` 修复后的微软拼音 Forward 人工复验为 `valid`:Escape 原生规则唯一命中并转发,18/18 次定位成功、零孤立结果、零丢失,人工截图确认候选 UI 位于固定锚点附近。
- 微软拼音 Consume 有效重跑为 `valid`:Escape 唯一命中并消费,旧过程未调用,对应 EasyX 键消失;7/7 次定位成功、零孤立结果、零丢失且无提交结果。
- 搜狗 Forward 运行确认候选 UI 可见且位置正常,但目标 HWND 未出现 START/COMPOSITION/END;Escape 到达时 tracked state 仍为 Idle,`ComposingOnly` 零命中,定位 6/6、零丢失、收口完整。
- 搜狗最终 Consume 请求按 `ime_condition_not_met` 正确运行时 fail-open:`experimentValidity=runtime_fail_open`、零消费、实际 Forward 一次、EasyX 键出现一次、定位 3/3、零丢失,最终 verdict 为 `MustForward`。
- 2026-10-07 默认 Debug x64 单元测试 15/15、UI fixture 1 轮和 F24 KeyDown A/B 新运行通过;既有 KeyUp 与 baseline mismatch 证据经当前分析器回放保持有效。
- 当前工具环境限制: 自动 F24 runner 已完成构建并打开夹具,但 Codex 非交互工具宿主无法把窗口切到前台,`ClickWindowForActivation` 在发键前失败;该运行没有形成新的 A/B 结论,不记为代码失败,也不覆盖既有有效证据。
- 首次微软拼音复验边界: 旧定位实现导致窗口未响应,失败运行保留于 `TestResults/InputProbe/0B/20261006-231604-636-4bc775a1-a3f8-41b9-b466-1cce740bc195/forward`;该运行只证明诊断死锁,不用于评价 Forward 或微软拼音。
- 验证边界: 自动 `SendInput` 不能替代真实 IME;搜狗不能被要求“规则唯一命中”,因为缺少可证明 Composition 状态时正确行为就是零命中并 fail-open。该 Fix 以固定定位链、原生键观察、零丢失和明确 `MustForward` 结论关闭,不把运行时 Forward 伪装成 Consume。
## 落地信息
- Commit: 待验证与用户确认后提交
- PR:无
- 发布版本:未发布
- 备注: 本修复不进入阶段 1,不实现 FocusManager、生产 InputCollector 或键盘路由。