Skip to content

Add "On Layout Switch" correction mode, permissions menu, and broader layout detection#4

Open
v-ivanyshyn wants to merge 5 commits into
rundax:masterfrom
v-ivanyshyn:correction-on-layout-change
Open

Add "On Layout Switch" correction mode, permissions menu, and broader layout detection#4
v-ivanyshyn wants to merge 5 commits into
rundax:masterfrom
v-ivanyshyn:correction-on-layout-change

Conversation

@v-ivanyshyn

Copy link
Copy Markdown

1. New correction mode: "On Layout Switch"
Introduces CorrectionMode.layoutSwitch as a third option next to automatic and hotkey. When enabled, SwitchFix observes NSTextInputContext.keyboardSelectionDidChangeNotification and, on a real layout change, transcribes either:

the currently selected text (via Permissions.getSelectedText()), or
the current in-progress word buffer from LayoutDetector,
from the previous layout into the new one — without triggering an additional layout switch (new shouldSwitchLayout flag on TextCorrector.performSelectionCorrection and DetectionResult).

A new helper AppDelegate.textContainsScript(of:text:) skips conversion when the selected text doesn't actually contain letters of the source layout's script (Latin for English, Cyrillic for Ukrainian/Russian), preventing spurious transcriptions of already-foreign text.

UI:
SettingsView exposes the new mode with a descriptive caption.
StatusBarController adds an "On Layout Switch" item to the Correction Mode submenu.

2. Permissions visible in the menu bar
StatusBarController now surfaces missing Accessibility and Input Monitoring permissions directly in the status bar menu, with click-through items that open the relevant System Settings panes (openAccessibilitySettings / openInputMonitoringSettings). The menu bar tooltip reflects a "missing permissions" state, and the indicators refresh every time the menu opens — so users can grant permissions after first launch without restarting the app.

3. Wider input-layout coverage
LayoutMapper matches input source IDs by suffix (e.g. keylayout.US) instead of exact full bundle IDs, and adds USExtended to the English set. This accommodates third-party and non-com.apple.keylayout.* sources. InputSourceManager now logs any unmatched input sources to aid diagnostics and avoids repeated matching work per source.

Files changed
Sources/Core/InputSourceManager.swift — single-pass matching + unmatched-source logging
Sources/Core/LayoutMapper.swift — suffix-based matches(sourceID:), added USExtended
Sources/Core/LayoutDetector.swift — public memberwise initializer for DetectionResult
Sources/Core/TextCorrector.swift — optional shouldSwitchLayout parameter
Sources/SwitchFixApp/AppDelegate.swift — layout-change observer, triggerLayoutSwitchCorrection, textContainsScript helper, correction-in-progress guard
Sources/UI/PreferencesManager.swift — new CorrectionMode.layoutSwitch case
Sources/UI/SettingsView.swift — picker option + per-mode description
Sources/UI/StatusBarController.swift — permission menu items, tooltip, new mode entry

@Hantok

Hantok commented Jul 8, 2026

Copy link
Copy Markdown
Member

@codex review

@Hantok Hantok self-assigned this Jul 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64352cc862

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +263 to +264
let fromVariant = inputSourceManager.currentUkrainianVariant() ?? inputSourceManager.preferredUkrainianVariant()
let toVariant = inputSourceManager.preferredUkrainianVariant()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Track actual Ukrainian variants during layout switches

When layout-switch correction involves Ukrainian and the user has both standard and legacy Ukrainian sources installed, these values can use the wrong keymap: the notification is handled after the system has already switched, so currentUkrainianVariant() describes the new layout when switching into Ukrainian and is nil when switching out, while toVariant is always the preferred/first discovered source. For example, switching English → Ukrainian Legacy will still convert with the preferred standard mapping, so letters on the s/b positions are transcribed incorrectly for both selection and buffer correction.

Useful? React with 👍 / 👎.

"com.apple.keylayout.USInternational-PC",
"com.apple.keylayout.Colemak",
"com.apple.keylayout.Dvorak",
"keylayout.US",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep switch fallbacks as selectable source IDs

These entries are now suffix fragments, but InputSourceManager.switchTo still builds its fallback targetIDs from Layout.inputSourceIDs and compares them to TIS source IDs with exact equality. If a supported Apple layout is added after startup, or installedSourceIDs is otherwise not populated for the target, the fallback now tries values like keylayout.US instead of com.apple.keylayout.US, so corrections cannot switch to that layout until the app rediscovers it or restarts.

Useful? React with 👍 / 👎.

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.

2 participants