Skip to content

Remove fn as a dictation-key option - #146

Merged
alexkroman merged 1 commit into
mainfrom
remove-fn-trigger-key
Aug 17, 2026
Merged

Remove fn as a dictation-key option#146
alexkroman merged 1 commit into
mainfrom
remove-fn-trigger-key

Conversation

@alexkroman

Copy link
Copy Markdown
Collaborator

What

Drops fn from TriggerKey, leaving right ⌘ (default) and right ⌥ as the dictation triggers.

Why

fn was the one option whose down/up state came from the shared kCGEventFlagMaskSecondaryFn bit rather than an NX_DEVICE* per-side bit. Every other trigger holds the invariant TriggerKey.deviceModifierMask was introduced for — one mask names exactly one physical key, so a release is unambiguous even with the other side held. fn sat outside that family, and its doc comment had to carve out an exception for itself.

Migration

None needed, by construction. TriggerKey's rawValue is the persisted macOS keycode, and fromPersisted(_:) — the single decode-with-default rule shared by TriggerKeyStore and the @AppStorage views — maps any unrecognized code to right ⌘. So an existing fn binding (keycode 63) decodes to the default rather than an invalid selection. removedFunctionFallsBack pins that, alongside the two options removed before it (right ⌃ = 62, Caps Lock = 57).

deviceModifierMask is an exhaustive switch with no default:, so removing the case is a compile error at every use site rather than a runtime surprise — which is what makes the removal provably complete.

Scope

  • Sources/BlurtEngine/Hotkey/TriggerKey.swift — case, mask, label, and the doc-comment carve-out
  • Tests/BlurtEngineTests/TriggerKeyTests.swift.function assertions out, fallback test in
  • README.md, AGENTS.md, Sources/BlurtEngine/README.md — trigger list

The Settings picker iterates TriggerKey.allCases, so it loses the row with no UI edit. DictationKeyTap.flag(for:) just wraps deviceModifierMask. SettingsUITests.testHotkeyPickerChangesSelection exercises right ⌥ and is unaffected.

Verification

scripts/check.sh green locally — 581 tests pass, the ≥88% engine coverage gate holds, periphery reports no unused declarations left behind, app builds. UI suite and leak scan skipped locally by design; CI covers those.

🤖 Generated with Claude Code

`fn` was the one trigger whose down/up state came from the shared
`kCGEventFlagMaskSecondaryFn` bit rather than an `NX_DEVICE*` per-side
bit, so it sat outside the invariant the other two options hold: one
mask names exactly one physical key. Dropping it leaves right ⌘ and
right ⌥, both right-side device bits.

No migration code needed: `TriggerKey`'s `rawValue` *is* the persisted
keycode and `fromPersisted(_:)` maps anything unrecognized to right ⌘,
so an existing `fn` binding decodes to the default rather than an
invalid selection. Covered by a regression test alongside the two
options removed before it (right ⌃, Caps Lock). The Settings picker
iterates `allCases`, so it loses the row with no UI change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@alexkroman
alexkroman added this pull request to the merge queue Aug 17, 2026
Merged via the queue into main with commit 4cb6cd3 Aug 17, 2026
10 checks passed
@alexkroman
alexkroman deleted the remove-fn-trigger-key branch August 17, 2026 16:40
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