Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 5 additions & 2 deletions .github/workflows/qt-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
"-DTERMFORGE_CONPTY_BACKEND_DIR=$dependencyRoot/conpty" `
"-DTERMFORGE_MSVC_RUNTIME_DIR=$dependencyRoot/crt"
- name: Build Qt product and independent smoke
run: cmake --build build/qt-cpp --config Release --target termforge_qt_shell qt_cpp_shell_smoke qt_cpp_resize_smoke --parallel 2
run: cmake --build build/qt-cpp --config Release --target termforge_qt_shell qt_cpp_shell_smoke qt_cpp_resize_smoke qt_unicode_input_test --parallel 2
- name: Record complete path-free runtime manifests
run: |
python tools/msvc_runtime.py manifest --directory build/qt-cpp/qt-bin/Release --executable termforge_qt_shell.exe
Expand All @@ -51,6 +51,8 @@ jobs:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python tools/msvc_runtime.py manifest --directory build/qt-cpp/qt-resize-bin/Release --executable qt_cpp_resize_smoke.exe
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python tools/msvc_runtime.py manifest --directory build/qt-cpp/qt-unicode-bin/Release --executable qt_unicode_input_test.exe
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Preserve runtime file identities without binaries
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
Expand All @@ -62,8 +64,9 @@ jobs:
build/qt-cpp/qt-bin/Release/runtime-manifest.json
build/qt-cpp/qt-smoke-bin/Release/runtime-manifest.json
build/qt-cpp/qt-resize-bin/Release/runtime-manifest.json
build/qt-cpp/qt-unicode-bin/Release/runtime-manifest.json
- name: Run Qt offscreen smoke in its owned Job
run: ctest --test-dir build/qt-cpp -C Release -R '^qt_cpp_(shell|resize)$' --no-tests=error --verbose
run: ctest --test-dir build/qt-cpp -C Release -R '^(qt_cpp_(shell|resize)|qt_unicode_input)$' --no-tests=error --verbose
# Keep this configuration independent from the default/system-backend and
# Alacritty reference jobs. SDKs, runtime folders and raw logs are not
# publication artifacts; this job does not produce a release package.
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,24 @@ if(TERMFORGE_BUILD_QT_SHELL)
"${PROJECT_SOURCE_DIR}/src/qt/run_smoke.py" "$<TARGET_FILE:qt_cpp_shell_smoke>")
set_tests_properties(qt_cpp_shell PROPERTIES TIMEOUT 35
ENVIRONMENT "QT_QPA_PLATFORM=offscreen")

add_executable(qt_unicode_input_test src/qt/unicode_input_test.cpp)
set_target_properties(qt_unicode_input_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qt-unicode-bin/$<CONFIG>")
termforge_qt_entry(qt_unicode_input_test)
target_link_libraries(qt_unicode_input_test PRIVATE Qt6::Test)
add_dependencies(qt_unicode_input_test shell_input_client)
add_custom_command(TARGET qt_unicode_input_test POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"$<TARGET_FILE:Qt6::QOffscreenIntegrationPlugin>"
"$<TARGET_FILE_DIR:qt_unicode_input_test>/platforms/"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"$<TARGET_FILE:shell_input_client>" "$<TARGET_FILE_DIR:qt_unicode_input_test>/"
VERBATIM)
add_test(NAME qt_unicode_input COMMAND "${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/src/qt/run_smoke.py" "$<TARGET_FILE:qt_unicode_input_test>")
set_tests_properties(qt_unicode_input PROPERTIES TIMEOUT 35
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;TERMFORGE_TEST_ARTIFACTS=${PROJECT_BINARY_DIR}/test-artifacts")
add_executable(qt_cpp_resize_smoke src/qt/resize_smoke.cpp)
set_target_properties(qt_cpp_resize_smoke PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qt-resize-bin/$<CONFIG>")
Expand Down
1 change: 1 addition & 0 deletions docs/EVIDENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
|---|---|
| 自主 C++ 限定 1049 协议 | [固定结果](../experiments/core/results/2026-10-29-cpp-1049/README.md)、[验证身份](../experiments/core/results/2026-10-29-cpp-1049/validation.json):文字/光标/颜色及 pending-wrap、重复进入与读者失效;55项中Qt1项分列,13条内部skip及旧负例判据失败保留。未验收非颜色属性/全网格背景、其他模式、真实TUI/IME/DPI、呈现或性能 |
| 自主 C++ 双缓冲存储与文档 epoch 基础 | [固定结果](../experiments/core/results/2026-10-29-buffer-state-r2/README.md)、[验证身份](../experiments/core/results/2026-10-29-buffer-state-r2/validation.json):拥有状态、共享 ID、隐藏帧 resize 回滚与跨缓冲句柄失效;Qt/candidate 关闭配置的完整 50 项及 12 条内部 skip 分列。未接 private CSI,不是原版模式、Qt 产品路线或完整 #27 验收 |
| Qt 基础 Unicode 文本字节 | [红绿与联合验证](../experiments/shell/results/2026-10-29-qt-unicode-input/README.md)、[固定联合身份](../experiments/shell/results/2026-10-29-qt-unicode-input/validation.json):公开Qt事件到独立ReadConsoleW接收端,整/分事件代理项、焦点/隐藏/关闭、1024B整包与NUL、两目标隔离。2b6d源码一次61项分列Qt3/其余58,13内部skip、旧红例与27原件保留;不是实际IME、字素/字形、原生Unicode窗口、DPI或性能验收 |
| Qt cmd 标签与退出前回收 | [固定结果](../experiments/shell/results/2026-10-28-qt-tabs/README.md)、[验证身份](../experiments/shell/results/2026-10-28-qt-tabs/validation.json):双 cmd 隔离、失败页、关闭与四个实际事件循环边界;Qt 1 项和其他 49 项诊断及内部跳过分列,旧中断轮不拼接 |
| Qt 基础动态网格与真实 child 尺寸 | [固定结果](../experiments/shell/results/2026-10-29-qt-resize/README.md)、[原冻结与查询](../experiments/shell/results/2026-10-29-qt-resize/validation.json)、[平台区域反例与夹具修订](../experiments/shell/results/2026-10-29-qt-resize/platform-area-validation.json)、[0ff 隔离原生补充](../experiments/shell/results/2026-10-29-qt-resize/native-validation.json):GUI/core、child、错误和字体度量红绿;678 原生极窄失败及 135 条 child 回复保留;0ff 新离屏 57 项与冻结包一次原生成功分列,原生保留全部 40 条 CSBI、实际顶层区域 120px→11 列及 root/Job 回收。两次离屏均分开 Qt 2 项、其余 55 项诊断及 13 条内部 skip;退出竞态旧尺寸保留;原生窗口仅 DPI 96,不是原版 reflow、真实不同 DPI、物理呈现或旧 system 失败修复 |
| Qt app-local 固定微软 CRT 与隔离 Windows 加载 | [固定结果](../experiments/shell/results/2026-10-29-qt-crt-deploy/README.md)、[完整运行时与验证身份](../experiments/shell/results/2026-10-29-qt-crt-deploy/validation.json):原 `cf8` 52 文件首次加载失败与仅追加 CRT/原许可后的成功分列;新源码构建、原生窗口、有限 cmd/关闭、offscreen 及 Job 清理独立记录。不是完整发行、跨 DPI/IME 或物理呈现验收 |
Expand Down
2 changes: 1 addition & 1 deletion docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

| 新路线迁移入口 | 当前状态与边界 | 目标差距 | 路标 |
|---|---|---|---|
| 自主 C++ / Qt / 固定微软 ConPTY | **实现中,未验收**:[显式 Qt 入口](../src/qt/README.md)提供默认 80×24、随可用区域变化的 cmd 标签、基本 ASCII/16 色及各会话独立有界队列;[基础动态尺寸验证](../experiments/shell/results/2026-10-29-qt-resize/README.md)分离窗口/核心/transport 与真实 child,覆盖极小、重复、隐藏页和关闭交叉,并复验原标签算术及事件循环回收。678 原生极窄失败保留;0ff 仅修订字面子区域/顶层实际区域夹具,另有[冻结包一次隔离原生成功](../experiments/shell/results/2026-10-29-qt-resize/native-validation.json):实际顶层区域、core/transport/child 一致,窗口仅 DPI 96。两次离屏完整 57 项分别绑定源码;Qt 2 项与其余 55 项既有/独立诊断、13 条内部 skip 分列 | 分屏、其他 shell、工作区恢复、完整 resize/reflow、历史/选择/Find、Unicode/IME、真实 DPI、应用兼容与性能仍需实现或迁移;物理裁剪不恢复丢弃正文,完整 WindTerm 标签/尺寸行为对照未完成;当前不是可发布开发包 | R2 |
| 自主 C++ / Qt / 固定微软 ConPTY | **实现中,未验收**:[显式 Qt 入口](../src/qt/README.md)提供默认 80×24、随可用区域变化的 cmd 标签、基本 ASCII 与[限定 Unicode 文本字节](../experiments/shell/results/2026-10-29-qt-unicode-input/README.md)、16 色及各会话独立有界队列;[基础动态尺寸验证](../experiments/shell/results/2026-10-29-qt-resize/README.md)分离窗口/核心/transport 与真实 child,覆盖极小、重复、隐藏页和关闭交叉,并复验原标签算术及事件循环回收。678 原生极窄失败保留;0ff 仅修订字面子区域/顶层实际区域夹具,另有[冻结包一次隔离原生成功](../experiments/shell/results/2026-10-29-qt-resize/native-validation.json):实际顶层区域、core/transport/child 一致,窗口仅 DPI 96。旧尺寸结果保留各自源码;[Unicode 联合源码的一次完整61项](../experiments/shell/results/2026-10-29-qt-unicode-input/validation.json)分开 Qt3项与其余58项既有/独立诊断,13条内部skip保留 | 分屏、其他 shell、工作区恢复、完整 resize/reflow、历史/选择/Find、完整 Unicode 字素/绘制与 IME、真实 DPI、应用兼容与性能仍需实现或迁移;物理裁剪不恢复丢弃正文,完整 WindTerm 标签/尺寸行为对照未完成;当前不是可发布开发包 | R2 |

自主 C++ 核心已有 [#130 双缓冲存储基础](../experiments/core/results/2026-10-29-buffer-state-r2/README.md),并接入 [#135 限定 1049 协议](../experiments/core/results/2026-10-29-cpp-1049/README.md):strict/recovery 识别 `?1049h/l`,重复进入归首格、清旧备用文本和复位写入颜色,返回恢复主屏文字/光标/颜色及 pending-wrap。共享行 ID、双帧物理 resize 与逻辑 epoch 防止旧位置、选择、搜索及 viewport 复活,包括清屏后重写相同文字。原版完整网格/背景、非颜色属性及其他模式仍未知;本地55项中 Qt1项与其余54项诊断分列,13条内部跳过保留,不表示完整 [#27](https://github.com/JavaZeroo/termforge/issues/27)、真实 TUI/Qt 交互或系统剪贴板已验收。

Expand Down
51 changes: 51 additions & 0 deletions experiments/shell/results/2026-10-29-qt-unicode-input/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Qt 基础 Unicode 文本输入的限定验证

执行项 [#147](https://github.com/JavaZeroo/termforge/issues/147),父项 [#30](https://github.com/JavaZeroo/termforge/issues/30)。正式 C++ / Qt Widgets / 固定 Microsoft ConPTY 路线将 `QKeyEvent.text()` 的 UTF-16 单元交给本项目既有 `KeyboardEncoder`;每个 widget 独立保存未完成的高代理项。临时编码器处理整条事件,只有整包进入有界输入队列后才提交状态。包过限或队列拒绝保留此前状态;失焦、隐藏、关闭及目标不可用清除未提交的半个标量。

未配对单元使用 U+FFFD,已支持的控制/导航键结束此前未完成标量,焦点变化丢弃未提交单元;这些是**现有 TermForge 编码策略**。本批没有运行 WindTerm,不宣称这些边界已经与原版匹配。

## 公共边界与原始接收

测试通过公开 Qt key/focus/hide/tab 动作进入正式 widget/session,再由固定 ConPTY 启动独立 `shell_input_client.exe`。该现有夹具用 `ReadConsoleW` 读取原始单元,通过 Windows UTF-8 API 导出文件;字面预期不调用被测编码器。只在夹具结束时由 Session 直接发送 EOT(4),不把它解释为产品已支持 Qt Ctrl-D。输入回显或 `send()` 返回成功均不是接收 oracle。

五组场景:

| 场景 | 实际接收与边界 |
|---|---|
| Unicode 文本 | 中文、NFD `e + U+0301`、整事件与跨事件的 U+1F600、固定 woman-technologist ZWJ/keycap、孤立低代理项、连续高代理项和 Return 边界;58B 精确 UTF-8 |
| 焦点/隐藏与包拒绝 | 显式 Qt 焦点移交、隐藏后恢复均使低代理项独立替换;1024B 接受,1025B 整包拒绝且不污染已持有高代理项;嵌入 NUL;最终 1037B |
| 原有正常模式按键 | ASCII、Return、Tab、Backspace、Ctrl-C 和四方向键的19B字面预期;Qt Ctrl-D 仍拒绝 |
| 标签与关闭 | 两个真实标签各有独立接收文件;隐藏目标拒绝输入,切换丢弃未完成单元;第三个目标带半个代理项关闭后只取消自身,存活目标继续接收 |
| 不可用目标 | 未启动目标拒绝后可以正常启动,孤立低代理项不能复用失败输入;已结束和启动失败目标拒绝,错误及回收可见 |

Qt 层实际拒绝场景使用现有单包上限。16KiB 总队列容量沿既有 `InputQueue` 公共夹具单独验证,没有通过随机洪流制造全队列现场,也没有增加生产测试钩子。不同配置的检查不拼成一条原生运行。

## 已固定的红与针对性绿

- 原始 test-only 源 `8adc256ffe53a7cace75d74bf6ac5d173e8b59fc`,测试 EXE SHA-256 `06d1b14692d08e672517409846fca27821514ca94e3d0163bd3f5b9943ba5dd8`:预期 `4ce4b8ade6968752`,独立接收端只收到 `4c52`;接收子进程正常结束,测试按字节不一致失败,外层 Job active=0/total=4,未超时。[原39文件运行时身份](red-runtime.json)保留。
- 扩展反例源 `39e3c2c` 显示高代理项越过 Return 后与低代理项错误拼接;按既有编码器 finish 策略修复。源 `dca412f` 还固定未聚焦目标接受合成文本的反例。
- 焦点夹具最初仅调用 `activateWindow()`,在 offscreen 平台重获焦点失败;该次失败保留在本地原日志。当前夹具改用公开 `QApplication::setActiveWindow` 并检查实际 Qt 焦点,不能据此声明 Windows 物理输入焦点已验收。
- 针对性源 `2bdcea3161f415f49d96bc0f30e5e72794c8c72f` 的五组场景通过;外层 Job active=0/total=17/terminated=0,测试根正常 exit=0。6个自然结束接收文件和1个取消目标分别记录。可审查的[源/原日志哈希与离线接收重算](focused-validation.json)、[40文件运行时](focused-runtime.json)与最终联合源码验证分开保留。

原等待边界不变:单阶段5秒,监督器主 `communicate` 25秒,CTest35秒,失败清理仍由原监督器/Session处理;这些是诊断期限,不是性能指标或完整进程生命周期承诺。运行使用 Qt 6.10.3、固定 ConPTY 1.25.260930003、VS2022/MSVC19.42 与 app-local CRT14.51;运行时清单绑定所有实际文件。

## 联合源码与一次完整回归

动态尺寸 PR148 合入 main `05f0065f4eb19ce5a76065d18f2247bcc731e285` 后,本分支以 `5d7cb5c` 合并:保留可扩展布局、resize/字体/DPR 事件与独立编码器的焦点、隐藏、关闭和结束清理。执行源码固定为 `2b6d988914b04a2a05520f0b67c08c30b6e2b43b`,tree `46e358272e6f1c99ef5d65ffcb007a3ce41b1ac9`;后续公开文档和 JSON 不算执行源码。[联合验证身份](validation.json)与上述旧红例、旧针对性绿例分别保留。

在 Windows 11 x64 build26200/UBR9711、MSVC19.42.34433.0、Python3.12.10 下使用固定 Qt6.10.3、ConPTY1.25.260930003 与 app-local CRT14.51.36247.0。先运行 Qt 三项针对性检查 **3/3**,随后唯一一次完整 CTest **61/61、exit0、307.06s**。其中正式 Qt 为 `qt_cpp_shell`、`qt_unicode_input`、`qt_cpp_resize` 三项,其余58项属于既有默认/system或独立诊断;**13条内部 unittest skip** 全部保留,包含私有 window station 的 OpenClipboard5,不能写成 CF 验收。时长仅为测试运行记录,不是性能基线。

两次 Unicode 检查各产生六个自然结束接收文件与一个取消目标的空文件,全部逐字核对字面预期。7397个执行输入及运行文件在完整回归后重算零变化:2817源码、4358 SDK、2 ConPTY、12 CRT、38产品目录、40原smoke、40 resize、41 Unicode、49旧诊断文件;这些目录计数包含各自 `runtime-manifest.json`。另外27份旧原件和已有公开红绿证据未变。四份实际运行时清单分别为[产品](final-product-runtime.json)、[原 smoke](final-shell-runtime.json)、[resize](final-resize-runtime.json)、[Unicode](final-input-runtime.json);其 `files` 字段不包含清单自身。

专用 Qt CI 新增 Unicode 测试目标、完整运行时身份与三项测试选择。当前公开文件由同一批原件离线派生,普通与 `-O` 解释器导出逐字一致;没有重新运行原版、Qt windows-plugin、guest 或第二次完整矩阵。旧 #80/#81/#144/#145 原因仍未知,这次通过不构成因果修复。原生缩放证据仍只绑定其原0ff源码,不转记为本次 Unicode 原生验收。

## 复验与限制

按 [Qt 构建说明](../../../../../src/qt/README.md)配置后:

```powershell
cmake --build build/qt-cpp --config Release --target qt_unicode_input_test
ctest --test-dir build/qt-cpp -C Release -R '^qt_unicode_input$' --no-tests=error --verbose
```

每次产生独立自有临时目录;合成接收文件及 stdout/stderr 留在本地,公开仅源码、输入字面量和脱敏身份/标量摘要。没有新第三方库,也没有修改核心字素、实验后端或开启 `WA_InputMethodEnabled`。Qt offscreen 与人工 `QKeyEvent` 不等于真实 OS IME、物理键盘、跨 DPI、字形/宽度/整形或实际呈现;这些及 WindTerm 对照、应用键盘模式和性能仍未知。本切片不验收完整 #30 或 R2。
Loading
Loading