Voice dictation plugin for Steam Deck using faster-whisper with context-aware transcription.
- Push-to-Talk: Hold button combo (default: L1+R1) to record
- Configurable buttons: Choose 1-5 button combinations from any Steam Deck controller buttons
- Game presets: Switch between game profiles with different chat systems (WoW, Guild Wars 2, Generic)
- Channel-aware: Speak channel prefixes like "party pull boss" and it routes to the right chat channel
- Test Recording: Built-in 3-second test with automatic transcription display
- Context-aware: Optional WoW addon integration for better accuracy with zone, boss, and party context
- Fast transcription: Uses faster-whisper for efficient CPU-based speech recognition
- Auto-type: Automatically types transcribed text into active window via ydotool
- Toast notifications: Optional notifications when recording starts/stops
Important
Use a direct ZIP URL that points to the packaged plugin artifact.
Recommended stable URL:
https://silverfoxy.github.io/decktation/releases/latest/decktation.zip
Branch build URL pattern:
https://silverfoxy.github.io/decktation/branches/<url-encoded-branch-name>/decktation.zip
GitHub release assets also work:
https://github.com/silverfoxy/decktation/releases/latest/download/decktation.zip
Do not use GitHub's Source code (zip) or Source code (tar.gz) archives. Those do not contain Decktation's bundled Python dependencies.
-
Open Decky Settings, enable developer options if necessary, and select Install Plugin from URL or Install Plugin from ZIP.
-
Paste the direct ZIP URL above, or download
decktation.zipfirst and then choose the file locally. Decky imports the archive and reloads the plugin automatically.
For example, branch feature/chat polish becomes
feature%2Fchat%20polish in the URL path.
All dependencies and the private keyboard helper are pre-bundled in the
release. No system packages or one-time sudo setup are required.
- Open Quick Access Menu (... button on Steam Deck)
- Navigate to Decktation plugin
- Select your game from the Game dropdown
- Enable the plugin (waits for Whisper model to load)
- (Optional) Change the button combination in the plugin UI
- In any app/game: hold [button1]+[button2] together to record, release to transcribe and type
Decktation ships with three presets configured in defaults/game_presets.json:
| Preset | Behavior |
|---|---|
| World of Warcraft | Presses Enter to open chat, types channel prefix + message, presses Enter to send |
| Guild Wars 2 | Presses Enter to focus chat, types the Guild Wars 2 channel command + message, presses Enter to send |
| Generic | Types text directly into whatever window is focused — no Enter presses |
In WoW mode, start your message with a channel name to route it to the right channel:
"party let's go" → /p let's go
"raid: focus adds first" → /raid focus adds first
"say, hello everyone" → /s hello everyone
"guild heads up" → /g heads up
"type search term" → types directly without opening chat
Separators supported: space, colon, comma, or period after the channel name. Case-insensitive.
Available WoW channels: say, party, raid, guild, officer, yell, instance, whisper, type
Guild Wars 2 mode uses the same voice-first flow. For example:
"map meta starts in five" → /m meta starts in five
"party stack on me" → /p stack on me
"squad: ready check" → /d ready check
"team push mid" → /t push mid
"guild one hello everyone" → /g1 hello everyone
"whisper Player Name hello" → /w Player Name hello
Available Guild Wars 2 channels: say, map, party, squad, raid (an alias for squad), team, guild, guild one through guild six, whisper, type.
You can add channels beyond the built-in ones (e.g. WoW's numbered channels /1, /2) by editing two config files.
Step 1 — add the channel command to defaults/game_presets.json under the preset's channels map:
"channels": {
"say": "/s ",
"party": "/p ",
"one": "/1 ",
"two": "/2 "
}Step 2 — add the spoken trigger words to defaults/channel_languages.json under each language's channels map:
"en": {
"channels": {
"one": ["one", "channel one"],
"two": ["two", "channel two"]
}
}After saving both files, saying "one hello" or "channel one hello" will send /1 hello.
You can add as many trigger words per channel as you like (e.g., aliases in multiple languages). The key in defaults/channel_languages.json must match the key in defaults/game_presets.json.
Edit defaults/game_presets.json to add new games — no code changes needed. Each preset specifies:
chat_open_key— key to open the chat box ("enter"ornull)chat_send_key— key to send the message ("enter"ornull)default_channel— channel to use when no prefix is spokenchannels— map of spoken words to slash-command prefixeswhisper_prompt— vocabulary hint for the Whisper model
The plugin uses a configurable button combo for push-to-talk. You can set 1–5 buttons from the plugin UI.
Available buttons:
- L1, R1 (bumpers) — Default combo
- L2, R2 (triggers)
- L4, R4, L5, R5 (Steam Deck back grips, detected through raw HID)
- A, B, X, Y (face buttons)
- WoW chat: Dictate messages with correct channel routing (party, raid, guild, etc.)
- Generic text input: Type player names, search terms, chat in any game without a keyboard
- Web browsing: Fill forms, search, comment
- Discord/messaging: Send messages hands-free
- Any text input: Works in any active window using the Generic preset
For improved accuracy with WoW-specific vocabulary, install the included WoW addon and run convert_wow_context.py --watch. It reads your current zone, target, party members, and class/spec from the game and feeds them to Whisper as context.
See doc/TESTING_GUIDE.md for setup instructions.
- Check Decky Loader logs:
/tmp/decky-*.log - Ensure all Python dependencies are installed
- Restart Decky Loader
- Ensure the plugin is enabled
- Check that Steam Deck mic is working (test in another app)
- Check
/tmp/decktation.logforydotoold ready - Check logs:
/tmp/decktation.log
- Try a different button combination in the plugin UI
- Rear grip buttons are supported on Steam Deck hardware through raw HID
- Check
/tmp/decktation.logfor controller listener errors - Verify controller listener is running:
pgrep -f controller_listener
- Default
basemodel is recommended (good balance) - For faster: use
tinymodel (edit wow_voice_chat.py line 28) - For accuracy: use
smallmodel (slower, needs more resources)
- Speech recognition: faster-whisper (CTranslate2 backend)
- Model: base (150MB, ~2-4s transcription time)
- Input: Steam Deck microphone or connected headset
- Controller input: Steam Deck raw HID reports (independent of per-game Steam Input layouts)
- Output: Keyboard simulation via ydotool (bundled)
- Game presets:
defaults/game_presets.json— data-driven, no code changes needed to add games - Dependencies: Pre-bundled Python 3.11 libraries in
lib/folder - Architecture: TypeScript frontend + Python backend + separate controller listener process
npm install # Install Node dependencies (package-lock.json is ignored)
npm run build # Compile TypeScript to dist/index.js
npm run watch # Watch mode for development
# Unit tests (no hardware required)
python3 -m venv .venv && .venv/bin/pip install pytest
.venv/bin/pytest tests/ -vCI runs unit tests and the TypeScript build on every push via GitHub Actions.
- Voice data stays local. Recording, transcription, chat parsing, and simulated keyboard input run on your Steam Deck. Decktation does not upload audio recordings, transcribed text, or WoW context data.
- Model downloads. The first use of each selected Whisper model downloads its model files from Hugging Face. This requires an internet connection; subsequent use is local while the model remains cached on the device.
- Optional diagnostics. The Diagnostics → Share setting is off by default. When enabled, Decktation sends scrubbed error and performance data to Sentry to help diagnose failures. It excludes audio, transcription text, WoW context, credentials, device/host identifiers, IP addresses, and paths containing the local user name. Diagnostics include the plugin release, error category/type, selected game preset, controller type, and whether a dictation operation succeeded.
- You can disable diagnostics at any time from the plugin’s Diagnostics section; no diagnostics connection is initialized while the setting is off.
Decktation declares Decky’s _root permission solely for the Steam Deck
devices required by push-to-talk and text input:
- It reads Valve raw controller reports from
/dev/hidraw*so the configured physical button combination works independently of a game’s Steam Input layout. - It runs its bundled
ydotooldhelper against/dev/uinputto simulate the keystrokes that enter the transcription in the active window. The helper uses a private, owner-only socket in/tmpand is stopped when the plugin unloads. - Dictated text is passed as data to
ydotool; it is never evaluated as a shell command. Decktation does not modify the system filesystem, install system packages, or create system services.
Built with:
- faster-whisper - Efficient Whisper implementation
- Decky Loader - Steam Deck plugin framework
MIT
