Global shortcut portal support
rhysperry111 opened this issue · comments
Currently there is a portal for registering global shortcuts in the works for xdg-desktop-portal v1.16.
I've just created this issue here to:
- Gather opinions on how this might want to be implemented on the wlroots/sway side of things
- Track progress of implementation
Since I don't think this is possible with current sway/wlroots, I presume it'd require a fair bit of development in both. Is this something that you think will be supported? The end goal is very similar to what the feature request of forwarding key events in sway would achieve.
Links:
- xdg-desktop-portal:
- Sway:
This project exists to interact between the portal api and wayland protocols. Unless there is a wayland protocol created (eg. https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/56) providing a comparable feature set this is blocked.
Because this is now a portal, I don't think that protocol is ever going to be finished. I am certainly not going to update it in favor of global shortcuts. So, what is the process of getting something in to wlr-protocols?
I don't think there is any. We can try making a PR to wlr-protocols ourselves for a global keybind protocol. I am always open to help with impls (both wlr and xdpw) if anyone's open to the idea.
How about intercepting the wayland-protocall like this proof-of-consept wayland-keylogger?
https://github.com/Aishou/wayland-keylogger
Well assuming the shortcut portal service would have appropriate permissions you could just read input events directly in compositor agnostic fashion and ignore the compositor all together.
Maybe we could have a dedicated shortcuts demon that runs as root and send envry keypress to the client (XDPW).
Not in the scope of this project, but a potential workaround might be a wrapper script that has the ability to send keypresses to a client:
keypress-wrap --id discord --exec /usr/bin/discord
And a script to trigger a keypress send:
bindsym $mod+m exec keypress-send --id discord --key ctrl,shift,m
Maybe we could have a dedicated shortcuts demon that runs as root and send envry keypress to the client (XDPW).
All it's needed for this WM agnostic portal would be access to /dev/input nodes, so a root daemon, or the user adds themselves to the input
group, or maybe using the seatd api(? I'm not sure if seatd works like this).
A compositor agnostic portal is an interesting idea IMO.
This project exists to interact between the portal api and wayland protocols.
I'd suggest a clarification on this point: I think this project is a bridge between the portals APIs and the features in wlroots-based compositors that can implement those APIs, not necessarily the broader/upstream wayland protocols and ecosystem
Okay, so, I've read through:
- portals API: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.GlobalShortcuts
- implementation PR for it in KDE: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/80
From this, my understanding is that application developers (or developers of the frameworks/libraries used by application developers) need to do explicit work to adopt this:
- use the portal API to request a GlobalShortcuts session
- use the portal API to register the keyboard shortcuts they want (along with user-facing text to describe how they'll be used)
- wait for portal API messages from DBus to know when one of these buttons is pressed and released (a.k.a. Activated and Deactivated), and triggers actions with the application that would normally be triggered by direct keyboard events
My understanding of the sort of work that would likely need to be done here in xdg-desktop-portal-wlr:
- wlroots-based compositors (e.g. sway/river/hyprland/etc) already allow keys to be bound to certain actions, so x-d-g-wlr should use the same wlroots APIs (during BindShortcuts) to bind the requested GlobalShortcuts
- however, instead of these keypresses resulting in the usual sort of compositor actions (e.g. change focus, run this user script, etc), they should result in the Activate and Deactivate signals to the app (via DBus)
- optionally, during BindShortcuts, show the user the GlobalShortcuts request so that they can see which keys will be bound, although this might be out of scope (x-d-g-wlr traditionally outsources UX to other tools like
dmenu
, etc) - optionally, during BindShortcuts, allow the user to re-map the requested bindings to different keys (same UX issue)
- optionally, during BindShortcuts, allow the user to ignore/block certain requested bindings and to approve other (same UX issue) bindings in the same request
- maintain internal state (similar to Screencast sessions) for which keyboard events are associated with which GlobalShortcuts sessions
- optionally, persist approved requests to a cache/config file so that future matching requests don't require human approval
Maybe we could have a dedicated shortcuts demon that runs as root
This is a possible solution, but I don't believe it's necessary, the compositor is already trapping keyboard shortcuts without needing to run as root, the only thing that's different here is the DBus messages
All it's needed for this WM agnostic portal would be access to /dev/input nodes, so a root daemon, or the user adds themselves to the input group, or maybe using the seatd api
Likewise, this shouldn't be necessary
Well assuming the shortcut portal service would have appropriate permissions you could just read input events directly in compositor agnostic fashion and ignore the compositor all together.
My understanding of the GlobalShortcuts portal API, and the way KDE has implemented it, is that applications would not directly receive the keyboard events, they instead receive DBus signal messages
The above is all based on my understanding, however, so of course I could be wrong and I could have misunderstood how this is supposed to work
Your summary is mostly correct, the main issue is this point:
- wlroots-based compositors (e.g. sway/river/hyprland/etc) already allow keys to be bound to certain actions, so x-d-g-wlr should use the same wlroots APIs (during BindShortcuts) to bind the requested GlobalShortcuts
There is no wlroots api for this. compositors implement their own custom controls (usually keybinds) via a configuration file (eg. sway) or a program (eg. riverctl).
xdpw is a separate wayland client and is not integrated in any compositor. xdpw only talks to the compositor via wayland protocols. As such we need a protocol to relay portal clients to the compositor. The mapping/decision logic will then again be in the compositor.
To clarify the situation is as follows:
application <---- dbus -----> xdg-desktop-portal <----- dbus -----> xdpw <----- wayland ------> compositor
Okay, read through these and I can see that we're somewhat blocked:
There is another approach that allows for universal coverage of compositors without requiring root:
- this is too generic for x-d-p-wlr, so likely would be a new x-d-p-??? that only implements GlobalShortcuts
- x-d-p-??? does all the work outlined in #240 (comment) but relies on user-supplied executables/scripts for the compositor-specific integration
- for BindShortcut, x-d-p-??? calls a user script with necessary arguments/variables for each requested binding
- the user script is responsible for calling
swaymsg
orriverctl
to bind the key:- really 2 bindings, one for press->Activate and another for release->Deactivate
- each binding should spawn
busctl
ordbus-send
to send Activate/Deactivate to the application (or perhaps to x-d-p-??? acting as a proxy if it's too dynamic to be hardcoded) - e.g.
#! /usr/bin/env sh swaymsg -t bindsym --no-repeat ${GLOBAL_KEY} exec 'busctl call ...' swaymsg -t bindsym --no-repeat --release ${GLOBAL_KEY} exec 'busctl call ...'
- there'd need to be another user script responsible for similarly unbinding a given key (e.g.
swaymsg -t unbindsym ...
) - working examples of per-compositor scripts could be provided along with x-d-p-???
The BindShortcut flow:
application <---- dbus -----> xdg-desktop-portal <----- dbus -----> x-d-p-??? -----> user script ------> compositor
The key-press and key-release flow:
compositor ------> sh ------> busctl / dbus-send <----- dbus -----> application
or:
compositor ------> sh ------> busctl / dbus-send <----- dbus -----> x-d-p-??? <----- dbus -----> application
A few downsides though:
- added latency given that each key-press now flows through at least one more component (and launches at least one more process) on its way to the destination application
- complexity: it's already tricky for users to get the xdg-desktop-portal constellation working with exactly the correct environment variables and implementations setup, so requiring the user to copy in these scripts isn't going to help
- both
sway
andriver
support separate key-press and key-release bindings, but I'm not sure how common this is, so maybe this would only end up solving the issue for a small number of compositors
There is no good way to achieve this without a wayland protocol.
What you could do is make a daemon like your xdp? and then make a binary that sends a keybind status, e.g. xdp-shortcut name pressed
xdp-shortcut name released
. (basically like swaymsg but for your daemon)
Not ideal, but it would work.
A proper solution is obviously a wayland protocol, like Hyprland does with hyprland_global_shortcuts_v1
and xdph.
You could either get a protocol of a similiar nature to wayland-protocols, or just adopt the hyprland one in your compositor of choice and use xdph.
In my uninformed opinion wlroots should just implement hyprland_global_shortcuts_v1
(if an implementation is even required), and either recommend a portal that bridges it, or add it to xdpw
, I'm all for not reinventing the wheel if there's already a viable solution available.