Skip to content

keyboard: Send modifers after key - #2191

Merged
Drakulix merged 1 commit into
Smithay:masterfrom
ids1024:modifiers
Sep 30, 2026
Merged

Drakulix merged 1 commit into
Smithay:masterfrom
ids1024:modifiers

Conversation

@ids1024

@ids1024 ids1024 commented Sep 29, 2026

Copy link
Copy Markdown
Member

Description

Fixes #2184.

be920fb reversed the order of these. But this doesn't appear to be correct.

I'm not sure exactly why the bug happens here, but sending modifiers after key seems to match Gnome.

@hojjatabdollahi what was this meant to fix? If there was some issue here, it may need a different solution.

Checklist

Fixes Smithay#2184.

Smithay@be920fb
reversed the order of these. But this doesn't appear to be correct.

I'm not sure exactly why the bug happens here, but sending `modifiers`
after `key` seems to match Gnome.
@YaLTeR

YaLTeR commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

https://wayland.app/protocols/wayland#wl_keyboard:event:key

If this event produces a change in modifiers, then the resulting wl_keyboard.modifiers event must be sent after this event.

(emph mine) seems this is right

@ids1024

ids1024 commented Sep 29, 2026

Copy link
Copy Markdown
Member Author

Right. So there may be some other issue this was meant to fix, but this wasn't the right solution, anyway.

@pgaskin

pgaskin commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Since this is in the shared keyboard code, it also affects #2159 (which makes virtual input use it). I was able to reproduce it for accented characters using ISO_Level5_Latch on a French layout.

It looks like in #2073, the order was swapped about halfway through.

"key event must be sent before modifiers event for libxkbcommon to process them correctly"

/// Send the input to the focused keyboards
pub fn input(
&mut self,
data: &mut D,
keycode: Keycode,
key_state: KeyState,
modifiers: Option<ModifiersState>,
serial: Serial,
time: u32,
) {
let (focus, _) = match self.inner.focus.as_mut() {
Some(focus) => focus,
None => return,
};
#[cfg(feature = "wayland_frontend")]
if let Some(keyboard_handle) = self.seat.get_keyboard() {
match self.isolated.as_ref() {
Some(iso) => {
keyboard_handle.send_keymap(data, &Some(focus), iso.keymap_file(), iso.modifier_state());
}
None => {
let keymap_file = keyboard_handle.arc.keymap.lock().unwrap();
let mods = self.inner.mods_state;
keyboard_handle.send_keymap(data, &Some(focus), &keymap_file, mods);
}
}
}
// key event must be sent before modifiers event for libxkbcommon
// to process them correctly
let key = KeysymHandle {
xkb: match self.isolated.as_ref() {
Some(iso) => &iso.xkb,
None => &self.inner.xkb,
},
keycode,
};
focus.key(self.seat, data, key, key_state, serial, time);
if let Some(mods) = modifiers {
focus.modifiers(self.seat, data, mods, serial);
}
}

"Modifiers must be sent before the key event so the client resolves the key against the updated modifier state"

/// Send the input to the focused keyboards
pub fn input(
&mut self,
data: &mut D,
keycode: Keycode,
key_state: KeyState,
modifiers: Option<ModifiersState>,
serial: Serial,
time: u32,
) {
let (focus, _) = match self.inner.focus.as_mut() {
Some(focus) => focus,
None => return,
};
#[cfg(feature = "wayland_frontend")]
if let Some(keyboard_handle) = self.seat.get_keyboard() {
let keymap_file = keyboard_handle.arc.keymap.lock().unwrap();
let mods = self.inner.mods_state;
keyboard_handle.send_keymap(data, &Some(focus), &keymap_file, mods);
}
let key = KeysymHandle {
xkb: &self.inner.xkb,
keycode,
};
// Modifiers must be sent before the key event so the client resolves the key against the
// updated modifier state.
if let Some(mods) = modifiers {
focus.modifiers(self.seat, data, mods, serial);
}
focus.key(self.seat, data, key, key_state, serial, time);
}

I'm not entirely sure what this means overall though, it's a bit mind-twisting to reason about.

But yeah, this PR seems correct if I understand it correctly.

@Drakulix
Drakulix merged commit 5a7e248 into Smithay:master Sep 30, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

regression: ISO_Level5_Latch modifier cleared immediately on key release instead of on next keypress (breaks fr Ergo-L special dead key)

4 participants