Skip to content

fix(insertion-windows): route per-codepoint Unicode SendInput through clipboard#363

Open
katanumahotori wants to merge 2 commits intoOpen-Less:betafrom
katanumahotori:fix/insertion-clipboard-fallback
Open

fix(insertion-windows): route per-codepoint Unicode SendInput through clipboard#363
katanumahotori wants to merge 2 commits intoOpen-Less:betafrom
katanumahotori:fix/insertion-clipboard-fallback

Conversation

@katanumahotori
Copy link
Copy Markdown
Contributor

@katanumahotori katanumahotori commented May 8, 2026

User description

Why

insert_via_unicode_keystrokes was injecting one KEYEVENTF_UNICODE SendInput per codepoint. On a Japanese host this competes with the active IME's composition state - hiragana ends up queued in the IME composition window while kanji / ascii get inserted ahead of it, so the user sees text reordered with kanji pushed to the end.

What

  • Route this path through the existing clipboard+Ctrl+V fallback so IME doesn't intercept individual codepoints.
  • Force the return value to InsertStatus::Inserted so coordinator.rs's gating logic doesn't double-paste via the non-TSF fallback path.
  • Split simulate_paste into per-OS impls so the keystroke synth is isolated to Linux (enigo Ctrl+V). Windows uses the same enigo path which is fine because Ctrl+V as a keyboard shortcut is not intercepted by IME composition (only KEYEVENTF_UNICODE is).

Note

Companion to #362 (force-skip TSF on non-zh hosts). Either PR alone helps; both together fully eliminate the Japanese-host text reorder bug.


PR Type

Bug fix


Description

  • Add send_text_with_ime_detached() to temporarily detach IME context during Unicode SendInput, preventing text reordering by Japanese IMEs

  • Modify insert_via_unicode_keystrokes to use the IME‑detached path and fall back to clipboard paste on failure

  • Update simulate_paste comment clarifying that Ctrl+V does not compete with IME

  • Add Win32_UI_Input_Ime feature dependency for IME context management


Diagram Walkthrough

flowchart LR
  A["insert_via_unicode_keystrokes()"] --> B["send_text_with_ime_detached()"]
  B --> C["Detach IME context (ImmAssociateContext)"]
  C --> D["Send Unicode keystrokes"]
  D --> E["Restore IME context"]
  E --> F["Result: text inserted without reordering"]
Loading

File Walkthrough

Relevant files
Bug fix
insertion.rs
IME-detached Unicode keystrokes to fix text reordering     

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

  • Add send_text_with_ime_detached() to temporarily detach and restore
    IME context
  • Update insert_via_unicode_keystrokes to use the new function and
    fallback to clipboard on error
  • Add comment explaining that Ctrl+V does not compete with IME in
    simulate_paste
  • Mark old send_text() with #[allow(dead_code)]
+65/-3   
Dependencies
Cargo.toml
Add IME feature dependency for Windows                                     

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

  • Add Win32_UI_Input_Ime feature to enable IME context API usage
+1/-0     

… clipboard

insert_via_unicode_keystrokes was injecting one KEYEVENTF_UNICODE
SendInput per codepoint. On a Japanese host this competes with the
active IME's composition state - hiragana ends up queued in the IME
composition window while kanji / ascii get inserted ahead of it, so
the user sees text reordered with kanji pushed to the end.

Route this path through the existing clipboard+Ctrl+V fallback so
IME doesn't intercept individual codepoints. Also force the return
value to InsertStatus::Inserted so coordinator.rs's gating logic
doesn't double-paste via the non-TSF fallback path.

Splits simulate_paste into per-OS impls so the keystroke synth is
isolated to Linux (enigo Ctrl+V), and Windows uses the same enigo
path which is fine because Ctrl+V as a *keyboard shortcut* is not
intercepted by IME composition (only KEYEVENTF_UNICODE is).
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

PR Reviewer Guide 🔍

(Review updated until commit 5805e20)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ❌

362 - Not compliant

Non-compliant requirements:

  • Force-skip TSF IME activation on non-Chinese hosts.
  • Add runtime host UI language detection on Windows.
  • Use a dynamic language ID for OpenLess TSF profile activation.
  • Suppress dead-code warnings for TSF helpers that become unused once the TSF path is gated.
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Status Mismatch

On Windows, the clipboard fallback returns its own insertion status instead of always reporting Inserted. If the coordinator treats a non-Inserted result as a signal to retry the non-TSF fallback, this can paste the same text twice when send_text_with_ime_detached fails.

Err(err) => {
    log::warn!(
        "[insertion] Unicode SendInput (IME-detached) failed: {err}; \
         falling back to clipboard paste"
    );
    self.insert(text, true)
}
Invalid Handle Check

The foreground-window null check uses hwnd.0.is_null(), but the HWND backing value is not a pointer type with an is_null() method. This will fail to compile on the Windows target; the handle needs to be compared against zero using the appropriate handle API.

if hwnd.0.is_null() {

@appergb
Copy link
Copy Markdown
Collaborator

appergb commented May 8, 2026

不符合要求:

通过短路 prepare_session() 函数,强制跳过非 zh 主机上的 TSF。
将 OPENLESS_TSF_LANG_ID 默认值从 0x0804 更新为 0x0411 。
将现在未使用的 TSF IPC/协议辅助程序标记为死代码。

@katanumahotori
Copy link
Copy Markdown
Contributor Author

Re: the previous comment — I think a copy was pasted from PR #362. Treating this PR on its own merits:

The original PR re-routed insert_via_unicode_keystrokes through the clipboard path because per-codepoint KEYEVENTF_UNICODE SendInput competes with IME composition state on Japanese hosts. That was a coarse fix; this revision keeps the original SendInput path but detaches the active IME context for the duration of the synthetic keystrokes, then restores it.

Implementation:

  • ImmAssociateContext(hwnd, HIMC::default()) before send_text
  • the existing per-codepoint SendInput
  • ImmAssociateContext(hwnd, original) + ImmReleaseContext after

So callers see the same behavior on zh / en hosts (Unicode SendInput goes through), but on Japanese hosts ATOK / Microsoft IME no longer reorders the kanji.

Please re-review.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit 5805e20

katanumahotori pushed a commit to katanumahotori/openless that referenced this pull request May 10, 2026
…llback

PR Open-Less#360 made TextInserter::insert require a 3rd PasteShortcut arg.
The fork-only insert_via_unicode_keystrokes (PR Open-Less#363, ATOK kanji-pushout
clipboard fallback) calls insert(text, true) — needed updating for the
new signature. Hardcoded CtrlV here because the clipboard fallback is
specifically engineered around Ctrl+V semantics on ATOK hosts; user's
configured paste_shortcut applies to the regular paste path.
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.

2 participants