Skip to content

fix(indicator): don't flash indicator when app switch keeps the same input source - #130

Open
doggy8088 wants to merge 1 commit into
runjuu:mainfrom
doggy8088:fix/indicator-same-source-flash
Open

fix(indicator): don't flash indicator when app switch keeps the same input source#130
doggy8088 wants to merge 1 commit into
runjuu:mainfrom
doggy8088:fix/indicator-same-source-flash

Conversation

@doggy8088

Copy link
Copy Markdown

Purpose

When switching from one app to another that resolves to the same input source (a cached keyboard, a per-app specified keyboard, or the system-wide default), Input Source Pro still selected the source and flashed the switch indicator — even though nothing actually changed. Going from an app in EN state to another app in EN state showed the indicator on every app switch.

This PR makes the indicator announce real input-source changes only, and skips the redundant TISSelectInputSource call when the target keyboard is already active.

Closes #126

Summary of changes

  • IndicatorVM+Triggers.swift.appChanges activate events now carry an inputSourceDidChange flag (computed from the input sources' persistent identifiers) so the indicator layer can distinguish real keyboard switches from no-op app switches. Added an isAppChangesWithUnchangedInputSource helper and updated pattern matches / log description.
  • IndicatorVM.swift — in the .appChanged action, when the resolved keyboard equals the current one, skip inputSourceVM.select (no redundant TIS select and no CJKV fix dance) and record the state reason as .noChanges. Keyboard cache learning ("restore previously used keyboard") still runs for the new app.
  • IndicatorWindowController.swift — unchanged-keyboard app switches route to the hide path instead of autoHidePublisher, so the indicator no longer pops up.
  • IndicatorWindowController+Activation.swiftautoShowPublisher suppresses its initial activation for unchanged keyboards while keeping the freshly rebuilt focus-detection watcher active, so focus-based show/hide keeps working.
  • Tests/ActivateEventInputSourceChangeTests.swift (new, registered in the Tests target) — unit tests for the new event flag.

Behavior notes

  • Different-keyboard app switches still announce the indicator exactly as before.
  • The always-on indicator keeps receiving .appChanges, so it stays steady (no hide/re-show flicker) on same-keyboard app switches.
  • With "Hide When Default Keyboard Rule Is Applied" enabled, an unchanged keyboard now consistently hides the indicator (previously a cached source would still show it) — nothing switched, so there is nothing to announce.
  • Shortcut- and system-driven input-source changes are untouched; per-app "Hide Indicator" rules still take precedence.
  • No new preference keys — no localization or settings-backup changes required.

Testing notes

  • xcodebuild -scheme "Input Source Pro" -configuration Debug buildBUILD SUCCEEDED
  • xcodebuild -scheme "Input Source Pro" -configuration Debug testTEST SUCCEEDED (all suites, including the 3 new tests in ActivateEventInputSourceChangeTests)
  • Manual smoke performed:
    • Switch between two apps that resolve to the same keyboard → no indicator flash
    • Switch to an app with a different configured keyboard → indicator appears as before
    • Always-on indicator remains visible across app switches

Screenshots

No UI changes — behavior-only fix for the scenario shown in #126 (comment) (EN → EN app switch previously always flashed the indicator).

…input source

Switching between two apps that resolve to the same input source (via a
cached keyboard, a per-app specified keyboard, or the system-wide default)
still called TISSelectInputSource and popped up the switch indicator every
time, even though the input method never actually changed. Users going
from an app in EN state to another app in EN state saw the indicator flash
on every app switch.

Root cause: IndicatorVM always selected the resolved keyboard on app
changes, and stateChangesPublisher emitted .appChanges for every app-kind
change, which IndicatorWindowController unconditionally treated as
"show the indicator".

Changes:
- ActivateEvent.appChanges now carries inputSourceDidChange so the
  indicator layer can tell real keyboard switches from no-op ones;
  add isAppChangesWithUnchangedInputSource helper
- IndicatorVM skips the redundant TIS select (and the CJKV fix dance)
  when the target keyboard equals the current one and marks the state
  as .noChanges; keyboard cache learning (restore previously used
  keyboard) still runs for the new app
- IndicatorWindowController routes unchanged-keyboard app switches to
  the hide path instead of showing the indicator
- autoShowPublisher suppresses its initial activation for unchanged
  keyboards while keeping the freshly rebuilt focus-detection watcher
  active, so focus-based show/hide keeps working
- Add ActivateEventInputSourceChangeTests covering the new event flag

Behavior notes:
- Different-keyboard app switches still announce the indicator as before
- The always-on indicator keeps receiving .appChanges, so it no longer
  flickers on same-keyboard app switches
- isHideWhenSwitchAppWithForceKeyboard now consistently hides the
  indicator when the keyboard is unchanged (previously "cached" sources
  would still show); nothing switched, so there is nothing to announce
- No new preference keys, no localization or settings backup changes

Fixes runjuu#126
Copilot AI lite review requested due to automatic review settings August 27, 2026 14:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is narrowly scoped, updates all relevant call sites consistently, and includes targeted unit tests for the new event-flag behavior.

Pull request overview

This PR prevents the indicator from “announcing” app switches that resolve to the same active input source by (1) detecting whether an app switch actually changed the input source (via persistent identifiers) and (2) routing unchanged-input-source app switches through non-show/hide paths so the indicator doesn’t flash.

Changes:

  • Extend IndicatorVM.ActivateEvent.appChanges to include an inputSourceDidChange flag and add a helper to detect unchanged-input-source app switches.
  • Skip redundant TISSelectInputSource on .appChanged when the resolved input source is already active, marking the reason as .noChanges.
  • Update indicator activation/show-hide routing to suppress popups on unchanged-input-source app switches, and add unit tests for the new event flag.
File summaries
File Description
Tests/ActivateEventInputSourceChangeTests.swift Adds tests validating unchanged/changed input-source flags on .appChanges.
Input Source Pro/Models/IndicatorVM+Triggers.swift Adds inputSourceDidChange to app-change events and exposes isAppChangesWithUnchangedInputSource.
Input Source Pro/Models/IndicatorVM.swift Skips redundant input-source selection when persistent identifiers match; records .noChanges.
Input Source Pro/Controllers/IndicatorWindowController.swift Routes unchanged-input-source app switches to justHidePublisher() to prevent indicator popups.
Input Source Pro/Controllers/IndicatorWindowController+Activation.swift Suppresses initial auto-show activation on unchanged-input-source app switches while keeping focus detection active.
Input Source Pro.xcodeproj/project.pbxproj Registers the new test file in the Tests target sources and project groups.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

Feature request: Hide the input method switch indicator

2 participants