KDE Frameworks contain a framework called KGlobalAccel. This framework allows applications to register key bindings (e.g. Alt+Tab) for actions. When the key binding is triggered the action gets invoked. Internally this framework uses a DBus interface to communicate with a daemon (kglobalaccel5) to register the key bindings and for getting notified when the action triggered.
On X11 the daemon uses the X11 core functionality to get notified whenever key events it is interested in happen. Basically it is a global key logger. Such an architecture has the disadvantage that any process could have this infrastructure and it would be possible for multiple processes grabbing the same global shortcut. In such a case undefined behavior is triggered as either multiple actions are triggered at the same time or only one action is triggered while the others do not get informed at all.
In addition the X11 protocol and the X server do not know that kglobalaccel5 is a shortcut daemon. It doesn’t know that for example the shortcut to lock the screen must be forwarded even if there is an open context menu which grabbed the keyboard.
In Wayland the security around input handling got fixed. A global key logger is no longer possible. So our kglobalaccel5 just doesn’t get any input events (sad, sad kglobalaccel5 cannot do anything) and even when started on Xwayland with the xcb plugin it’s pretty much broken. Only if key events are sent to another Xwayland client it will be able to intercept the events.
This means a global shortcut handling needs support from the compositor. Now it doesn’t make much sense to keep the architecture with a separate daemon process as that would introduce a possible security vulnerability: it would mean that there is a way how to log the keys. One only needs to become the global shortcuts daemon and there you go. Also we don’t want to introduce a round trip to another application to decide where to deliver the key event to.
Therefore the only logical place is to integrate global shortcut handling directly into KWin. Now this is a little bit tricky. First of all kglobalaccel5 gets DBus activated when the first application tries to access the DBus interface. And of course KWin itself is using the DBus interface. So KWin starts up and has launched the useless kglobalaccel5. Which means one of our tasks is to prevent kglobalaccel5 from starting.
Of course we do not want to duplicate all the work which was done in kglobalaccel. We want to make use of as much work as possible. Because of that kglobalaccel5 got a little surgery and the platform specific parts got split out into loadable runtime plugins depending on the QGuiApplication::platformName(). This allows KWin to provide a plugin to perform the “platform specific” parts. But the plugin would still be loaded as part of kglobalaccel5 and not as part of KWin. So another change was to turn the functionality of kglobalaccel into a library and make the binary just a small wrapper around the library. This allows KWin to link the library and start kglobalaccel from within the KWin process and feed in its own plugin.
Starting the linked KGlobalAccel is one of the first things KWin needs to do during startup. It’s essential that KWin takes over the DBus interface before any process tries to access it (as a good part it’s done so early that the Wayland sockets do not accept connections yet and Xwayland is not even started). We will also try to make kglobalaccel5 a little bit more robust about it to not launch at all in a Plasma/Wayland session.
Now the reader might think: wait, that still gives me the possibility to install a stealth key logger, I just need to create shortcuts for all keys. Nope, doesn’t work. As key events get filtered out a user would pretty quickly notice that something is broken.
Integrating KGlobalAccel into KWin on Wayland brings an obvious disadvantage: it’s linked to KWin. If one wants to use applications using KGlobalAccel on other compositors some additional work might be needed to use their local global shortcut system – if there is some. For most applications this is no problem, though, as they are part of the Plasma workspace. Also for other global shortcut systems to work with KWin it’s needed to port them to use KGlobalAccel internally when running in a Plasma/Wayland session (that’s also a good idea for X11 sessions as KGlobalAccel can provide additional features like checking whether the key is already taken by another process).
8 Replies to “Global shortcut handling in a Plasma Wayland session”
That reminds me how pretty much all DOSBox special key combinations, like to switch CDs, conflict with KWin’s shortcuts. So instead of swapping CDs, another desktop would be opened; what’s worse, if there are not enough desktops defined (Ctrl+F4, so there would have to be 4, but the default is 2), the key combination would do absolutely nothing. So it was quite frustrating until I managed to find out what was going on.
Another thing this reminds me of is that KSnapshot needs to be ported over to KF5. It’s quite unfortunate that I need to go into the menus to launch it, thus I miss the exact moment I need.
Oh, and under this new system, how does VT switching work? Do the key combinations go through KWin or do they go around it?
The perfect illustration of that kind of thing is when you try to run a Windows VM in a Windows host. The host UI has to provide a menu item for sending a Ctrl+Alt+Delete sequence to the child VM, because the Windows host will never allow that particular sequence to be trapped and passed on to the child.
I thought you said you split out the functional bits of kglobalaccell into a library and made a wrapper for when Plasma/Wayland is not running (and Plasma/Xorg is), so that you could still use it.
You’re saying that wrapper still depends on kwin, so it can’t be used with other compositors?
No, the wrapper is independent of KWin. What depends on KWin is the plugin for kglobalaccel on Wayland.
This is why the protocol for registering global shortcuts should be standardized between the desktops. Are there any talks with GNOME guys about that?
yes we talked about that and unanimously agreed that we do not want to have this as a standardized interface. Global shortcut handling is by definition desktop specific.
I want to tell the story why KGlobalAccel exists in the first place. Theoretically, under X11 every application could just use the mechanism that KGlobalAccel uses and grab its global shortcuts itself. That would mean conflicts can’t be recognized and handled. Which wouldn’t be much of a problem if users only assigned their own global shorctuts. But applications also have defaults and there’s no great way to coordinate them. Checking with other running applications isn’t perfect because currently not running application can also have global shortcuts.
The solution is that applications “officially” register their shortcuts. They do this with a unique name for both application and shortcut so they can later refer to a shortcut again, like when they want to change it, usually at the user’s request. This also has the useful side effect that you can show and edit a list of all global shortcuts in systemsettings. For that reason, global shortcuts have… well, are supposed to have a unique name and a “friendly name” which can be translated.
Now this reads a bit like a Raymon Chen story about why something weird in Windows absolutely had to be that way for the following reasons, but if you think about it maybe some reason wasn’t so important so you could have disregarded it and come up with something massively simpler. I’m not sure if I would still do it the same way today.
Anyway: As a happy accident, (relatively) not much needs to change to improve security a bit by having only one trusted component that may grab keys for the whole session. The next best alternative to get global shortcuts at all would be adding the same “everyone can grab every key” capability that X has to Wayland.
Comments are closed.