WaylandKeybinds: Discord global mute, deafen and push-to-talk that keep working when GNOME drops the key release

Home: git.evandro.dev.br/evandro/vencord-wayland-keybinds, on my self-hosted Gitea. GitHub only carries this copy for reach.

**WaylandKeybinds** is a [Vencord](https://vencord.dev) plugin for the Discord desktop app on Linux. Discord already hands your keybinds to GNOME through the `GlobalShortcuts` portal, but GNOME loses the key release whenever a modifier is let go first, and Discord's mute and deafen only act on the release. The plugin fixes this inside Discord's own **Keybinds** screen: whatever key you choose there becomes global, like Discord on Windows.

Timeline of one Ctrl+Shift+F10 hold with Ctrl+Shift let go first: GNOME sends a press and key repeats but no release; Discord alone never toggles and ignores the next press; with WaylandKeybinds the mute toggles on the press and silence after a re-registration means the key was released

Measured on GNOME 50 with Discord 1.0.168: every press toggled the mute exactly once, 11 to 14 ms after GNOME's signal, including a 6-second hold that GNOME repeated 57 times. ## Why Discord's keybinds break on GNOME - GNOME's compositor looks up a shortcut's release using the modifiers still held at that moment. Let Ctrl or Shift go before the main key and the release never matches, so the portal never sends `Deactivated` ([`process_event`](https://gitlab.gnome.org/GNOME/mutter/-/blob/main/src/core/keybindings.c)). - Mute, deafen and most other toggles fire on the key **release** only. - Discord's native module ignores further presses until it sees a release, so after one lost release the next gesture disappears too. - GNOME describes the trigger as `Press F10` while Discord expects `CTRL+SHIFT+F10`, so every working shortcut is flagged as different from the system one. ## What the plugin does - Toggle actions (mute, deafen, streamer mode and the rest) fire on the **press**. - One second after a press it re-registers the shortcut, which clears Discord's stuck state, then listens for 300 ms. While the keys are held, GNOME's key repeat answers within a few milliseconds; silence means they were released. That is how push-to-talk stops even when the release is lost. A real release still stops it at once. - It reads GNOME's trigger format, so the Keybinds screen stops warning about a mismatch. - It changes nothing unless Discord registers the keybind through the Wayland portal. It runs in the renderer only: no native code, no new dependency, no DOM clicks. ## Install You need a [Vencord source checkout](https://docs.vencord.dev/installing/), because user plugins are compiled into your build. ```sh cd /path/to/Vencord git clone https://git.evandro.dev.br/evandro/vencord-wayland-keybinds.git src/userplugins/waylandKeybinds.discordDesktop pnpm build pnpm inject ``` Restart Discord. The plugin is on by default; you can find it as **WaylandKeybinds** in Vencord's plugin list. Its info panel shows whether the fix is active, how many keybinds GNOME has registered, and a button that opens Discord's Keybinds page. > [!IMPORTANT] > Keep the folder name `waylandKeybinds.discordDesktop`. The suffix limits the plugin to the Discord desktop app, the only place where Discord's native keybind module exists. ## Use 1. Open Discord **User Settings → System → Keybinds** and click **Add a Keybind**. 2. Pick an action (Toggle Mute, Toggle Deafen, Push to Talk…) and press your combination. 3. GNOME asks once to allow the shortcut. Click **Add**. Change the keys whenever you want on the same screen; GNOME asks again for the new combination. > [!TIP] > For push-to-talk, a single key without modifiers (Pause, F13 to F24) keeps both press and release reliable. On Wayland, Discord records only combinations the portal can represent: one main key plus optional modifiers. Mouse buttons cannot be global shortcuts there. ## Compatibility | Component | Tested with | | --- | --- | | Discord | 1.0.168 (Electron 44) | | Vencord | 1.15.15 | | GNOME | 50.5 (mutter 18, xdg-desktop-portal-gnome 50) | | KDE Plasma, Hyprland | Not tested. The portal path is the same, the release behavior may differ. | ## Limits - Release detection relies on GNOME's key repeat (500 ms, then every 30 ms by default). With key repeat turned off, push-to-talk ends about 1.3 s after the press even while you hold it. - When the release is lost, push-to-talk stops up to about 1.3 s after you let go. - The live checks covered toggle mute; push-to-talk is covered by the state-machine tests. - Soundboard hold stays off the portal on Linux. That is Discord's own choice. - The patches target Discord's minified code and can break with Discord updates. Run `check-patches.mjs` before you rebuild. ## Development From the root of your Vencord checkout: ```sh # one test case per independent path of every function in logic.ts pnpm exec esbuild src/userplugins/waylandKeybinds.discordDesktop/logic.test.ts \ --bundle --platform=node --format=esm --outfile=/tmp/wk-test.mjs node --test /tmp/wk-test.mjs # apply the patches to the Discord build that discord.com serves right now node src/userplugins/waylandKeybinds.discordDesktop/check-patches.mjs ``` The design notes, measurements and acceptance criteria (in Portuguese) are in [`specs/2026-11-01-wayland-keybinds.md`](specs/2026-11-01-wayland-keybinds.md). ---

Made by Evandro · git.evandro.dev.br/evandro · evandro.dev.br