[windows][ime] TSF 失败后的静默 unicode 兜底按 Enter 发送换行并可能与迟到插入叠加,导致聊天输入框内容重复与拆分

未关闭
#1,318 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
18/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
rust, tauri
领域
desktop

调研方向

Start in src-tauri/src/core_adapters.rs at the TSF submit failure branch, where the warning is logged and allow_non_tsf_fallback routes to windows_unicode_fallback. Then read insert_via_unicode_keystrokes, which currently logs nothing, and check how newline_mode = enter turns \n into Enter presses. A first step is adding the missing fallback log lines; done means the fallback path is visible in logs and a regression test asserts that a multi-paragraph insert under TSF NotDispatched sends the text once without submitting.

由索引模型根据 Issue 内容生成。

描述

现象

  • 触发条件:windowsInsertionMode = tsf、allowNonTsfInsertionFallback = true(默认开启)、windowsSendInputNewlineMode = enter(出厂默认);目标为聊天类前台输入框(实测 Codex Desktop 的 Chromium composer,进程 ChatGPT.exe);听写内容经 Structured 润色后包含多个段落/分条。
  • 当前表现:一次听写后,目标输入框出现两份内容、尾部片段劈裂重复;内容逐段被以 Enter 提交为新消息("说完一条分出新的一条,结束后还会出现第三条")。记事本/普通网页不复现(TSF 正常 Committed,不走兜底;Enter 也不提交)。
  • 证据(2026-10-31 本机日志,已脱敏,仅含长度/hash/session id):
    • 正常路径:submit begin op=commit ... payload_bytes=308(= 146 字符 ×2 + 16 头部,commit 只含一份文本)→ status=Committed → Ok(Inserted)。
    • 异常路径:submit complete op=commit status=NotDispatched → [WARN] [core-adapter] TSF submit failed: TSF edit session was rejected before dispatch → 0.4s 后 insert_final result=Ok(Inserted),期间没有任何兜底路径日志。该会话 polish 85 字符,目标输入框实际出现约 2×85 字符(内容两份、尾部片段 ×2)。
    • 近期统计:probe deadline expired 32 次、NotDispatched 6 次,目标均为 Codex Desktop composer;失败后均未观察到第二次 submit 或兜底日志。

影响

  • 聊天类应用中听写结果重复、被拆分成多条消息提交,需手工清理;核心听写链路在此类应用中不可信。
  • 兜底路径零日志:故障时无法从日志定位(本次排查的主要成本),用户侧表现为"随机重复"。
  • 观测:单日兜底路径触发最高 20 次(2026-10-24)。

复现步骤

  1. Windows 11 x64 + OpenLess 2.0.2-Beta.3+build.141-c9f49c60,保持 windowsInsertionMode=tsf、windowsSendInputNewlineMode=enter(出厂默认)。
  2. 前台置为 Codex Desktop 消息输入框(Chromium WebView composer)。
  3. 听写一段会被 Structured 风格润色成多段/分条的内容,松手。
  4. 观察目标输入框:内容两份 / 尾部片段重复 / 被按段提交为新消息;日志特征为 TSF submit failed 后 0.2~2s 内 Ok(Inserted) 且无兜底日志。

根因定位(代码固定到 v2.0.2-Beta.3-tauri)

  1. src-tauri/src/core_adapters.rs TSF 提交失败分支:log::warn!("[core-adapter] TSF submit failed: {error}") 后 break InsertStatus::Failed;allow_non_tsf_fallback 为真时进入 windows_unicode_fallback(&self.context, &text)。
  2. 同文件 windows_unicode_fallback(约 :5240):insert_via_unicode_keystrokes(text, WindowsSendInputOptions { newline_mode: windows_sendinput_newline_mode }),函数内零日志;newline_mode = "enter" 时每个 \n 转成 Enter 键按下——聊天类 composer 中即"提交消息"。
  3. TSF NotDispatched / rejected-before-dispatch 不保证文本未插入:异步 edit 仍可能落进文档(源码注释自证 "a timeout proves nothing: the edit can still commit"),与逐字打字兜底叠加 → 内容 ×2、尾部劈裂。
  4. payload 字节数学(chars×2+16)证明 commit 本身只含一份文本;重复由"迟到但真实落地的 TSF 插入 × 打字兜底"叠加造成,而非 commit 重复。

建议接受标准

  • windows_unicode_fallback 进入/完成写入日志(建议并入 insert-diagnostics:operation=insert_fallback_unicode、chars、result),从日志可直接判定走了兜底。
  • TSF NotDispatched/outcome-unknown 时不再无条件报 Ok(Inserted):至少在日志/用户可见文案中提示"文本可能已插入",并评估兜底前探测目标现有内容。
  • 评估兜底打字换行默认值:enter 在聊天类输入框会提交消息;考虑默认 shiftEnter 或在文档标注 enter 模式风险。
  • 回归用例:TSF NotDispatched + 多段文本 + 聊天类前台,断言目标只收到一份文本、无意外提交。

TODO / 不确定项

  • Codex Desktop composer 对 TSF 异步 apply 的确切时序未做 instrumentation(黑盒);"TSF 失败但实际已插入"由内容 ×2 观测与源码注释佐证,未逐帧取证。
  • 其他 Chromium/Electron 应用的 TSF 拒绝率未统计。

已验证的绕过

  • windowsInsertionMode = paste(剪贴板 + Ctrl+V 单次插入):本机实测不再出现重复/拆分,重启后配置稳定。
  • 或 windowsSendInputNewlineMode = shiftEnter:兜底打字不再提交消息,但 TSF × 兜底双插入风险仍在。

环境:Windows 11 Pro 10.0.26200 x64;OpenLess 2.0.2-Beta.3+build.141-c9f49c60。本 issue 不含转写正文,仅含长度、hash、session id 与日志结构。

主要语言
Rust
星标
3.7k
派生
349
平均合并
2 天 14 小时
30 天内合并 PR
97

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Open-Less/openless 的其他 Issue

查看 Open-Less/openless 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。