wincons

command
v3.8.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 12 Imported by: 0

README

wincons

在 真实 Windows 控制台上驱动示例程序(_examples/cliapp),是 scripts/ptysmoke(PTY,仅 Linux/macOS)的 Windows 对应物。Python 的 pty 模块在 Windows 上不存在,ConPTY 子进程在 gofer job 里也起不来(CreateProcess 带 PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 会以 0xC0000142 退出, 见 suga 的 scripts/wincons README 实测),所以这里用 Windows 自己的控制台:

  1. FreeConsole 脱离启动它的控制台(gofer job 里没有可保留的),AllocConsole 另建一个私有控制台;
  2. 应用以该控制台的 CONIN$ 作为 stdin 启动(cooked 行输入是真的,提示符也是真的), stdout/stderr 走管道 —— 这样 harness 仍能读到它打印了什么;
  3. 等提示符在输出里出现后,用 WriteConsoleInput 写 KEY_EVENT 记录(等价真人敲键 + 回车);
  4. 每个用例都新建一个控制台,避免上一次残留的按键事件串到下一次。
go build -o tmp/wincons/cliapp.exe ./_examples/cliapp
go run ./scripts/wincons --bin tmp/wincons/cliapp.exe          # --verbose 打印每个用例的完整输出与控制台状态

该文件带 //go:build windows:在 Linux/macOS 上 go build ./... / go test ./... 会跳过它(不报错), 但指名构建这个包会报 build constraints exclude all Go files(平台专用工具的正常行为,同 suga)。

运行时会为每个用例弹出(并很快关闭)一个控制台窗口;输出与结果打印在本进程的 stdout(管道), 退出码 0 表示全部通过。

用例 检查
ask-demo(局部选项 CliOpt.Question) 空值 → 提示符出现一次、键入的内容成为选项值、退出码 0
ask-demo --token=cli-token 不提问、值被采用
shared-ask run(共享选项 + WithQuestion) 只在实际执行的命令处提问一次,键入值被叶子命令读到
shared-ask run --token=leaf-token 不提问、叶子用给定值
shared-ask run -h help 列出继承选项且从不提问

实测(本机 Windows 10 IoT LTSC 2024,Go 1.25.10):15/15 通过;把 doExecute 里的 prepareSharedOpts() 调用去掉后重建,shared-ask run 两条检查立即 FAIL、退出码 1(与 PTY 侧 shared_ask.py 的反向验证一致)。

踩坑记录

  • 虚拟键码必须真实:KEY_EVENT 里的 wVirtualKeyCode 用字符本身是错的 —— - 的 0x2D 恰好是 VK_INSERT,控制台会把它当功能键(插入模式切换)而丢掉字符,win-token 变成空/wintoken。 改用 VkKeyScanW 取真实的 VK + 移位状态(高位字节)。
  • 回车要显式发 VK_RETURN(VkKeyScan 对 CR 拿不到)。
  • 子进程的 stdout 是管道 → 颜色/高亮默认关闭(NO_COLOR=1,断言看文本);要测彩色效果就把它接到 CONOUT$,但那样 harness 读不到输出(suga 的 --console-output 是同一权衡)。
  • 控制台窗口会真出现(AllocConsole),CI/无人值守时注意;本 harness 每次用例后 FreeConsole 释放。

与 ptysmoke 的分工

同一批场景两边都跑了 ask-demo / shared-ask:PTY 侧(Linux/macOS)还覆盖 cliui 的行式提示 (interact_confirm.py),Windows 侧覆盖的是控制台路径。真正跨平台不变的语义(收集只在执行命令处、 已给值不提问)用 go test(shared_opts_test.go)固化,这两个 harness 负责"在真终端里确实如此"。

Documentation

Rendered for windows/amd64

Overview

Command wincons drives the example app (./_examples/cliapp) on a real Windows console: the Windows twin of scripts/ptysmoke (PTY, Linux/macOS only).

Python's pty module does not exist on Windows, and a ConPTY child cannot be started from a gofer job (CreateProcess with PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE fails with 0xC0000142 there), so this harness drives the console Windows has: it detaches from the console it was started with, creates a private one (AllocConsole), starts the app with that console's CONIN$ as stdin and its stdout/stderr on a pipe, then types the answer as KEY_EVENT records with WriteConsoleInput - exactly what a keyboard writes into the console input buffer. The app therefore sees a genuine console on stdin (cooked line input, the prompt is real), while the harness can still read what it printed.

go build -o tmp/wincons/cliapp.exe ./_examples/cliapp
go run ./scripts/wincons --bin tmp/wincons/cliapp.exe

Every case is independent: it gets a fresh console, so no stale key event can leak into the next one. Exit status 0 when every check passes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL