sway
sway copied to clipboard
Sway not registering global hotkeys from other applications under certain conditions
-
Sway Version:
- sway version 1.5-36c3c222 (Jul 19 2020, branch 'master')
-
Debug Log:
- sway.log
- (Nothing in this is useful/got added while the issue was happening)
-
Configuration File:
-
bindsym Mod4+Return exec kitty
-
-
Description: Sway seems to not be catching or sending key presses (or their release) which are global hotkeys to their relevant application when certain windows (or lack of any window) is currently selected. In my use case the issue is the registration of the
Push to Talk
hotkey in both mumble and discord (so not isolated to discord because it's terrible or something). The hotkey fails to work whenever my active window is either a blank workspace ormpv
. At first I thought that the issue was sway only registering/sending the key press when any window was selected and the bug was only in the case of there being no window at all (blank workspace), but then I noticed it happening whenever I selected/was hovering over my mpv window as well, so I'm really not sure what's going on. I tested just about every type of keybind I could think of in case it was exclusively an issue with the LCTRL key, but LALT, LSHIFT, F1 and G all have the same problem. -
Reproduction steps:
- Launch sway using the one line config so I could use the terminal.
- Open terminal and run
discord
. - I have three monitors and at this point monitor one had the terminal running discord, monitor two had discord, and monitor three was an empty workspace.
- Join a channel and then try pressing my push to talk hotkey while moving my mouse over different windows/areas.
- Push to talk bind registered and voice activated/deactivated when the selected window (via mouse hover) was either the terminal on monitor one or discord on monitor two, but would either not activate or would remain activated (stuck down) while I had my mouse on monitor three (which had nothing open).
- Quit and exit sway.
AFAIK the Push to talk
for discord and mumble are by default implemented using X11 global keybinds, these will only work as long as an X11 application is currently focused. This is in line with your report, since mpv
should be Wayland-native and with an empty workspace there is no selected application. For mumble, you can use the mumble DBUS interface, sway has the --no-repeat
keybind option for this, see https://github.com/swaywm/sway/pull/5132.
I think there may be no solution for discord, but YMMV.
Is there anything sway can do about this then or is it a wayland issue (and thus I should look to take this elsewhere)? Is the issue that xwayland and wayland are separate and inputs aren't shared between the two interfaces or does wayland lack the functionality altogether? If so, looking forward to when these applications are using wayland by default and not the compatibility layer of xwayland, how are you supposed to use a feature like this?
Wayland does not support global keybindings at all. For now the preferred way is for applications to provide a DBUS or CLI interface. Then you define a keybinding in the compositor that uses the cli or dbus.
I think there may be no solution for discord, but YMMV.
You could try a sway keybinding with xdotool keydown/keyup events.
Edit: KDE seems to use the XDG Desktop Actions and allows assigning hotkeys for them: https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#extra-actions
Related: https://github.com/swaywm/sway/issues/4937
That would work, except that at least in my case I'd prefer it if the key was sent to the matching window in addition to whatever happens normally. It'd be quite bad for my LCTRL to be permanently swallowed because it's getting sent to the discord window. It also doesn't quite work when I want the behavior for multiple windows (say I also want it sent to mumble as well, potentially at the same time).
Posting here so others may find this workaround: the following script works for the specific use-case of getting push-to-talk on Discord.
import sys
import evdev
from Xlib import X, XK, display
from Xlib.ext import xtest
display = display.Display()
device = evdev.InputDevice(sys.argv[1])
key = display.keysym_to_keycode(XK.string_to_keysym('Control_L'))
def press():
xtest.fake_input(display, event_type=X.KeyPress, detail=key)
display.flush()
def release():
xtest.fake_input(display, event_type=X.KeyRelease, detail=key)
display.flush()
try:
for event in device.read_loop():
if event.type == evdev.ecodes.EV_KEY:
if event.code == 29:
print(key)
if event.value == 1:
press()
elif event.value == 0:
release()
else:
continue
print("Forwarding %s" % evdev.categorize(event))
except KeyboardInterrupt:
release()
Needs python-evdev
and python-xlib
(the latter, AFAICT, is Python 2-only). Needs sudo
or being in the input group. Takes the /dev/input/eventX
device corresponding to a keyboard as its only parameter.
This works by just listening to raw evdev events and forwarding them off to X11.
I'm going to list my much simpler solution here too. This is just a button that mutes your mic completely:
.config/sway/config
bindsym f4 exec pactl set-source-mute @DEFAULT_SOURCE@ toggle
Not that sway users don't know how to conf, but it took me a while to even think of this option. It helps if you have a mic icon in your top bar (waybar in my case) so you actually know if your mic is on.
This only solves the one case of using a microphone though, while good, it does nothing to assist with for example pressing Ctrl-F10 to begin recording in OBS.
This can be used for OBS: https://github.com/muesli/obs-cli
I think this issue should be closed in favour of #4937. It has already been said here that Wayland doesn't allow global keybindings, and that applications should provide command-line or dbus interfaces.
Just to add another workaround: for applications running under xwayland (which is the case for Discord, for now), forwarding the keys to X works fine, e.g.:
bindsym Control_R exec xdotool keydown Control_R
bindsym --release Control_R exec xdotool keyup Control_R
Update: xdotool
no longer works with XWayland
I think this issue should be closed in favour of #4937. It has already been said here that Wayland doesn't allow global keybindings, and that applications should provide command-line or dbus interfaces.
Just to add another workaround: for applications running under xwayland (which is the case for Discord, for now), forwarding the keys to X works fine, e.g.:
bindsym Control_R exec xdotool keydown Control_R bindsym --release Control_R exec xdotool keyup Control_R
I agree that #4937 is the way forward. The xdotool trick you supplied almost works, but the key isn't released when another key is pressed. I'm using Control_L, and if I do for example, Ctrl+T to open a tab, the Ctrl key gets stuck down until I press it again on it's own. I'm using the Python script method that Xyene posted, it works, it's just too bad it's not flexible. Hopefully one day it won't be necessary at all.
In gnome-shell using wayland global hotkeys from X apps works, why do need a work around for sway?
Edit: I think XWayland lets X to X globals work. its' not unique to Gnome.