Skip to content

Commit 2c02e6f

Browse files
committed
wayland: Restore valid state information when building keymaps
The spec doesn't guarantee that a modifier event won't arrive before a keymap event, or that it will always be sent after a keymap change if the modifiers and layout index haven't changed, so restore any valid state after allocation when building a new keymap.
1 parent 1c1f708 commit 2c02e6f

File tree

2 files changed

+30
-20
lines changed

2 files changed

+30
-20
lines changed

src/video/wayland/SDL_waylandevents.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,11 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
16631663
}
16641664

16651665
WAYLAND_xkb_keymap_key_for_each(seat->keyboard.xkb.keymap, Wayland_KeymapIterator, seat);
1666+
1667+
// Restore any previously set modifier/layout information, if valid.
1668+
WAYLAND_xkb_state_update_mask(seat->keyboard.xkb.state,
1669+
seat->keyboard.xkb.wl_pressed_modifiers, seat->keyboard.xkb.wl_latched_modifiers, seat->keyboard.xkb.wl_locked_modifiers,
1670+
0, 0, seat->keyboard.xkb.current_layout < seat->keyboard.xkb.num_layouts ? seat->keyboard.xkb.current_layout : 0);
16661671
Wayland_SeatSetKeymap(seat);
16671672
}
16681673

@@ -1806,7 +1811,9 @@ static void Wayland_ReconcileModifiers(SDL_WaylandSeat *seat, bool key_pressed)
18061811
* The modifier will remain active until the latch/lock is released by
18071812
* the system.
18081813
*/
1809-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.shift_mask) {
1814+
const xkb_mod_mask_t xkb_locked_modifiers = seat->keyboard.xkb.wl_latched_modifiers | seat->keyboard.xkb.wl_locked_modifiers;
1815+
1816+
if (xkb_locked_modifiers & seat->keyboard.xkb.shift_mask) {
18101817
if (seat->keyboard.pressed_modifiers & SDL_KMOD_SHIFT) {
18111818
seat->keyboard.locked_modifiers &= ~SDL_KMOD_SHIFT;
18121819
seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_SHIFT);
@@ -1817,7 +1824,7 @@ static void Wayland_ReconcileModifiers(SDL_WaylandSeat *seat, bool key_pressed)
18171824
seat->keyboard.locked_modifiers &= ~SDL_KMOD_SHIFT;
18181825
}
18191826

1820-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.ctrl_mask) {
1827+
if (xkb_locked_modifiers & seat->keyboard.xkb.ctrl_mask) {
18211828
if (seat->keyboard.pressed_modifiers & SDL_KMOD_CTRL) {
18221829
seat->keyboard.locked_modifiers &= ~SDL_KMOD_CTRL;
18231830
seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_CTRL);
@@ -1828,7 +1835,7 @@ static void Wayland_ReconcileModifiers(SDL_WaylandSeat *seat, bool key_pressed)
18281835
seat->keyboard.locked_modifiers &= ~SDL_KMOD_CTRL;
18291836
}
18301837

1831-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.alt_mask) {
1838+
if (xkb_locked_modifiers & seat->keyboard.xkb.alt_mask) {
18321839
if (seat->keyboard.pressed_modifiers & SDL_KMOD_ALT) {
18331840
seat->keyboard.locked_modifiers &= ~SDL_KMOD_ALT;
18341841
seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_ALT);
@@ -1839,7 +1846,7 @@ static void Wayland_ReconcileModifiers(SDL_WaylandSeat *seat, bool key_pressed)
18391846
seat->keyboard.locked_modifiers &= ~SDL_KMOD_ALT;
18401847
}
18411848

1842-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.gui_mask) {
1849+
if (xkb_locked_modifiers & seat->keyboard.xkb.gui_mask) {
18431850
if (seat->keyboard.pressed_modifiers & SDL_KMOD_GUI) {
18441851
seat->keyboard.locked_modifiers &= ~SDL_KMOD_GUI;
18451852
seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_GUI);
@@ -1850,26 +1857,26 @@ static void Wayland_ReconcileModifiers(SDL_WaylandSeat *seat, bool key_pressed)
18501857
seat->keyboard.locked_modifiers &= ~SDL_KMOD_GUI;
18511858
}
18521859

1853-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.level3_mask) {
1860+
if (xkb_locked_modifiers & seat->keyboard.xkb.level3_mask) {
18541861
seat->keyboard.locked_modifiers |= SDL_KMOD_MODE;
18551862
} else {
18561863
seat->keyboard.locked_modifiers &= ~SDL_KMOD_MODE;
18571864
}
18581865

1859-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.level5_mask) {
1866+
if (xkb_locked_modifiers & seat->keyboard.xkb.level5_mask) {
18601867
seat->keyboard.locked_modifiers |= SDL_KMOD_LEVEL5;
18611868
} else {
18621869
seat->keyboard.locked_modifiers &= ~SDL_KMOD_LEVEL5;
18631870
}
18641871

18651872
// Capslock and Numlock can only be locked, not pressed.
1866-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.caps_mask) {
1873+
if (xkb_locked_modifiers & seat->keyboard.xkb.caps_mask) {
18671874
seat->keyboard.locked_modifiers |= SDL_KMOD_CAPS;
18681875
} else {
18691876
seat->keyboard.locked_modifiers &= ~SDL_KMOD_CAPS;
18701877
}
18711878

1872-
if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.num_mask) {
1879+
if (xkb_locked_modifiers & seat->keyboard.xkb.num_mask) {
18731880
seat->keyboard.locked_modifiers |= SDL_KMOD_NUM;
18741881
} else {
18751882
seat->keyboard.locked_modifiers &= ~SDL_KMOD_NUM;
@@ -2195,21 +2202,24 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
21952202
uint32_t group)
21962203
{
21972204
SDL_WaylandSeat *seat = data;
2198-
2199-
if (seat->keyboard.xkb.state == NULL) {
2200-
/* if we get a modifier notification before the keymap, there's nothing we can do with the information
2201-
*/
2202-
return;
2203-
}
2204-
2205-
WAYLAND_xkb_state_update_mask(seat->keyboard.xkb.state, mods_depressed, mods_latched,
2206-
mods_locked, 0, 0, group);
2205+
const uint32_t previous_layout = seat->keyboard.xkb.current_layout;
22072206

22082207
seat->keyboard.xkb.wl_pressed_modifiers = mods_depressed;
2209-
seat->keyboard.xkb.wl_locked_modifiers = mods_latched | mods_locked;
2208+
seat->keyboard.xkb.wl_latched_modifiers = mods_latched;
2209+
seat->keyboard.xkb.wl_locked_modifiers = mods_locked;
2210+
seat->keyboard.xkb.current_layout = group;
22102211

22112212
Wayland_ReconcileModifiers(seat, false);
22122213

2214+
// If we get a modifier notification before the keymap, there's no further state to update yet.
2215+
if (!seat->keyboard.xkb.state) {
2216+
return;
2217+
}
2218+
2219+
WAYLAND_xkb_state_update_mask(seat->keyboard.xkb.state,
2220+
mods_depressed, mods_latched, mods_locked,
2221+
0, 0, group);
2222+
22132223
// If a key is repeating, update the text to apply the modifier.
22142224
if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
22152225
char text[8];
@@ -2220,8 +2230,7 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
22202230
}
22212231
}
22222232

2223-
if (group != seat->keyboard.xkb.current_layout) {
2224-
seat->keyboard.xkb.current_layout = group;
2233+
if (group != previous_layout) {
22252234
Wayland_SeatSetKeymap(seat);
22262235

22272236
if (seat->keyboard.xkb.compose_state) {

src/video/wayland/SDL_waylandevents_c.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ typedef struct SDL_WaylandSeat
110110

111111
// Current system modifier flags
112112
xkb_mod_mask_t wl_pressed_modifiers;
113+
xkb_mod_mask_t wl_latched_modifiers;
113114
xkb_mod_mask_t wl_locked_modifiers;
114115
} xkb;
115116
} keyboard;

0 commit comments

Comments
 (0)