Skip to content

fix(windows-ime): TSF 插入后输入法未切回原输入法(#852) - #914

Merged
H-Chris233 merged 4 commits into
Open-Less:betafrom
H-Chris233:codex/fix-852-ime-restore
Aug 5, 2026
Merged

fix(windows-ime): TSF 插入后输入法未切回原输入法(#852)#914
H-Chris233 merged 4 commits into
Open-Less:betafrom
H-Chris233:codex/fix-852-ime-restore

Conversation

@H-Chris233

@H-Chris233 H-Chris233 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

User description

背景

Windows 11 以 TSF 输入法为插入模式时,听写结束(录音结束)后输入法停在 OpenLess,没有切回用户原输入法(issue #852)。

根因

  • 恢复决策依赖 is_openless_profile_active()(ITfInputProcessorProfileMgr::GetActiveProfile)的探测结果,只有返回 true 才恢复。该探测运行在 OpenLess 自己进程的后台线程上,而 OpenLess IME 激活发生在目标 App 进程,GetActiveProfile 可能返回线程本地的默认配置 → 误判为“用户已切走”而跳过恢复。

estore_profile 中 legacy 两步失败会用 ? 短路,导致现代 ActivateProfile 根本不执行,恢复整体失败。

  • 若上次会话已停在 OpenLess,下次会话会把 OpenLess 本身捕获为“原输入法”,失败状态自粘。

改动

estore_decision 改为依据会话已知的激活状态(openless_was_activated / ^Gctivation_failed)决定恢复,不再依赖探测结果。

estore_profile 中 legacy 与现代调用各自独立执行并分别记录结果;任一成功即视为整体成功,两者都失败才算失败。

restore_session 以 restore_profile 返回值判定成败(legacy 与现代均失败才算失败),失败后 250ms 重试一次;恢复后探测(GetActiveProfile)仅作诊断日志,不参与控制流。

  • 粘滞态防护:saved 快照本身是 OpenLess 时跳过恢复并告警(避免把 OpenLess 当原输入法写死)。
  • prepare_session /
    estore_session 增加诊断日志(决策依据、恢复前 active profile、恢复结果),便于区分“未走恢复 / 恢复被跳过 / 恢复失败”。

已知限制

  • 粘滞态防护:若上次会话恢复失败、本次会话开始时 OpenLess 已是当前输入法(原输入法信息已丢失),恢复会被跳过,用户需要手动切回一次输入法。该场景下 issue [area] Windows上以TSF输入法为插入模式时,输入完毕后应当切换回原输入法 #852 的验收标准不适用。
  • 恢复后探测(GetActiveProfile)运行在 OpenLess 进程后台线程,与目标 App 线程的 TSF 状态可能不一致,因此仅作诊断日志;重试依据为 restore_profile 返回值。

测试

  • cargo test --lib windows_ime:41/41 通过(含新增的 openless_snapshot_detection_matches_exact_profile_identifiers、
    eport_restore_step_results 用例与更新的
    estore_decision 用例)。
  • 全量 cargo test --lib:933/936;3 个失败均为环境/顺序相关(Windows symlink 权限 1314、两个单跑通过的 flaky),与本次改动无关。

closes #852


PR Type

Bug fix, Tests


Description

  • Fix IME restore relying on session activation

  • Legacy and modern restores independent; any success passes

  • Sticky-state guard, retry, and diagnostic logging

  • Cross-platform restore module with unit tests


Diagram Walkthrough

flowchart LR
  A["Session begin: capture original IME"] --> B["Activate OpenLess"]
  B --> C["Recording / TSF insertion ends"]
  C --> D["restore_decision uses session facts"]
  D --> E["run_restore_flow: sticky guard & retry"]
  E --> F["legacy + modern restore"]
  F --> G["Diagnostic probe only"]
Loading

File Walkthrough

Relevant files
Tests
backend_rust.rs
Add new IME modules to backend tests                                         

openless-all/app/src-tauri/backend-tests/tests/backend_rust.rs

  • Include windows_ime_profile and windows_ime_restore modules in backend
    test harness
  • Enables cross-platform unit testing of the new restore flow
+4/-0     
Enhancement
lib.rs
Register windows_ime_restore module                                           

openless-all/app/src-tauri/src/lib.rs

  • Register the new windows_ime_restore module
  • Keep module visible to the rest of the crate
+1/-0     
windows_ime_restore.rs
Create cross-platform restore flow module                               

openless-all/app/src-tauri/src/windows_ime_restore.rs

  • Add new cross-platform run_restore_flow with sticky guard, retry, and
    diagnostic verification
  • Add RestoreOutcome enum and retry delay constant
  • Implement sleep_restore_retry that avoids blocking tokio worker
    threads
  • Add six unit tests covering skip, success, retry, and failure
    scenarios
+238/-0 
Bug fix
windows_ime_profile.rs
Make restore decision session-based and restore paths independent

openless-all/app/src-tauri/src/windows_ime_profile.rs

  • Add is_openless_profile_snapshot helper for sticky-state detection
  • Change restore_decision to rely on session activation facts instead of
    background-thread probe
  • Extract report_restore_step_results and resolve_restore_args for
    independent legacy/modern restore execution
  • Update tests for new decision semantics and restore step success rules
+183/-74
windows_ime_session.rs
Use session facts and restore flow for IME restore             

openless-all/app/src-tauri/src/windows_ime_session.rs

  • Update restore_session to use run_restore_flow and session activation
    facts
  • Replace probe-dependent decision with restore_decision based on
    confirmed activation state
  • Add diagnostic logging for saved profile, decision, and active profile
  • Add tests for confirmed activation state restore semantics
+75/-35 
Dependencies
Cargo.toml
Add dependencies for IME restore tests                                     

openless-all/app/src-tauri/backend-tests/Cargo.toml

  • Add tokio with multi-thread runtime feature for testing retry delays
  • Add Windows feature flags and winreg dependency required by IME
    restore tests
+13/-0   

- restore_decision 改为依据会话已知的激活状态(openless_was_activated / activation_failed),不再依赖 GetActiveProfile 探测结果,避免后台线程误判导致跳过恢复
- restore_profile 中 legacy 失败不再短路现代 ActivateProfile,任一成功即视为整体成功
- restore_session 增加恢复后校验与一次重试;saved 本身是 OpenLess 时跳过(粘滞态防护)
- prepare/restore 补充诊断日志,便于区分未走恢复/恢复被跳过/恢复失败
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dbaea91)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

852 - Partially compliant

Compliant requirements:

  • 正常会话场景(会话确实激活过 OpenLess 且捕获到非 OpenLess 原输入法快照)下,恢复决策改为依据会话激活事实,不再依赖不可靠的 GetActiveProfile 探测。
  • 恢复流程对 legacy/现代 API 分别执行,并在恢复 API 失败时重试一次,增强恢复鲁棒性。

Non-compliant requirements:

  • 粘滞态场景:若上次会话恢复失败、本次会话开始时 OpenLess 已是当前输入法,恢复会被跳过,不能保证“结束录音后切回原输入法”。

Requires further human verification:

  • 需要在真实 Windows 11 + TSF 环境下验证恢复是否真正生效,尤其是 legacy 失败但 modern 成功、或 restore API 返回成功但输入法仍停留在 OpenLess 的情况。
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

restore_profile 将“legacy 与现代任一成功”视为整体成功,并在 report_restore_step_results 中返回 Ok。但同一函数上方的注释写明:单独调用现代 ActivateProfile 不会更新 legacy current language / active profile 状态,OS 仍会认为 OpenLess 是当前输入法。因此在 legacy 失败而 modern 成功时,run_restore_flow 收到 Ok 后不会重试,用户可能仍停留在 OpenLess,issue #852 在该场景下仍可能复现。该问题成立的前提是 modern-only 激活不足以切换用户可见输入法;若实际足以切换,则可忽略。

match (legacy_result, modern_result) {
    (Ok(()), _) | (_, Ok(())) => Ok(()),
    (Err(legacy_error), Err(modern_error)) => Err(WindowsImeProfileError::WindowsApi(
        format!(
            "both legacy and modern restore failed: legacy={legacy_error}; modern={modern_error}"
        ),
    )),
}

@H-Chris233
H-Chris233 marked this pull request as ready for review August 4, 2026 11:29
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 2178958

- restore_profile 合并 TextService/KeyboardLayout 同形分支,差异收敛为参数
- 恢复重试等待在 tokio runtime 上改用 block_in_place 让出工作线程
- 粘滞防护/校验/重试抽为 run_restore_flow,可跨平台注入测试
- 新增 5 个恢复流程测试(粘滞跳过/一次成功/重试/restore 报错仍校验/探测报错)
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 49dbd0b

- run_restore_flow 重试条件改为 restore_profile 返回值(legacy+modern 均失败才重试)
- is_openless_profile_active 探测降级为恢复后诊断日志,不再参与控制流(线程局限见 Open-Less#852)
- 更新恢复流程测试覆盖新语义(6 个用例,47/47 通过)
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dbaea91

@H-Chris233 H-Chris233 self-assigned this Aug 5, 2026
- 新增 windows_ime_restore 模块:run_restore_flow/RestoreOutcome/重试等待
  迁出 windows_ime_session;sleep_restore_retry 增加 MultiThread runtime 守卫
- report_restore_step_results 提升为无门控顶层函数,测试可在任意平台执行
- restore_profile 参数收敛为 RestoreArgs 结构体(resolve_restore_args)
- 测试夹具 openless_snapshot_for_test 由生产常量派生,替换重复 GUID 字面量
- restore_session 消费 RestoreOutcome 补 debug 诊断日志
- backend-tests 纳入 windows_ime_profile/windows_ime_restore(tokio/winreg/features)
- 新增 9 个单测现已在 macOS/Linux cargo test --lib 与 Windows backend-tests 执行
@H-Chris233
H-Chris233 merged commit f22eb54 into Open-Less:beta Aug 5, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[area] Windows上以TSF输入法为插入模式时,输入完毕后应当切换回原输入法

1 participant