Skip to content

fix: reliable IME switch on macOS 26 Tahoe (postEvent HID source + timing)#118

Merged
kazukinakai merged 1 commit into
mainfrom
fix/tahoe-postevent-hid-source
Jul 3, 2026
Merged

fix: reliable IME switch on macOS 26 Tahoe (postEvent HID source + timing)#118
kazukinakai merged 1 commit into
mainfrom
fix/tahoe-postevent-hid-source

Conversation

@kazukinakai

Copy link
Copy Markdown
Member

Root cause (researched, not guessed)

Confirmed on-device: macOS 26.5.1 (Tahoe). Reference: macism, the battle-tested CJK input-source switcher, documents that macOS 26 tightened input-event timing (older macOS needed ~1ms, Tahoe needs much longer).

cmd-ime's postEvent() — which posts the Eisu(102)/Kana(104) key to switch the frontmost app's IME — used two pre-Tahoe patterns that Tahoe now drops:

  1. nil CGEventSource (macism uses a real CGEventSource(stateID: .hidSystemState)).
  2. key-up posted immediately after key-down, no gap (macism spaces them ~50ms).

Result: on Tahoe the synthesized key is dropped and the switch silently fails in normal apps — the regression the user hit.

Why not TIS: TISSelectInputSource alone only moves the menu-bar indicator unless the caller forces activation (the "menu shows あ but types direct" bug — also documented by macism). macism forces it with a focus-stealing temporary window, which is fine for a one-shot CLI but unacceptable for a background switcher that must not yank focus from the app you're typing in. So the correct primitive for cmd-ime is posting the key, done right.

Fix

  • postEvent(): real HID event source + key-up dispatched ~50ms after key-down (async, so the event-tap callback on the main run loop is never blocked).
  • Revert to a single switch mechanism (post the key) and remove the v2.4.7–2.4.9 TIS special-casing (InputSourceSwitcher, isTISSwitchApp, palette-avoidance) — that whole detour was the wrong primitive for a live switcher and caused the palette-window and half-switch regressions.

Tests

  • KeyEventTests: Kana/Eisu remap output passes through on keyDown/keyUp (the key that drives the IME).
  • InputSourceDumpTests: skippable on-device diagnostic (CMDIME_DUMP_INPUT_SOURCES=1) that enumerates installed IMEs' TIS structure — how the Google single-mode-source fact was established.
  • swift build clean · 32 tests (1 skipped, 0 failures) · swiftlint 0 serious.

Needs on-device confirmation (IME switching can't be verified headless): after auto-update, press the switch key in a normal app (メモ/TextEdit) and confirm it actually types Hiragana.

Version 2.4.10.

Root cause (researched against macism, the reference CJK input switcher):
macOS 26 Tahoe tightened input-event timing. cmd-ime's postEvent() used a
nil CGEventSource and posted key-up immediately after key-down, which Tahoe
now drops — the Eisu/Kana switch silently fails in normal apps (regression
vs. older macOS).

Fix postEvent() to match macism's proven approach:
  - real HID event source (CGEventSource(stateID: .hidSystemState)) not nil
  - space key-up ~50ms after key-down, dispatched async so the event-tap
    callback (main run loop) is never blocked

Also revert the Eisu/Kana switch to a single mechanism (posting the key,
which drives the IME's internal Hiragana/direct mode without stealing focus)
and remove the v2.4.7-2.4.9 TIS special-casing: bare TISSelectInputSource
only moves the menu-bar indicator unless the caller forces activation, and
the focus-stealing window workaround macism uses for its CLI is unacceptable
for a background switcher.
@kazukinakai kazukinakai enabled auto-merge July 3, 2026 13:53
@kazukinakai kazukinakai merged commit 2029d15 into main Jul 3, 2026
2 checks passed
@kazukinakai kazukinakai deleted the fix/tahoe-postevent-hid-source branch July 3, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant