## 实现已合入,剩余为验收(2026-11-01) Qt IME组合/提交/取消由#205(dea6065)和#230(a44bd2c)进入main;旧PR165已关闭,不再列为“待合入实现”。固定微软拼音已有preedit→cancel→commit“你好”精确6B的限定证据。父项#30。 ## 最新原版对照 [N11报告](https://github.com/JavaZeroo/termforge/blob/main/docs/research/qt-ime-candidate-panel-reference-2026-11-01.md)已由#302合入。每侧3次,Qt为历史冻结5fab30b,官方WindTerm2.7.0:输出后即时/延后点都保持候选面板旧位;resize后延后点都更新。**不能继续将输出后不动列为TermForge独有故障**。 字体阶段原版合成Ctrl+=未触发可见放大,无法比较;密集亮度带只支持候选面板几何观察,没有证明窗口身份/归属。原版运行收尾失败保留,不称整次native通过,presented_done仍未知。 ## 剩余验收 - [ ] 明确候选窗身份/关联及覆盖边界;几何识别不能替代归属证明。 - [ ] 先确认原版字体放大的有效操作,再做组合期字体变化对照;不能把未触发算不跟随。 - [ ] 区分组合期Ctrl-C实际交付、provider消费和child字节,未知继续保留。 - [ ] 在当前正式源/包完成组合与输出、resize、字体、焦点/切换、隐藏、关闭/错误交叉,核对preedit不写入、commit不重复、cancel零字节及目标隔离。 - [ ] 与#30/#35连接单屏96/144及实际glyph/交互验收,保留构建身份与所有失败;旧5fab结果不直接验收当前main。 [Qt入口](https://github.com/JavaZeroo/termforge/blob/main/src/qt/README.md) · [固定拼音](https://github.com/JavaZeroo/termforge/blob/main/research/ui/results/2026-10-30-qt-ime-fixed-pinyin/README.md) · [N11原记录](https://github.com/JavaZeroo/termforge/issues/155#issuecomment-6556346789)。 本项保持开放。N1–N10、构建监督残留及原版关闭失败均保留各自证据;台账刷新不改变它们的结果。
Activity
JavaZeroo commentedon Oct 28, 2026
已执行一次冻结 N1 原生观察,source
194101a9bc2bf1fe22cba2479677b7f3bcf30a49,runtime ZIP SHA5caf0fc14b18069280dd2a43971577f5cc24ffa9de427ddfebd46df372426899,root plan SHA80ede34f0318a5910378857ce4b3c0aef61990f321f914f871fb10a772c09006。结果为 执行前置失败,SendInput 批次0,不是IME功能通过或失败:两个接收端已ready,但 controller 的一次SetForegroundWindow返回false,故在真实输入前停止,无自动重试。目标 Qt GUI 线程在本次保留采样中
GetActiveProfile=S_OK、固定微软拼音/provider/profile、语言2052、active flags3、HKL8040804;Qt has_focus/ImEnabled为true,IMM open=false、conversion1。这些各自只是观察值,线程焦点不代替全局前台,IMM open也不代替TSF转换是否可用的结论。未取得提交/取消/Ctrl-C/候选关联的功能证据。controller 对精确自有 Job 发起一次终止后,root已reap,Job0/5/0、cleanup verified;接收端没有自然完成/complete.json。外层70s监督未超时、未强杀,自然CLI1、Job0/11/0。7207源/依赖、158旧原件、89 lifecycle原件前后零变;旧0db包、r1/r2草稿及本次失败均保留。
之后独立只读环境探针看到 Session1 的 WinSta0/Default 与输入desktop Default(Job0/4/0),不支持该时刻已切Winlogon的假设;它不能倒填N1瞬间的拒绝原因。接续仅调查前台授权/实际FG和TSF只读状态,不重跑原批次。最终full尚未执行,#155/#30/#31保持开放,native acceptance与实际呈现仍null。
JavaZeroo commentedon Oct 29, 2026
N2已按新source
0deb19bf4da73a1cc0e82f398925c540da7edb55唯一执行并停止,仍为 0个输入批次 / 0次Shift / 0截图,不判IME功能。与N1不同,实际全局foreground已是exact Qt root,故正确跳过SetFG/鼠标;随后首次读取仍由receiver写入的native-a.bin时,采集器File.ReadAllBytes触发Windows共享冲突。接收端允许RW/Delete共享,但默认reader的FileShare.Read不允许现有writer;这是采集工具前置缺陷。精确root Job按失败路径终止一次后0/5/0、rootreaped/cleanupverified;outer自然CLI1、Job0/13/0、无timeout或外层终止。7229源码/依赖及641旧原件前后0变。原完整ZIP已本地留存,SHA
9db061b42e108e623b11e57195d866d7a64dda6a33f6c52ce9b38196d3e5c656。原N2不重跑。后续仅修共享live-reader,以合成普通文件持写句柄形成确定性RED→GREEN;postexit最终raw/receiver判据不改。新的N3必须另冻结同0deb程序、新采集器与单次计划,不通过重复旧批次取绿。最终full及真实拼音提交/取消/候选关联仍未验收。
JavaZeroo commentedon Oct 29, 2026
原生观测 N3/N4 已分别执行各一次,均保留失败,产品输入批次仍为 0;没有形成 native IME 功能结论。固定软件源为
0deb19bf4da73a1cc0e82f398925c540da7edb55,打包 EXE SHA256fb3df045ddd8654af4cfbf70d6aa4820553385aa4b742075282e89346d7cd596。N3 在首张全屏 PNG 超过原采集上限时停止;N4 仅修正采集 ROI 为自有窗口与 monitor 交集,实际 976×679、662704 像素,PNG 编码完成为 2123283B,仍超过工程采集上限 2097152B,因此首张未保存、输入/Shift/候选结论均为0/0/unknown。实际 Qt GUI 线程处于固定微软拼音 profile、IME open=true/native conversion1025,借用输入上下文已释放;这只是运行环境观测。
N4 保留失败 metadata,exact owned root Job 请求一次终止后 root124、reaped、Job0/5/0,outer CLI1自然退出、Job0/13/0,无 outer timeout/强制清理。源/Qt/ConPTY/CRT共7229项及先前641文件后验零变化;N2/N3/N4原ZIP已逐文件解压校验,N4 ZIP12518B/SHA256
9c7c23ab04b9cc00e86c15791d498d545f16c510509e3e12d6ad061bd52fec6c,均仅私有保留。不会重复旧case。同HEAD hosted Qt PR检查6/6、14.90s通过(run40795030570/job123189306275,offscreen);默认PR检查通过。但push默认Windows job123188586384为60/61,shell selection场景内部deadline,原因未明,不能由PR绿覆盖。下一步只修采集预算并复审,输入序列、receiver原字节oracle与原时间预算保持。#155保持开放,PR165仍draft,main尚无此实现。
JavaZeroo commentedon Oct 29, 2026
N5 一次原生执行已停止,固定source/EXE仍为0deb19b及既有身份。6批OS虚拟键N/I/H/A/O/Space,各SendInput2/2、焦点guard通过;5张实际屏幕图共2393505B。Qt收到5次非空preedit,无commit事件,两个最终私有raw均0B。原2秒阶段在 exact nihao commit 未满足,未继续B/取消/Ctrl-C/自然finish,不称native通过。
root查看原PNG,候选第一项“你好”,同时存在微软拼音“启用来自必应的建议”首次提示。该提示与Space未提交同时存在,因果未建立;先独立处理VM首次环境,不加长期限或盲重跑产品。
失败清理:exact root Job一次Terminate后root124/reaped、Job0/5/0;outer自然CLI1、Job0/13/0,无outer超时/强制终止。7229源/依赖+641原证据后验0变。40个原成员及ZIP逐SHA校验,ZIP2435732B/SHA256
6c16723b609773b4c2aaf3a043e70085fae08a4491382bb580a81b17b29a3515,私有保留。另确认PS5.1 JSON小数类型Decimal未被原Numeric-Vector接受,导致4张cursor mapping unknown;原件不改。N6草稿只补Decimal,离线执行实际Snapshot纯mapping片段,对5个冻结JSON为旧1/5、新5/5匹配字面矩形,6无效向量拒绝。这是离线分析修正,不是candidate/native验收。N6执行0、配置false,待复审及VM环境准备。
JavaZeroo commentedon Oct 29, 2026
旧正文状态留证:N1–N8 与既有 source/package 身份;由 N9 当前摘要接续,原失败不追认为成功。
最新原生进展(仍未合入 main)
PR165当前源5bbf86dc已整合main05f04d0及专用CI补线;app相关源/核心头/根CMake相对冻结C6无变化。C6实际包347136B EXE/SHA
07c19d17795da0250d26b615e7bb7ca651a67b9766074bc204d0aabf14d8a787,41文件ZIP/SHA0624f492f582d2c11abea527b5f3e19ed2c67eee3e7d5ff59384343c846375c1。独立构建与4CTest(原IME5组、console8例、normal/cancel)通过、自然Job0/176/0及0/39/0。C6首次Hosted Qt是6/6,未选择新console;新的CI已补构建和regex,结果另核,不追记成7/7。N7仅一次、10个输入批次:实际A commit事件一次UTF16
604f7d59,child准确6Be4bda0e5a5bd;B出现preedit后Escape空取消,child0B。后续回切A时private reader的FileStream构造遇共享异常,root被唯一强收尾124/Job0/5,outer自然1/0/13;无complete,未完成Ctrl-C/正常退出,整次失败。56原件逐文件验证,ZIP2549618B/SHAfcab13bf07ccfa3af0f2117f2793d907312313c5afd5179eda00aa9019f5cc66。N8仅一次、1个N键批次:新reader仅对确切HResult32做原期限内有界open重试(30项纯managed检查已过,不是原生计时证明);本次无该冲突记录,C6 observer先因native-state.json
json-commit失败退出,expected/actual均4240B、QtFileError10、错误为拒绝访问。root自然exit1/Job0/5,outer自然1/0/13,无强收尾或timeout;A/B raw均0B。21原件ZIP2153188B/SHA8b146918b6392621ce503173a7c46541c4aff87ca5819ad36d9cdf11fb063f7f。两次源7230+旧3973后验零变,另N7全部98本地文件在N8前后零变。下一步是无GUI/无IME输入的QSaveFile无reader/ReadWrite/ReadWriteDelete三模式覆盖对照。普通File.Move成功不等于QSaveFile覆盖成功;目前不得将N6唯一根因、N7/N8同根因或产品IME故障写成已证。N7照片可见字体变化后候选位置与新query不一致,异步/组合起点/provider策略及WindTerm对应行为尚未知;不先改产品策略。原生提交/取消已有上述限定事实,整项和完整candidate/焦点/终态回收验收仍开放。
当前状态:实现候选已验证,真实原生验收未通过,未合入 main
main 当前为
3aa78f068154387851ce6776a35077ec02da029e;PR165 的已发布冻结候选为0deb19bf4da73a1cc0e82f398925c540da7edb55。正式 C++/Qt/固定 ConPTY 路线不变。preedit/commit/cancel/query、目标状态和原始字节功能测试已实现,公开事件与 offscreen 生命周期验证各自绑定候选;PR Qt 首次 CI 为 6/6。push 默认 Windows 曾在 ui-copy-system 第二轮内部 30s 截止失败,已留证在 #73;另一个工作流成功不覆盖该失败。隔离 Win11 固定拼音:N1–N4 各一次前置/采集失败,产品输入为0;N5 实际 N/I/H/A/O/Space 六批均返回2/2,有5次真实 preedit,但没有 commit,raw A/B 各0字节。截图中存在必应首次启用提示,提示与 Space 未提交的因果关系未知。
N6 是独立一次观察,同一0deb包/41 runtime文件;实际 N/I/H/A/O 五批均2/2,尚未 Space、环境 click 或 continuation GO。约3.4s observer 因
native observer evidence gap主动关闭:源码与最终事件可将首发原因限定到粘滞write_failed_(JSON留证异常或PNG保存失败),原代码未保留具体操作/错误码。随后才发生 FocusOut/preedit清除和被拒收的 ASCII nihao,不能记为产品 IME 自发失败。该次截图没有必应面板,不能由此推断环境设置完成或根因消失。A/B raw仍各0字节,候选关联/实际呈现/提交与取消均未获原生验收。N6 子树自然exit1/Job0/5/0,外层自然exit1/Job0/13/0,无超时或Terminate;30份原件逐文件验证,ZIP 2247320B/SHA256
0cd20325817c795b985b44189a005a8608c2393326fbca63b0da10466708307c。7229源/依赖及641旧原件后验零变化。原始OS截图和本地标识只留私有。当前继续为观察器补首错操作与Qt错误上下文,保留原failstop;共享读句柄与QSaveFile原子替换冲突仅是假设,尚未确证。真实原生条件、最终完整矩阵和main集成仍未闭环。JavaZeroo commentedon Oct 29, 2026
N10 独立几何观察已完成,保留为未验收结果,不重跑 N9:同一冻结 5fab30b/41-file 包,只有 N/I/H/A/O/Escape 六批,返回12/12 INPUT,A/B最终均0B、commit0。四阶段各即时与延后采集,实际延后255/254/262/264ms(从即时采集返回起算,250ms仅采集方法,不是通过门槛),共10张图。
输出后的即时/延后图、字体变化后的即时/延后图中,白色候选面板均仍在旧位置;resize后可见位置更新。这里只证明这些固定采集点的现象,原因、更长时段和与WindTerm的差异尚未确定,不能写成单即时帧问题已经消失。
57个immutable packet、final57/complete精确绑定,26接受记录/20事件副本/10PNG逐项匹配;双receiver和UI自然exit0/Job0,无timeout或Terminate,外层自然exit1明确pending comparison。124-file归档1732132B/SHA
cd77ffe31ee7c30d7a07e0f23d6a5ee553655c177cbcf0b1018af31dd418a57c;独立只读机械审0 finding。7253源/依赖+5314旧保护+2858 C6 tracked后验零变,N9全部180本地文件也逐个零变。原版pure 2.7.0参考入口也已单次bootstrap尝试,但在ResumeGui之前的desktop/station查询出现空句柄,GUI/导航/IME输入均0;旧错误未区分station/current/target,确切失败调用未知。唯一仍挂起的自有root强收尾124/Job0,外层自然1/Job0(total9),无外层timeout或Terminate。它没有产生原版IME/候选对照结果。后续只补具体调用错误上下文和输入前严格desktop验证,不改产品行为。
本项/PR165继续开放和Draft,native/candidate acceptance及presented_done仍null;原始OS截图/本地身份不公开。
JavaZeroo commentedon Oct 29, 2026
原版 bootstrap 的“GUI 之前就停下”已定位到私有采集前置的确定性缺陷,并已在 VM 上验证修复前半段。
本地因果证明(合成探针):创建 suspended 的
cmd.exe后查询GetThreadDesktop(TID)返回 NULL(last_error=0);ResumeThread+ 800ms 后返回 Default。也就是说,线程在从未运行过时不持有 desktop 句柄。这正好命中原失败:私有
bootstrap-native.cs/旧的bootstrap.ps1在ResumeGui()之前调用Desktop(RootTid),其中Name(GetThreadDesktop(targetTid))必然拿到 NULL,于是抛出笼统的Missing desktop/station handle——上一批记录的“GUI/输入之前停止、确切失败调用未知”由此解释。修复(仅私有 harness):
DesktopDiagnostics(),并让Name()指明是哪个句柄、附last_error;WinSta0/Default(controller/target/input 一致)的硬前置移到ResumeGui()+ 等到 owned root HWND 之后再执行;VM 实测(reference-2,一次性):bundle zip 26,141,357B / SHA-256
cf34290294f418ca857b17f27f0a7c7f904f062da87a3b03f8aaaa361c357425,4057 文件,stage exit 0。desktop_before_resume:station=WinSta0、controller_desktop=Default、target_error=Missing target desktop handle (last_error=0)—— 直接留证旧前置确实无效;desktop(resume 之后):station WinSta0 / controller Default / target Default / input Default,前置通过;native_roots= 1 个 owned 可见顶层窗口,class=Qt5152QWindowIcon、bounds=[94,71,929,686]、pid=3336/tid=8680、owner=0;Passed=true / CleanupVerified=true / RootExitCode=0 / JobAfterActive=0,无强收尾。Original root is not actual foreground; no activation guess(gui_runs=1,ready_event=false,未发送任何 IME 键、无 UIA/几何结论)。下一步(仍为私有 harness 的有界项):
SetForegroundWindow激活 vs 在无竞争窗口的会话里运行;二者都要先取证,不能用“重试到前台”取绿。本条不改变 #155/#165 的产品实现,也不关闭任何 issue;原 bootstrrap 失败记录与一次尝试的约定保持不变。
JavaZeroo commentedon Oct 29, 2026
前台阻塞已定位并解决,bootstrap 现在真正走到 UIA 阶段(reference-3,一次性)。
前台事实(探针 + 实际运行):VM 交互会话空闲时
GetForegroundWindow()是 Progman / "Program Manager"(pid 4884),没有任何应用窗口持有前台;owned WindTerm 窗口出现后不会自动获得前台(启动方是非前台进程)。采用的处置:一次显式、受记录的
SetForegroundWindow(不循环、不重试;失败即停止),并保留前后对照。reference-3 实测:即:一次调用成功把 owned 原版窗口带到前台;
last_error=203只作观察记录,不作为判定。本轮在 reference-3 上实际达到的阶段:
gui_runs=1、root 窗口 1 个(Qt5152QWindowIcon、bounds [94,71,929,686])、前台检查通过;Passed / CleanupVerified / RootExitCode=0 / JobAfterActive=0;UIA synthetic leaf absent; no verified expand route——UIA 树里没有出现合成 profile 的TermForge Lab组与TF_UI_CMD叶。这说明:之前从未验证过的“合成 profile 是否被原版 2.7.0 真正加载”现在是唯一的卡点;桌面/前台/窗口/清理链路已经闭环。
下一步(有界):核对 2.7.0 的 profile 发现路径与格式(
profiles.config指向TOOL\profile、session 写在.wind/profiles/default.v10/terminal/user.sessions),用 UIA 125 行树与磁盘/日志证据确认它是未加载、加载到别处,还是 UIA 未暴露;确认后再决定是否需要单独一修。原一次尝试、不重试、不改产品行为的约定保持。本条不改变 #155/#165 的产品实现状态;bundle(26,141,762B / SHA
a786f54903efa29a0836afb4c5afb109a01fb83683d074382371fb69ea5b86ce,4057 文件,stage exit 0)与 result 已按私有身份保存。JavaZeroo commentedon Oct 29, 2026
合成 profile 的加载已定位:WindTerm 确实读取了我们的 profile,组节点已出现,缺的是会话叶。
reference-4 实测(一次性,bundle 26,141,840B / SHA
ef573f38f1dc5bc8b72135ac440a624e80599140e2fef67dda2f45eaecaf0e89,4057 文件,stage exit 0):uia_attempts=1、uia_wait_ms=2:树在窗口出现时已就绪,不是加载竞态;synthetic_tag=synthetic-group存在(ControlType.TreeItem,bounds [790,190,131,24])→ 说明user.sessions被读到了,session.group="TermForge Lab"生效;synthetic-session(TF_UI_CMD)叶不存在,且该组节点没有 ExpandCollapse 可展开路由,所以走到UIA synthetic leaf absent; no verified expand route;qt_ime_input_test.exe在 guest 存在(358,912B,与固定包身份一致),ready_event=false属预期(会话要等 End+Return 才启动);user.config、global/reopen.history、terminal/reopen.history),而我们的terminal/user.sessions未被改写——文件格式被接受,会话条目没有形成可见叶;Passed / CleanupVerified / RootExitCode=0 / JobAfterActive=0。旁证:树里
ExplorerList的 rect 是{∞,∞,-∞,-∞}(无效),而组节点落在 [790,190](右侧),与已验的research/ui/launch.py/benchmarks/tools/windterm_c0_settings.py使用的同一 schema 相比,差异只在process.arguments(我们的是带引号的受控 exe 命令行)与会话树所在面板/布局。下一步(有界):
/d /q+ cmd.exe)做一次同环境对照,确认“同 schema 下叶一定出现”,从而把变量收敛到process.arguments或面板/布局;本条不改产品代码、不关闭 #155/#165;bundle/result 按私有身份保存。
JavaZeroo commentedon Oct 29, 2026
UIA 叶节点缺失已做四组对照,结论是"UIA 不是本 profile 的可用入口",需要一次 harness 路径决策。
已排除的变量
TermForge Lab组/d /q(无 BOM 写回)user.config/reopen.history(只剩 user.sessions)raw_children=0、无 ExpandCollapse、无 SelectionItem;右侧 TreeView [770,190,151,106] 只有这 1 个 child;另一个 TreeView 的 rect 是{∞,∞,-∞,-∞}(未布局)-s/--session/-n/--new-session/-h)已知的有效路径:已验收的 research/ui/launch.py 用的是 Frida + Qt 探针(
qt_*.js)直接读 Qt widget 树,而不是 UIA。也就是说,本 bootstrap"依赖 UIA 暴露合成会话"的假设从未被验证,现在被证伪。建议(需要一次明确取舍,不是产品行为变更)
frida_deploys>0,并保留一次性的注入身份与回收证据。在拿到取舍前,我不改 harness 的注入策略;本条不关闭 #155/#165。
JavaZeroo commentedon Oct 29, 2026
UIA 路线追加两组实测:菜单栏是可用的激活入口,但"新建会话"是模态对话框。
观察 1:菜单栏可通过 UIA 展开与调用
新建会话(N) Alt+N、新建窗口(W)、断开会话(D)、重新连接会话(R)、打开会话...(O) Alt+O、最近打开(N)、保存会话(S)、日志(L)、关闭视图(C)、退出(X)等。观察 2:
新建会话触发模态对话框新建会话(N)调用 InvokePattern 后,脚本执行 35 秒超时(RootExitCode=124、JobBefore/After 3→0、清理正常);说明弹出的对话框让后续 UIA 遍历或脚本收尾阻塞。本次没有对对话框做任何输入,也没保存任何东西。可行性判断
user.sessions——同时解决"合成 schema 是否被接受"的疑问。本条不改变 harness 策略;#155/#165 保持开放。若你倾向 Frida 路线,我仍可在拿到确认后切换。
20 remaining items
JavaZeroo commentedon Oct 29, 2026
候选窗枚举结果(同一 VM/同一固定拼音)
在组合态(
ni'hao已输入、未选候选)用 UIA 枚举所有顶层窗口,结果只有 4 个:{"rect":"1024,566,819,48","pid":4884,"name":"","class":"Shell_SecondaryTrayWnd"} {"rect":"0,720,1024,48","pid":4884,"name":"","class":"Shell_TrayWnd"} {"rect":"141,58,742,604","pid":3464,"name":"TermForge — local shells","class":"QWidget"} {"rect":"0,0,2048,768","pid":4884,"name":"","class":"Progman"}即:组合期间没有枚举到独立的候选窗窗口(任务栏/桌面除外,剩下只有我们自己的 Qt 窗口)。
说明与边界
preedit序列到ni'hao,并成功提交你好),所以输入法在本应用里是工作的;TextInputHost在另一会话/桌面上绘制,或当前输入法配置不显示候选列表,因此 UIA 顶层枚举看不到;WM_IME_*/UI Automation 的文本模式,或直接在屏幕上检测候选窗矩形(本 VM 的截图通道已可用)。Merge pull request #207 from JavaZeroo/diag/qt-ime-log
JavaZeroo commentedon Oct 29, 2026
候选窗观测结论:本 VM 配置下没有候选窗 UI
在组合态(
ni'hao已输入、未选候选)用两种 UIA 范围枚举:同时:
preedit到ni'hao→commite4bda0e5a5bd);判读
该 VM 里的固定微软拼音处于行内组合、无候选列表 UI 的状态(或被配置为不显示候选窗),因此:
建议
JavaZeroo commentedon Oct 29, 2026
对照实验:记事本同样没有候选窗
为区分"我们的应用没有候选窗"与"该 VM 的输入法本身不显示候选窗",在同一 VM 用 Windows 记事本做对照:
n i h a o;结果:
{"step":"typed","window":"*ni'hao - Notepad","count":33}*ni'hao - Notepad,文档里显示的就是组合串ni'hao(说明 IME 在记事本里同样处于行内组合);结论
该 VM 的固定微软拼音处于行内组合、不显示候选窗的状态,与我们的应用无关;因此:
你好)可验证;JavaZeroo commentedon Oct 29, 2026
Ctrl-C 在组合态下的观测(我们自己的应用 + 固定拼音)
新增可选观测
TERMFORGE_QT_INPUT_LOG(记录成功发送到会话的字节),与已有 IME 事件观测一起使用,在隔离 VM 上执行:ni'hao(IME 日志 5 条 preedit);input.log03)ni'hao之后没有 cancel/commit 事件 —— 组合未被取消即:组合态下的 Ctrl-C 既没有到达
keyPressEvent(没有0x03),也没有触发 IME 取消,被输入法/系统层吞掉。这与本 issue 早前 N9 的观察("没有 C KeyPress、没有03")一致。意义
边界
观测代码:PR #209(默认关闭)。
JavaZeroo commentedon Oct 29, 2026
对照组:不在组合态时 Ctrl-C 确实发送
03为验证上一轮"组合态下没有
03"不是观测方法本身失效,做了同样流程但不输入拼音、直接按 Ctrl-C:{"bytes":1,"hex":"03"}即
TERMFORGE_QT_INPUT_LOG能正常捕获0x03;组合态那次input.log不生成,是真的没有字节发出。两条结果合并
03结论更明确:组合期间 Ctrl-C 被输入法层吞掉,既不到按键路径也不到 IME 事件路径。
(观测代码:PR #209,默认关闭。)
Merge pull request #209 from JavaZeroo/diag/qt-input-log
JavaZeroo commentedon Oct 29, 2026
原版对照:组合态 Ctrl-C 同样不打断会话
方法:原版 WindTerm 2.7.0(固定 EXE/文件清单),用同一 harness 展开会话组并打开
TF_UI_CMD,会话命令为ping -n 300 127.0.0.1(持续输出)。步骤:
n i h a o(触发组合);结果:
orig-a1.png(548,408 B)与orig-a2.png(548,559 B)大小不同;即:组合态 Ctrl-C 之后,原版终端画面 仍在滚动,
ping没有被中断 —— 与我们的应用观测一致(组合态 Ctrl-C 不产生0x03)。边界
对 #155 的意义
"Ctrl-C 与 IME 的消费关系"这一项现在有了双方一致的观测;若要判定"应用是否应主动处理组合态 Ctrl-C",那属于产品决策,需要你确认,而不是原版差异。
原版对照图片与脚本保存在本地私有目录,未上传仓库。
Merge pull request #211 from JavaZeroo/docs/features-ime
JavaZeroo commentedon Oct 30, 2026
#155 剩余验收项对照:代码/测试 vs 固定拼音 VM 证据 vs 未观察
只读核对:未改产品源码、未合入、未派发 CI。
身份与入口
f84dd01(2026-10-29T20:45Z)、#206def8a37(21:00Z)、#207c380d7a(21:33Z),均 MERGEDsrc/qt/terminal_widget.hpp:143-152(inputMethodQuery)、:172-188(inputMethodEvent)、:218-228(preedit 预览)、:250-253(WA_InputMethodEnabled);origin/main7ff5cde与当前 worktree HEAD 的src/qt无差异.github/workflows/qt-cpp.yml:44-45构建、:68-69在 owned Job 内跑 `^(qt_cpp_(shellresearch/ui/results/2026-10-30-qt-ime-fixed-pinyin/README.md:14-22(7 条事件)、:32-34(锚点)、:36-40(未覆盖)、validation.json:74-80逐项对照
判定口径:已覆盖=代码与测试都指到;仅 VM=只有实测、无代码级守卫;未观察=两者都没有。
src/qt/unicode_input_test.cpp:270仍写{"ime": false},shell_smoke.cpp:363-386直接是绿断言terminal_widget.hpp:172-188:model_.send(commit.toUtf8())整包一次、无键盘 Backspace→DEL 改写;合成断言shell_smoke.cpp:363-386(preedit 不入会话、commit 入会话、空 preedit 取消不写)e4bda0e5a5bd6B(README:21)InputQueue拒绝(experiments/shell/queues.hpp:134,容量 16KiB:69);terminal_widget.hpp:183未看send()返回值,只留通用错误(terminal_session.hpp:246)后仍清 preeditImeContext仅被experiments/shell/*引用(ime.hpp:15-42),src/qt未用;Qt 侧只显式返回空ImSurroundingText/ImCurrentSelection与ImCursorPosition=0(143-152),无 256 上限;QString::toUtf8对孤立代理项替换 U+FFFD 而非失败event->attributes();query 每次现算光标矩形(143-147),无缓存keyboard_.reset()(73-75),preedit_不清;标签用例不含 IME(84-151)shell_smoke.cpp保留 750/exit 37/标签;docs/FEATURES.md:26、docs/EVIDENCE.md:11已记录代码级缺口(读代码得到,无测试覆盖)
preedit_.size()(UTF-16 单元)算格宽terminal_widget.hpp:222terminal_widget.hpp:172-188terminal_widget.hpp:73-75terminal_widget.hpp:183+queues.hpp:134三项未观察:各自最便宜的一次观察
EnumWindows+EnumChildWindows,按本进程 PID 过滤,记 class/rect/IsWindowVisible/owner)代替 UIA:UIA 只暴露 provider 实现的元素,枚举含不可见窗口。同一探针在组合态对 输出写入/字体变更/resize 各读一次 rectinputMethodQuery每次都现算(143-147),rect 不变即可判为 provider 未重查,而非我们的锚点陈旧TERMFORGE_QT_IME_LOG已有同型先例 156-171;TERMFORGE_QT_INPUT_LOG132-141 已把是否发出字节分开),组合态与非组合态各一次QKeyEvent不能替代(不经过 Windows IME provider)presented_donebenchmarks/PROTOCOL.md:52presented_done;native acceptance 另需前两项之后再记整场景边界
presented_done三项仍无证据。Merge pull request #230 from JavaZeroo/fix/qt-ime-gaps
JavaZeroo commentedon Oct 31, 2026
现状核对:实现已在 main,正文的状态行已过期
本项正文开头写「PR165 未合入 main」,这条已不成立:
dea6065a44bd2c两者均已核对为
origin/main的祖先。docs/EVIDENCE.md也已有对应行:因此本项性质已变
正文里「原生机械链路完成,候选框对照仍开放」这句仍然准确,但"未合入"的前提消失后,本项剩余的是纯验收,不含实现:
建议
把本项改写为验收项(例如标题或正文首段明确「实现已合入 main,剩余为候选框与对照验收」),并按上列 1–5 拆分对应的证据要求。这样它不会继续与"实现是否合入"混在一起,也便于与 #30 的固定 TUI 验收衔接。
本条只核对状态与证据位置,不关闭本项,也不改验收标准。
JavaZeroo commentedon Nov 1, 2026
N11 候选框几何对照完成:输出后不更新与官方 WindTerm 2.7.0 一致;字体阶段原版放大未触发,保持未知
在隔离 Windows 11 固定微软拼音下,把 TermForge 冻结源(Qt,
5fab30b)与官方纯 WindTerm 2.7.0 做同输入轨迹、同固定时间点对照,各 3 次独占运行。协议:
N I H A O组合 → 受控输出 6 行纯文本 → 窗口 resize +96/+48 → 一次 Ctrl+= 字体放大 → Esc 取消;四阶段各采集「即时」与「延后 ≥250 ms(实测 252–269 ms)」两张全屏图,候选框几何用同一采集器n11-capture.cs的密集亮度带检测。候选面板在组合期表现为窗口标题带下方新增的 2 条亮带。候选面板矩形(物理像素,主屏 1024×768/96 DPI):
[73,108,711,142][373,232,1011,266][181,196,819,230](3/3 即时更新)[373,340,1011,374](2/3 延后更新)结论(区分实测/推断/未验证):
归档(原始截图只留私有,仅哈希公开;6 个 zip 已逐文件解压并与各自 manifest 逐项核对 SHA-256,0 不匹配;文件数 = zip 内条目数):
样本数:Qt 3 次共 38 采集(12/13/13),WindTerm 3 次共 45 采集(13/16/16);每侧 4×3=12 个几何配对。
边界与仍开放项:
failed,但失败点都在收尾关闭阶段(自动化 Ctrl+W / WM_CLOSE / 对话框确认 / SC_CLOSE 后官方 WindTerm 2.7.0 未在预算内退出);四个几何配对在失败前均已完整采集,不影响候选框几何结论。这本身是官方 WindTerm 的自动化关闭行为,不是候选框差异。native acceptance/presented_done仍 null,本评论不改变其他 DPI / 完整字形 / [R2-07][文字] 验收复杂 Unicode、IME 与键盘/选择语义 #30 / [R2-08][显示] 明确字体网格并验收真实 DPI 与跨显示器切换 #31 的验收口径。docs(research): Qt 与 WindTerm 2.7.0 IME 候选框固定时间点对照 refs #155 (#302)
[-][R2][输入] 为正式Qt终端接入组合、提交、取消及固定拼音验证[/-][+][R2][输入验收] Qt IME 候选窗与固定拼音交叉验证[/+]