Repository navigation
Sweep fix: Caps Lock no longer blocks the dictation key or chord shortcuts - #2113
Merged
Merged
Conversation
With Caps Lock latched, every event tap flag set carries the capsLock bit, so the modifier-key matcher compared option|capsLock against a binding with no modifiers and the default Right Option key never started dictation. Caps Lock is a toggle, so the matcher and the recorder now ignore it for modifier-key bindings, the same way duplicate detection already did.
matchesKeyDown compared the binding against event modifiers that still had the Caps Lock bit, so Option-M (and any other chord) silently did nothing while Caps Lock was latched. Recording a chord with Caps Lock on also saved the bit, so that shortcut then only worked with Caps Lock on. Both now ignore Caps Lock.
Review follow-up. A binding recorded with Caps Lock on before this fix still carried the bit on disk, so pressing Caps Lock while holding Left Option counted as that dictation key, and Settings labelled it "Caps". Stored bindings now load with the bit stripped.
r3dbars
marked this pull request as ready for review
October 8, 2026 10:22
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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.
Two bugs from the Haiku sweep, one PR because they're the same fix: Caps Lock was being treated as a held modifier.
Caps Lock kills the Right Option dictation key
With Caps Lock latched, every event-tap flag set carries the capsLock bit.
isModifierBindingActivecomparedoption|capsLockminus option (so just capsLock) against the default binding's modifiers (0), got false, and dictation never started. Recording a modifier-key binding with Caps Lock on also saved the bit.testPhysicalDictationTriggerCapsLocksuites "The Right Option dictation key still presses and releases with Caps Lock on" and "A modifier chord recorded with Caps Lock on does not need Caps Lock to fire". Red before the fix (press didn't match, recorded binding had modifiers 32), green after.bindingForFlagsChangeddrops it when recording. Duplicate detection already did this.Caps Lock kills chord shortcuts (Option-M etc.)
matchesKeyDowncheckedbinding.modifiers == (modifiers & .all), and.allincludes capsLock, so Option-M with Caps Lock on was 0x04 vs 0x24 and just did nothing. Recording a chord with Caps Lock on stored the bit, so that shortcut then only worked with Caps Lock on.matchesKeyDowncompares with capsLock masked out of both sides, andbindingForKeyDowndoesn't record it. A real extra modifier (Command, Shift) still blocks a match; the test checks that too.The Caps Lock key's own binding path is unchanged.
Review follow-up: bindings saved by older builds
A key recorded with Caps Lock on before this fix still had the bit on disk. For something like Left Option + Caps, pressing Caps Lock while holding Option counted as the dictation key (could start dictation or swallow Caps Lock), and Settings labelled it "Caps". Stored bindings now load with the bit stripped (in
safeBinding, which every loader goes through).Overlaps
#2033 (removes dead paste-last / Hands-Free code) touches
PhysicalDictationTriggerPreferences.swiftand its test file, but different hunks: it doesn't touch the matchers orbindingFor*. I put the new tests in their own file (Tests/PhysicalDictationTriggerCapsLockTests.swift) so whichever lands second merges clean.Checks
bash run-tests.sh --filterfor testPhysicalDictationTriggerCapsLock, testPhysicalDictationTriggerPreferences, testPhysicalShortcutMatcher, testContextCaptureEnginePolicy, testHotkeyPreferences: all greenbash check.shon the combined branch with all sweep fixes: PASS (build, 42,163 fast tests, all 19 steps)bash build.sh --no-openon this branch alone: pass, plus the filtered suites abovecheck-source-pins.py --changed-only: passIndependent review: approve with nits; review fixes pushed. Remaining nits: none open on this one.
Re-review of the review fixes (round 2): approve. The new test goes red on the previous head; nothing new found.
🤖 Generated with Claude Code