A Stream Deck plugin and a Hammerspoon shortcut that give Typeless dictation two modes, on a foot pedal and on Right Ctrl+J:
- Tap starts dictation. Tap again to stop. Good for long, hands-free rambles.
- Hold starts dictation, and letting go stops it and presses Enter once Typeless has pasted the text. Good for quick bursts you want sent.
Typeless only supports tap-to-toggle. If you hold its shortcut, it stops recording and tells you "Don't hold. Press key once." This plugin fakes the hold: pressing the pedal sends one tap, and releasing it after 0.4 seconds or more sends a second tap.
keyboard/typeless_keys.lua gives Right Ctrl+J the same tap-or-hold behavior. Hammerspoon catches the physical keys, swallows them, and calls src/keyboard.ts, which runs the same logic as the pedal.
This only works if Typeless is not bound to Right Ctrl+J itself, because Typeless grabs its own shortcut before Hammerspoon can see it. So Typeless is bound to Right Ctrl + F19, a combo no keyboard sends, and both the pedal and the keyboard post that.
ln -sf "$PWD/keyboard/typeless_keys.lua" ~/.hammerspoon/typeless_keys.lua
echo 'require("typeless_keys")' >> ~/.hammerspoon/init.luaStream Deck's built-in Hotkey action sends Ctrl+key as a key with a Control flag set, without ever pressing the Control key itself. Typeless tells Left Control and Right Control apart, so it ignores that keystroke. This plugin posts the Right Control key down and up around the key, which Typeless accepts.
- macOS, Stream Deck app 6.4 or later, Bun
- Typeless with its Dictate shortcut set to Right Ctrl + F19. For a different key, change
KEY_LETTERinsrc/keystroke.ts(it's a macOS virtual key code). - Stream Deck needs Accessibility permission in System Settings → Privacy & Security. The Hotkey action needs this too, so you probably granted it already.
- For the keyboard shortcut: Hammerspoon with Accessibility permission.
git clone https://github.com/danielmiessler/typeless-pedal
cd typeless-pedal
bun install.tsRestart Stream Deck, then drag Dictate (tap or hold) from the LifeOS category onto a pedal or key.
Typeless takes 0.5 to 1.5 seconds after the shortcut to open the microphone, and anything said before that is lost. preroll/ builds TypelessPreroll.app, a small background helper that opens the mic the moment you press (about 30 ms), buffers it, and plays it to Typeless through BlackHole once Typeless starts listening. Before the stop, it waits until Typeless has heard everything through your release, skipping silence to catch up.
brew install --cask blackhole-2ch, thensudo killall coreaudiod(or restart) so macOS loads it.bun install.tsbuilds and starts the helper and creates an input called Typeless Preroll (an aggregate of BlackHole; Typeless hides BlackHole itself as a virtual device). Building it needs Go.- In Typeless, set the microphone to Typeless Preroll. Allow TypelessPreroll the microphone when macOS asks.
Your real mic still does the recording: the helper captures the Mac's default input. The trade-off is that text arrives a little later after you let go.
The pedal and Right Ctrl+J do nothing to audio: no muting, no pausing. Anything playing keeps playing while you dictate.
A pedal that drops off USB and comes back (a flaky hub does this) reconnects in Stream Deck, but Stream Deck does not reattach the action to the running plugin, so presses stop arriving. The plugin watches for that and restarts itself; Stream Deck relaunches it within a few seconds with the action attached. If a pedal comes back without its serial number (System Information shows "Serial Number: Not Provided"), Stream Deck treats it as a new device with an empty profile: unplug it and plug it back in, ideally straight into the Mac rather than through a monitor or hub.
-
HOLD_MSinsrc/dictate.ts(default 400) is the press length that counts as a hold. -
ENTER_AFTER_HOLDinsrc/dictate.ts(default true) turns the auto-Enter off. The plugin reads Typeless's local history database to know when the paste is done, and skips Enter if the dictation was cancelled or had no speech. -
Presses are logged to
~/Library/Logs/TypelessPedal.log. Each start press also logs how long Typeless took to open the mic (mic live Nms after the tap); speech before that point is not in the recording.
The plugin doesn't track whether Typeless is recording, so it can't get out of sync if Typeless stops on its own. The cost is that when you tap to stop a toggle-mode dictation, the press has to be short. Hold it and let go, and you'll start a new dictation.
MIT