OpenDeck plugin: single-button push-to-mute toggle for Discord via mouse4/5
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-19 03:49:16 +02:00
bin Add retry loops for Discord RPC and mouse device lookup 2026-08-19 03:45:26 +02:00
docs/superpowers Wire mouse4/5 listener into armed state -> Discord mute; fix icon-toggle desync (DisableAutomaticStates, symlink 403) 2026-08-19 03:44:10 +02:00
icons Handle keyDown/willAppear: armed toggle + icon state sync; icon design iterations 2026-08-19 03:28:36 +02:00
.gitignore Add README and .gitignore 2026-08-19 03:49:16 +02:00
manifest.json Wire mouse4/5 listener into armed state -> Discord mute; fix icon-toggle desync (DisableAutomaticStates, symlink 403) 2026-08-19 03:44:10 +02:00
README.md Add README and .gitignore 2026-08-19 03:49:16 +02:00

opendeck-mute-toggle

OpenDeck plugin: one Stream Deck button arms/disarms mouse4/mouse5 as a push-to-mute for Discord. Hold mouse4 or mouse5 while armed and Discord mutes; release and it unmutes. Disarmed, the buttons do nothing to Discord (so they're free for other uses, e.g. in-game chat binds) and the icon shows which state you're in.

Why

Built for games that already use mouse4/mouse5 for their own chat, where binding Discord's own keybind to the same buttons would collide. This plugin only intercepts them (via a non-exclusive evdev tap, so the game still receives the events normally) while explicitly armed.

Requirements

  • OpenDeck on Linux
  • python-evdev (pacman -S python-evdev on Arch; pip install evdev elsewhere)
  • websocket-client (pip install websocket-client if not already present)
  • Your user must be in the input group (sudo usermod -aG input $USER, then log out/in) so the plugin can read the mouse device
  • A Discord desktop client running locally (uses its local RPC socket)

Setup

  1. Register a Discord application at https://discord.com/developers/applications — note its Client ID and Client Secret (OAuth2 page). No redirect URI setup needed beyond adding http://localhost under OAuth2 → Redirects.
  2. Create ~/.config/discord-mute-toggle/app.json:
    {"client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET"}
    
    chmod 600 it. This directory also holds tokens.json, written automatically on first authorize — don't commit either file, they're both gitignored.
  3. Install into OpenDeck (must be a real copy, not a symlink — see the design doc's "Gotchas" section for why):
    rsync -a --delete ./ ~/.config/opendeck/plugins/dev.lvxy.mutetoggle.sdPlugin/ \
      --exclude .git --exclude docs
    
    Restart OpenDeck, add the "Push-to-Mute Toggle" action to a button.
  4. First run authorizes Discord: either run python3 bin/mute-toggle.py --selfcheck once from a terminal (so you can see and click the Discord authorize prompt), or just press the OpenDeck button — either path writes tokens.json after you approve.

Usage

  • Press the button once to arm (icon shows ARMED). Press again to disarm (icon shows OFF).
  • While armed, holding mouse4 or mouse5 mutes Discord; releasing unmutes. Either button (or both) held counts as muted.
  • Disarming while a button is held un-mutes immediately — never gets stuck muted.

Development

No test framework — this is a small, single-file, event-driven personal utility. python3 bin/mute-toggle.py --selfcheck exercises the Discord RPC/token path standalone (no OpenDeck needed). Full design notes and the protocol details (reverse-engineered from OpenDeck's own Rust source, since no Python SDK exists) are in docs/superpowers/specs/2026-08-19-opendeck-mute-toggle-design.md.