Files
msime-windows/windows
fanlusky 1640cb353f fix(punctuation): 终端里智能标点改写恢复 SendInput 兜底
重构智能标点(#413)之后,「英文/数字后面连按两次同一个英文标点变回中文
标点」在 Windows Terminal 里失效:输入 `1.` 再按一次 `.`,屏幕上变成
`1.。`。

#413 把原来的 SendInput(合成 VK_BACK + KEYEVENTF_UNICODE)改写换成了编
辑会话里的 ITfRange::SetText 原地改写。原地改写要求宿主背后有一份真正的
文档文本存储;终端类宿主的 TSF 上下文只是一层代理,不保存已上屏的文字,
于是 ShiftStart(-1) 拿不到前一个字符,代码退回 fallback
insertChinesePunctuation(),把中文标点追加在 ASCII 标点后面而不是替换掉
它。SendInput 走的是系统输入队列,与宿主实现无关,这也是老方案在哪儿都
能用的原因。

两条路并存:先试原地改写,失败才排队 SendInput 改写,两条都不成立时才是
原来的 fallback。区分宿主不靠进程名,而靠写入前把待改写字符读回来校验——
空壳存储会照单全收 ShiftStart 和 SetText 并报告成功,只有把字符交还回来
的存储才真的能被原地改写。

SendInput 改写从编辑会话里 PostMessage 出去,执行前校验焦点会话 token、
前台窗口和 500 ms 期限,任一不符就放弃,而不是对着已经挪走的光标盲目退
格;每个清除 action 的地方一并取消排队中的改写。合成事件带自生成标记,本
输入法自己的按键钩子据此放行。

顺带补上一个洞:FUNCTION_SMART_PUNCTUATION_CONVERT/REVERT 在 replay 与
prevalidated 路径上没有处理者,按键会被吃掉后静默丢弃,现在走同一个编辑
会话。

两条改写路径各加一行诊断日志,走已有的 tsf_diagnostic_log 开关,默认关
闭:宿主用的是哪种存储从外面看不出来,出问题时不用靠猜。
2026-09-19 17:21:30 +08:00
..

windows —— TSF 文本服务

水杉输入法在 Windows 上的前端:一个纯 TSF 方案的文本服务 DLL,注入宿主进程,负责按键预判、焦点与线程归属、composition 的 edit session 写入,以及与 Server 之间的命名管道协议。候选窗、工具栏、设置页和实际的候选计算都在 ../server/,本目录只做宿主适配。

产品介绍、安装和功能说明见仓库根目录的 README;本目录的代码地图、TSF/COM 硬约定和改动要求见 AGENTS.md。

构建

从仓库根目录配置,源码目录是本目录:

cmake -S windows -B windows/build -A x64 `
  -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
  -DVCPKG_TARGET_TRIPLET=x64-windows-static
cmake --build windows/build --config Release --parallel
ctest --test-dir windows/build -C Release --output-on-failure

Win32 用 -A Win32 和 x86-windows-static;安装包两种架构都要。scripts/ 下是本机开发用的生成、构建、注册和签名脚本,从本目录运行。

引擎契约来自 ../engine/contracts/,是本仓的目录,普通检出就有。TSF 只引用这些头文件,不链接引擎运行库。