Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/research/qt-ime-candidate-panel-reference-2026-11-01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Qt 终端候选框与官方 WindTerm 2.7.0 的固定时间点对照(N11)

[#155](https://github.com/JavaZeroo/termforge/issues/155) 的候选框剩余验收:在隔离 Windows 11 固定微软拼音下,
把 TermForge 冻结源(Qt,5fab30b)与官方纯 WindTerm 2.7.0,在同一条输入轨迹、同一组固定采集点做候选框几何对照。
原始 OS 截图、采集器与受控端身份、本地账户/口令/PID 只留私有,本页只发布脱敏几何结论与哈希。

采集时间约 2026-11-01(Asia/Shanghai);环境即 [docs/research/r2-win11-display-environment.md](r2-win11-display-environment.md) 的同一台自有 KVM/QEMU Windows 11 x64 guest。

## 采集协议(N11)

- 合成会话:每个产品各自打开一个 cmd 会话,运行一个最小的受控输出程序(打印就绪行后等待外部触发)。
- 输入轨迹:`SendInput` 依次 `N I H A O`(触发固定微软拼音的 `ni'hao` 组合),随后受控输出 6 行纯文本、窗口 resize +96/+48、一次 Ctrl+= 字体放大,最后 Escape 取消。
- 固定时间点:每个阶段(组合期 / 输出后 / resize 后 / 字体后)各采集即时与延后两张全屏图;延后为即时采集返回后 ≥250 ms(实测 252–269 ms)。250 ms 只是采集方法,不是通过门槛。
- 候选框几何:同一采集器 `n11-capture.cs` 对全屏 BitBlt 图做确定性「密集亮度带」检测(行 ≥300 个 ≥240 RGB、其中存在 ≥200px 窗口 ≥75% 亮、连续 ≥14 行成带,再以种子 flood-fill 取精确亮区)。候选面板在组合期表现为窗口标题带下方新增的 2 条亮带。
- 身份:Qt 侧 `side=termforge-frozen-5fab30b`(`qt_ime_input_test.exe`,TextInputHost 渲染候选窗),WindTerm 侧 `side=official-windterm-2.7.0`(`WindTerm.exe`)。

## 采集样本与几何结果

候选面板矩形 = 组合期新增亮带的并集(物理屏幕像素,主屏 1024×768、96 DPI):

| 阶段 | Qt(3 次一致) | WindTerm 2.7.0(3 次) |
|---|---|---|
| 组合期(preedit) | `[73,108,711,142]` | `[373,232,1011,266]` |
| 输出后(即时/延后) | `[73,108,711,142]`(不变) | `[373,232,1011,266]`(不变) |
| resize 后(即时) | `[181,196,819,230]`(已更新) | run0 已更新;run1/run2 仍 `[373,232,1011,266]`(旧位置) |
| resize 后(延后) | `[181,196,819,230]` | `[373,340,1011,374]`(已更新) |
| 字体后(即时/延后) | `[181,196,819,230]`(不变) | `[373,340,1011,374]`(不变,但屏幕本身未见变化,见下) |

各产品面板的绝对位置不同是终端布局差异(光标锚点在屏幕上的位置不同),不是行为差异;对照的是同一轨迹下是否更新、何时更新。

## 结论

1. **输出后候选框不移动 = 原版一致。** 输出后即时与延后两个点,Qt 与 WindTerm 2.7.0 都把候选框保持在与组合期相同的位置。N10(#155 评论)观察到的「输出后固定延后点仍在旧位置」在官方 WindTerm 2.7.0 上同样成立,不是 TermForge 特有缺陷。
2. **resize 后候选框会更新,两产品一致(仅时序有差异)。** Qt 3/3 即时更新;WindTerm 1/3 即时、2/3 在延后点才更新(WindTerm 自身逐次不一致,属帧/调度时序,非产品行为差异)。两者都在延后点前到达新位置,不存在「持续不更新」。
3. **字体放大阶段不可直接对照。** Qt 侧 Ctrl+= 产生了可见变化(前后 PNG 不同)但候选框未动;WindTerm 侧同样的合成 Ctrl+= 没有产生任何可见变化(前后 PNG 逐字节相同),即官方 WindTerm 2.7.0 在该合成输入下未触发字体放大。因此「字体变化后候选框不更新」只在 Qt 侧实测,WindTerm 侧因放大未触发而未验证/不可比,保持未知。

总判断:N10 的「输出/字体变化后候选框仍在旧位置」在输出阶段与官方 WindTerm 2.7.0 一致(原版一致),不构成需要改产品行为的缺陷;字体阶段因原版放大未触发而保持未知。resize 阶段两产品都更新(原版自身有延后帧),不存在 TermForge 独有滞后。

## 归档(全部私有,仅哈希公开)

| 归档 | 字节 | SHA-256 | 文件数 |
|---|---|---|---|
| qt-ime-n11-qt-0.zip | 2025455 | 0c6829cfa93ea4083933c8c122f292da028e89c6a19b4823f8085aa41b3add4c | 112 |
| qt-ime-n11-qt-1.zip | 2322587 | da78f6f8e9ddfa252fd20979b720aa3a9abc42970a3cf5f80b2a3fcbdd24b72a | 117 |
| qt-ime-n11-qt-2.zip | 2332066 | a8a03aaf9cf0cf46af010288fa66891372dc2f68e114044820b7250e5224f5f7 | 114 |
| windterm-n11-orig-0.zip | 5230029 | 342101c30fa19a53893fab14c2601848dc9b62c6707e56ab835e4fc847636610 | 34 |
| windterm-n11-orig-1.zip | 6523389 | 27aa5c9e73e3d14fb4f1b2b4911c845eda15f46afd4ed0f0dcd58c93c4100f7f | 40 |
| windterm-n11-orig-2.zip | 6510251 | a959baf89ed0fb5f2b60b46f54b712681930da344dfbb2f798ddadf0f685e6e8 | 40 |

每个归档内含 `controller-record.json`(完整输入、即时/延后采集、密集带宽矩形与 PNG 哈希)、`snapshots/*.png + *.json`、`flags/*`、`user.sessions.before.txt`。全部 6 个归档已逐文件解压并与各自 manifest 逐项核对 SHA-256,0 不匹配。

样本数:Qt 3 次共 38 次采集(12/13/13),WindTerm 3 次共 45 次采集(13/16/16);每侧各 4×3 = 12 个几何配对。

## 已知边界与开放项

- WindTerm 3 次的 `controller-record` 状态为 `failed`:失败点都在收尾关闭阶段(自动化 Ctrl+W / WM_CLOSE / 对话框确认 / SC_CLOSE 之后官方 WindTerm 2.7.0 未在预算内退出),四个几何配对在失败前都已完整采集,不影响候选框几何结论;这本身是 WindTerm 2.7.0 的自动化关闭行为,不是候选框差异。
- 字体阶段原版放大未触发(未知,需换触发方式或确认官方 WindTerm 的 Text.ZoomIn 快捷键映射)。
- resize 阶段 WindTerm 的即时/延后不一致(2/3 延后更新)未定位到具体成因,只归为时序差异。
- 候选框「身份/关联」仍非本页结论:本页只用密集亮度带作几何位置,不含窗口句柄的候选框归属证明。