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

Ouverte
#1,318 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
18/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
Active
Stack technique
rust, tauri
Domaine
desktop

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

现象

  • 触发条件: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 与日志结构。

Langage dominant
Rust
Étoiles
3.7k
Forks
349
Merge moyen
2 j 14 h
PR mergées (30 j)
97

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de Open-Less/openless

Toutes les issues de Open-Less/openless

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.