fix(ui): follow-up fixes for the ascii_mode status icon#1159
Open
metalbreeze wants to merge 3 commits into
Open
fix(ui): follow-up fixes for the ascii_mode status icon#1159metalbreeze wants to merge 3 commits into
metalbreeze wants to merge 3 commits into
Conversation
Switching to Squirrel produces no flagsChanged event, so state established while another input source was active goes unnoticed. Two consequences fixed in activateServer: - lastModifiers may hold a stale Caps Lock bit, so the user's first Caps Lock press after switching in compares equal to lastModifiers and is swallowed by the early-return in handle(). Seed the bit from CGEventSource.flagsState(.combinedSessionState) — NSEvent's modifierFlags only reflects this process's own event stream and is stale at activation time. - The icon may not reflect the session's actual ascii_mode: sessions are torn down and rebuilt around input-source switches, and a fresh session initializes its options from the schema (switches/@N/reset) without firing any option notification — the icon keeps showing the pre-switch state while the session actually starts in the schema's reset state. Repaint it silently from the actual state on every activation. set_option is deliberately not used for this: re-asserting an option fires the notification and would flash the status bubble on every app switch. Nor is ascii_mode ever written from the observed Caps Lock: macOS clears Caps Lock when the input source changes, so a Caps Lock seen at activation is transient and acting on it would race that clearing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The status icon's visibility follows the kTISNotifySelectedKeyboardInputSourceChanged distributed notification. The block-based addObserver(forName:object:queue:using:) registers with a suspension behavior that holds notifications back while the process is not active — which is precisely Squirrel's state right after the user switches to another input source. The "hide now" notification then sat undelivered until the next activation, so the icon lingered in the menu bar while ABC was selected. Register with suspensionBehavior: .deliverImmediately (selector-based API) so the notification arrives regardless of activation state, and hop to the main queue before touching NSStatusItem. The observer is already removed in applicationWillTerminate via DistributedNotificationCenter.removeObserver(self). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Silences the SwiftLint unused_parameter warning; #selector resolution is unaffected by the anonymous parameter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two follow-up fixes for the menu-bar status icon introduced in #1122, found while testing across input-source switches.
1. Keep status icon and modifier state in sync on activation
Switching to Squirrel produces no
flagsChangedevent, so state established while another input source was active goes unnoticed:lastModifiersmay hold a stale Caps Lock bit; the user's first Caps Lock press after switching in then compares equal to it and is swallowed by the early-return inhandle(). Seed the bit fromCGEventSource.flagsState(.combinedSessionState)—NSEvent.modifierFlagsonly reflects this process's own event stream and is stale at activation time.switches/@N/resetwithout firing any option notification — the icon keeps showing the pre-switch state while the session actually starts in the reset state (the icon says 中 while typing produces English). Repaint the icon silently from the actual state on every activation.set_optionis deliberately not used for this: re-asserting an option fires the notification and would flash the status bubble on every app switch. Nor isascii_modeever written from an observed Caps Lock — macOS clears Caps Lock whenever the input source changes, so a Caps Lock seen at activation is transient and acting on it would race that clearing.2. Hide the status icon reliably when switching away from Squirrel
The block-based
addObserver(forName:object:queue:using:)onDistributedNotificationCenterregisters with a suspension behavior that holds notifications back while the process is not active — which is precisely Squirrel's state right after the user switches to another input source. The "hide now" notification sat undelivered until the next activation, so the icon lingered in the menu bar while ABC was selected. Register selector-based withsuspensionBehavior: .deliverImmediatelyinstead; the handler also keeps performing the #1140 stranded-composition cleanup.Testing
show_notifications_when: appropriate, no status-bubble flashes on app switches.🤖 Generated with Claude Code