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

6.8 KiB
Raw Permalink Blame History

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 或键盘路由。