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

オープン
#1,318 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
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時間
マージ済み PR(30日)
97

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Open-Less/openless のほかの issue

Open-Less/openless の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。