Repository navigation
Right Option dictation starts on key press, not on release - #1858
Merged
Merged
Conversation
Hands-free on right Option waited for the key to come back up whenever another shortcut also used Option (the defaults do: Option+M and Option+Shift+V), so every start silently added the whole hold, about 0.1 to 0.2 s. Almost all real starts are this tap. It now fires on press unless a key was typed in the last second, where a right Option press is more likely a combo like Option+E for é. If another key goes down while it is still held, the detector reports comboInterrupted and the dictation that press started is dropped with no sound, error, or saved audio, and the combo runs as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016DYGa1i8HDv497ewpWgaCM
Review fixes: - A right Option press during a dictation stops and pastes it, which a following combo key can't undo (Option+Shift+V pasted twice, Option+M cut the take). Those presses wait for release again; only a start fires on press. The engine mirrors isDictating into the detector. - A dropped combo start now sends dictation_start_dropped_for_modifier_combo (duration_bucket, trigger), so the start funnel doesn't read it as a lost start. Allowlisted and listed in the privacy doc. - A combo on a press that only queued a start behind a finishing take drops the queued start. - Moved the orphaned cancelDictation doc comment back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016DYGa1i8HDv497ewpWgaCM
r3dbars
marked this pull request as ready for review
September 25, 2026 16:53
r3dbars
pushed a commit
that referenced
this pull request
Sep 25, 2026
6 tasks done
14 of 19 tasks
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.
Requested by Justin · project thread
Why
Before: a right Option tap (the default hands-free key) only counts when you let go of it, because Option+M (meeting) and Option+Shift+V (paste last) also use Option. So every hands-free start quietly adds however long the key is held, about 0.1 to 0.2 s, and none of the logged start timings include it. On Justin's Mac, 289 of about 294 recent dictations were this tap.
After: the tap counts the moment the key goes down, so dictation (and the start click from #1857) begins that much sooner. If another key goes down while right Option is still held (Option+M, or typing é with Option+E), the dictation that press started is dropped quietly and the combo works as before.
Waiting on Justin's pick on the decision card in the thread. Don't merge until he chooses "Start on press".
Product Impact
dictationdictation reliabilityWhat changed
PhysicalShortcutMatcher.firesSharedModifierOnPress(secondsSinceLastTypedKey:): a hands-free modifier that other shortcuts share fires on press, unless a key was typed in the last second. Mid-typing, right Option is more likely the start of a combo, so it keeps waiting for release there.ContextCaptureEnginedetector: it records when a key was last typed. When the shared hands-free modifier fires on press, it remembers the key until release. Any key that goes down while it's still physically held sends a new.comboInterruptedphase. A missed release (tap disabled) orresetStateclears it.ContextCaptureEnginerouting: it remembers the session a hands-free press started. On.comboInterruptedit calls the newDictationSessionController.abandonDictationStartForModifierCombo(sessionID:), which cancels that exact session with no sound, no error overlay, and no saved audio, and writes a localdictation_start_dropped_for_modifier_combolog line. A press that stopped a dictation is left alone.Sources/Capture/CLAUDE.mddocuments the behavior and adds a manual check.How I checked it
scripts/dev/agent-preflight.shbash scripts/dev/linux-checks.sh(runs without Swift): 48 passed, 0 failed.agents/test-matrix.ymlfor the files changed (source pins)bash build.sh --no-open(CI)bash run-tests.sh(CI). New suite inTests/PhysicalShortcutMatcherTests.swiftbash run-integration-smoke.sh: not needed, noSources/Meeting/or Core changesswift test: not neededbash run-e2e-smoke.sh: not mappedChecks I could not run, and why:
Mac or hardware test still needed? Yes:
events.jsonlshowsdictation_start_requestedclose to the physical press. Onmainit only starts after release.dictation_start_dropped_for_modifier_combo. Onmainno dictation starts at all.main.Risk Review
.info).check-source-pins.py --changed-only: pass; read theContextCaptureEngine.swiftpins inContextCaptureEnginePolicyTests,DictationQueuedStartPolicyTests,DictationRecordingStartOverlayPolicyTests)Notes
dictation_start_requestedbut sends no terminal PostHog event, so it shows up as an attempt without an outcome. That's acceptable at the expected rate. If it's noisy, a follow-up can add afailure_kind.Agent handoff
COORD_DONE: BRIEF | this PR | right Option hands-free fires on press, quiet drop on combo | none | Justin's pick on the card, then CI + deep review + Mac check | linux-checks, source pins | wait for his pick🤖 Generated with Claude Code
https://claude.ai/code/session_016DYGa1i8HDv497ewpWgaCM
Generated by Claude Code