git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit9b1a0e0ea8b4a3fd80b875ea7da6137870a77e81
parent197891c990
authorIsaac Freund <[email protected]>
date2026-02-13 14:44
Keyboard: fix modifiers with X11/Wayland backend

The modifiers event is never emitted by the libinput backend.

The Wayland backend also has been working fine thus far despite
the modifiers event never being sent by the backend, the Wayland
protocol notifies the wlroots Wayland backend of the currently
held keys when focus is gained. However, the host compositor
changing modifier state through a side channel rather than a
key press was broken with the Wayland backend.

With the X11 backend, things were terribly broken since X11 does
not communicate the currently held keys when keyboard focus is gained.
It should work a lot better now, but do note that modifiers may be
out-of-sync with the host until the first key press after keyboard
focus is gained.

 river/Keyboard.zig | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/river/Keyboard.zig b/river/Keyboard.zig
index 037eb8d..e2bb194 100644
--- a/river/Keyboard.zig
+++ b/river/Keyboard.zig
@@ -69,7 +69,16 @@ pub fn create(seat: *Seat, wlr_device: *wlr.InputDevice, virtual: bool) !*Keyboa
 
     wlr_keyboard.events.key.add(&keyboard.key);
     wlr_keyboard.events.modifiers.add(&keyboard.modifiers);
-    wlr_keyboard.events.keymap.add(&keyboard.keymap);
+
+    if (virtual) {
+        wlr_keyboard.events.keymap.add(&keyboard.keymap);
+    } else {
+        keyboard.keymap.link.init();
+        // We must set a keymap even though this is not the wlr_keyboard river
+        // exposes to clients. If there is no keymap set, wlroots will not emit
+        // the modifiers event when using the Wayland or X11 backend.
+        _ = wlr_keyboard.setKeymap(keyboard.config.keymap);
+    }
 
     return keyboard;
 }
@@ -109,6 +118,7 @@ pub fn setRepeatInfo(keyboard: *Keyboard, rate: u31, delay: u31) void {
 
 pub fn setKeymap(keyboard: *Keyboard, keymap: *xkb.Keymap) void {
     assert(!keyboard.device.virtual);
+    _ = keyboard.device.wlr_device.toKeyboard().setKeymap(keymap);
     if (keyboard.config.keymap) |old| old.unref();
     keyboard.config.keymap = keymap.ref();
     if (keyboard.group) |group| {