Files
StellarX-kaifa/开发记录/Fix/Fix-BUG-20261006-0001-IME锚点变化时预设候选框位置.md
T

6.4 KiB
Raw Blame History

Fix-BUG-20261006-0001

适用场景:记录某个 BUG 的修复方案、影响评估、验证结果与落地信息。

关联信息

  • Fix ID: Fix-BUG-20261006-0001
  • 关联 BUG ID: BUG-20261006-0001
  • 修复目标: 不依赖 IME 必须先发送组合生命周期消息,在锚点变化时立即预设候选框和组合窗口位置
  • 状态:已验证
  • 负责人: Codex
  • 分支 / 版本: master,修复实现提交 43cf4ac(起点 225bc35)

根因分析

  • 根因: 探测器只在 WM_IME_STARTCOMPOSITION/WM_IME_COMPOSITION 到达时调用 ImmSetCompositionWindow/ImmSetCandidateWindow。非组合态按 F1/F2/F3 时仅记录 anchor_change,导致下一次组合开始前 IME context 仍保留默认位置或上一个锚点位置。
  • 触发条件: 搜狗候选 UI 已出现,但目标 EasyX HWND 没有收到探测器预期的组合生命周期消息;或者生命周期消息晚于候选 UI 首次定位。
  • 为什么微软拼音测试未暴露: 微软拼音在此前人工测试中会为三个锚点产生可观察的组合生命周期消息,恰好触发原有设置路径;这不能证明其他 TSF 输入配置文件也遵循相同时序。
  • 关键证据: 失败运行中 F1/F2 的 IMM API 尝试次数均为 0,F3 为 2/2;截图与事件序列一致。

修复方案

  • 修复思路: 采用“双时机定位”。锚点变化时立即向当前 HWND 的 IME context 写入位置,生命周期消息到达时再次校准。
  • 关键改动:
    • F1/F2/F3 WM_KEYDOWN 立即调用 IMM 定位,并把该次调用标记为 positionTrigger=anchor_change、stage=anchor_preconfigure。
    • 探测专用 F1/F2/F3 在完成锚点切换后返回 0,避免旧窗口过程或输入法把功能键解释成其他行为。
    • WM_IME_STARTCOMPOSITION/WM_IME_COMPOSITION 保留二次定位,并标记为 positionTrigger=ime_lifecycle。
    • raw event 增加 compositionActiveAtAttempt,分析器分别统计预设调用和生命周期调用。
    • 自动完成条件除三个锚点均至少有一次成功定位外,还要求本轮至少有一个真实 IME 生命周期定位事件完成 context 获取与两个 setter;仅按三次功能键或只观察到失败的生命周期调用不能伪造完整通过。
  • 涉及文件 / 类 / 函数: tests/visual-probe/ImePositionProbe.cpp、scripts/analyze-visual-probe.ps1。
  • 影响的 API / 行为: 仅改变诊断探测器;不修改当前生产框架的 WndProc 或控件行为。
  • 关键约束 / 不变量:
    • 坐标仍使用目标 HWND 客户区坐标,不新增 DPI 缩放。
    • CFS_POINT 与 CFS_EXCLUDE + caretLineRect 组合保持不变。
    • API 成功只证明位置请求被接受;最终候选框位置仍必须由人工截图验收。
  • 回滚点 / 开关: 可单独恢复 F1/F2/F3 的只记录分支,但会恢复搜狗首次定位和 stale-position 问题。

影响评估

  • 影响范围: EasyX.VisualProbe 的 IME position 模式及 manifest 字段。
  • 兼容性影响:新增字段为向后兼容扩展;分析器对旧 raw event 继续通过 stage 推断生命周期来源。
  • 行为变化:F1/F2/F3 成为探测器内部专用且被消费;每次锚点变化都会立即产生一条位置设置事件。
  • 性能影响:每次人工切换锚点增加一次短生命周期 ImmGetContext、两个 IMM setter 和 ImmReleaseContext,只存在于诊断程序。
  • 回归风险:
    • 某些 IME 可能接受预设调用但随后主动调整候选框;必须保留截图和 positionDisposition 人工判断。
    • 若只看 API 成功次数,可能把未实际输入的运行误判为完成;因此额外保留至少一个生命周期事件门槛。

验证结果

  • 验证步骤:
  1. 构建 EasyX.VisualProbe 的 Debug x64、Release x64 和 Debug Win32。
  2. 检查 Windows PowerShell 5.1 与 PowerShell 7 对分析脚本的解析结果。
  3. 用历史失败 raw 重放 analyzer,确认 F1/F2 仍失败、F3 仍通过,并纳入三张人工失败截图。
  4. 执行仓库单元测试和 git diff --check。
  5. 使用搜狗重新执行 F1/F2/F3 真实输入,确认三处候选 UI 均跟随当前锚点,提交一次后再次切换也不沿用旧坐标。
  • 当前验证结果:
    • EasyX.VisualProbe Debug x64、Release x64、Debug Win32 均构建成功;仅保留 EasyX 头文件既有的 C4201 匿名联合警告。
    • Windows PowerShell 5.1 与 PowerShell 7.6.5 对 analyze-visual-probe.ps1、run-visual-probe.ps1、test.ps1 的 AST 解析均为 0 错误。
    • Debug x64 单元测试 15/15 通过。
    • 历史失败 raw 重放后仍保持 automatedStatus=fail:F1/F2 为 0 次定位尝试,F3 为 2/2;三张失败截图已纳入 manifest,evidenceCount=6,manifest SHA-256 为 0AE37CB4D1B9B2D91A7625E0A3ADA5C4FA9B44C1671CA055EA84965D03F2D1E8。
    • 人工失败截图哈希分别为:F1 5D54508C93385C07D10E9A347CA3443D750F81F4A1EF31E6D09C24692666D852,F2 7FE71CBB96DFD04301D1E7BD13ACB90CF6DFB2DBEB5F1E0DAEAD8AB1648D5B8D,F3 stale-position 55DF55E86D7F4DE83AFB1901CEA23FBE825A04D6C2D857447530D0F39646480A。
    • 搜狗修复后真实运行 20261006-010231-219-3fc5186a-f494-4d88-8988-67d80b25ed7e 自动状态与人工状态均为 pass;F1 预设 2/2、F2 预设 1/1、F3 预设 1/1 且生命周期校准 2/2。
    • F1 初始截图与“F3 提交后重新回到 F1”截图裁剪结果字节一致,SHA-256 均为 230C2C260174AD4B45F95E97AF27CC4C0DF37105F9DB960EFBC6C1CFE6A2EC11,确认不再沿用 F3 stale position。
    • 成功运行 manifest SHA-256 为 4908B1F9B5C29555216EF62BE64F2F6780F7EF213D8E1ECE16817B5915FF9AED;人工评审旁车 SHA-256 为 94459F19A3F74E46C23322E6276C03B3AF054D6293DA4D090220FF06470A32A3,sidecar 校验匹配。
    • analyzer 已验证人工 review 覆盖三个用例、逐用例证据归属和总体状态推导;使用临时副本把 F2 review 指向不存在的截图时,analyzer 按预期拒绝生成 manifest。
    • 人工评审机制落地后再次执行 Debug x64 单元测试,15/15 通过。
  • 回归检查: 微软拼音定位行为需在最终收口前确认未退化;阶段 6 仍须使用真实 TextBox anchor 集成复验。
  • 验证证据: 修复前失败运行 20261005-235150-704-4e01df99-019b-41bd-b8ea-b2ff508626e0;修复后成功运行 20261006-010231-219-3fc5186a-f494-4d88-8988-67d80b25ed7e。

落地信息

  • Commit: 43cf4ac
  • PR:无
  • 发布版本:未发布
  • 备注: 失败截图位于忽略目录 TestResults,文档只记录相对路径、事实与证据边界。