App-scoped composer dictation shortcut should support tap-to-toggle and hold-to-talk
What version of the Codex App are you using (From "About Codex" dialog)?
ChatGPT/Codex app 26.707.31428 (CFBundleVersion 5059)
What subscription do you have?
Not relevant to this issue / not provided.
What platform is your computer?
macOS 26.5.2 (25F84), Apple Silicon (arm64)
What issue are you seeing?
Every app update, I have to reapply a local patch to restore natural keyboard behavior for native dictation in the composer.
I want one app-scoped composer shortcut, currently Command+Shift+D, to behave like this:
- Tap once: start dictation and leave it running.
- Tap again: stop dictation and insert the transcript.
- Press and hold: start dictation immediately, then stop and insert on release.
I do not want to use the OS-global dictation feature. I only want this shortcut active while the ChatGPT/Codex composer is focused.
The current app separates these into different command surfaces:
composer.startDictation: app-scoped, but currently behaves as hold-to-dictate because key-up always stops the recording.globalDictationToggle: global toggle.globalDictationHold: global hold-to-dictate.
That means the only supported way to get both toggle and hold behavior requires two global shortcuts. It also brings in global hotkey registration and the floating/global dictation UI, which are unnecessary for composer-only dictation.
I believe the composer shortcut behaved as a toggle in an earlier build. The regression from toggle to hold-only is also reported in #30208.
What steps can reproduce the bug?
- In Settings -> Keyboard Shortcuts, bind Start Dictation /
composer.startDictationtoCommand+Shift+D. - Leave the global Toggle Dictation and Hold to Dictate shortcuts disabled.
- Focus the composer.
- Quickly tap
Command+Shift+D.
Actual behavior:
- Dictation starts on key-down.
- Dictation stops immediately on key-up.
- A quick tap therefore cannot leave dictation running.
- Pressing the shortcut while dictation is already active does not provide an app-scoped toggle-off action.
What is the expected behavior?
The app-scoped composer shortcut should support the common hybrid interaction with one configurable key combination:
- A short tap toggles dictation on or off.
- A longer press acts as push-to-talk and stops on release.
- The shortcut remains app-scoped and does not register an OS-global listener or show the global dictation window.
An explicit mode setting for Toggle, Hold, or Hybrid would also solve the underlying problem, but hybrid behavior is especially ergonomic because it supports short and long dictation with one shortcut.
Additional technical information
The packaged renderer already receives both onKeyDown and onKeyUp for the app-scoped composer shortcut. In the current bundle, the handler roughly does this:
- On key-down, start dictation and mark the key as active.
- On key-up, if the key was active, stop dictation and insert the transcript.
- If dictation is already active, the key-down path exits instead of toggling it off.
A small local renderer patch proves the desired behavior can be implemented within the existing app-scoped path:
- Record the key-down timestamp.
- If dictation is already active on key-down, stop it as a toggle action.
- Otherwise start dictation immediately.
- On key-up, stop only when the press duration exceeds a threshold (currently 350 ms).
- For a shorter tap, leave dictation running.
This patch only changes the app-scoped renderer hotkey handler. It does not enable the global dictation commands. My local state is:
composer.startDictation = Command+Shift+D
globalDictationToggle = disabled
globalDictationHold = disabled
global-dictation-keep-visible = false
The workaround modifies app.asar, invalidates the sealed-resource signature, and is replaced by every app update, so it is not a sustainable user solution. The patch has had to be adapted repeatedly as minified asset names change, while the underlying handler behavior remains the same.
Related issues:
- #30208: composer dictation shortcut regressed from toggle to hold-only
- #27296 and #27657: global dictation shortcut failures, which are a separate path and part of why an app-scoped solution matters
- #30768: unwanted global dictation floating-window behavior