6.8 KiB
6.8 KiB
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_POINTcomposition setter 与CFS_EXCLUDEcandidate 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失败丢弃记录。
- 0B 人工 runner 固定窗口为
- 涉及文件 / 类 / 函数:
src/StellarX/SxInputProbe.cpptests/UiFixture.cppscripts/run-input-consume-probe.ps1scripts/run-input-consume-probe-manual.ps1scripts/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 或键盘路由。