SDL: wayland: Set the keymap in keyboard_handle_modifiers

From dfcd5fbcade077df038269123d9f3e57880aec4b Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Thu, 8 Apr 2021 21:57:58 -0400
Subject: [PATCH] wayland: Set the keymap in keyboard_handle_modifiers

---
 src/video/wayland/SDL_waylandevents.c | 57 +++++++++++++++++++++++++++
 src/video/wayland/SDL_waylandsym.h    |  7 ++++
 2 files changed, 64 insertions(+)

diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index ef4f2ccca..73b81c1e0 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -767,6 +767,54 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
     }
 }
 
+typedef struct Wayland_Keymap
+{
+    xkb_layout_index_t layout;
+    SDL_Keycode keymap[SDL_NUM_SCANCODES];
+} Wayland_Keymap;
+
+static void
+Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
+{
+    const xkb_keysym_t *syms;
+    Wayland_Keymap *sdlKeymap = (Wayland_Keymap *)data;
+
+    if ((key - 8) < SDL_arraysize(xfree86_scancode_table2)) {
+        SDL_Scancode scancode = xfree86_scancode_table2[key - 8];
+        if (scancode == SDL_SCANCODE_UNKNOWN) {
+            return;
+        }
+
+        if (WAYLAND_xkb_keymap_key_get_syms_by_level(keymap, key, sdlKeymap->layout, 0, &syms) > 0) {
+            uint32_t keycode = WAYLAND_xkb_keysym_to_utf32(syms[0]);
+            if (keycode) {
+                sdlKeymap->keymap[scancode] = keycode;
+            } else {
+                switch (scancode) {
+                    case SDL_SCANCODE_RETURN:
+                        sdlKeymap->keymap[scancode] = SDLK_RETURN;
+                        break;
+                    case SDL_SCANCODE_ESCAPE:
+                        sdlKeymap->keymap[scancode] = SDLK_ESCAPE;
+                        break;
+                    case SDL_SCANCODE_BACKSPACE:
+                        sdlKeymap->keymap[scancode] = SDLK_BACKSPACE;
+                        break;
+                    case SDL_SCANCODE_TAB:
+                        sdlKeymap->keymap[scancode] = SDLK_TAB;
+                        break;
+                    case SDL_SCANCODE_DELETE:
+                        sdlKeymap->keymap[scancode] = SDLK_DELETE;
+                        break;
+                    default:
+                        sdlKeymap->keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(scancode);
+                        break;
+                }
+            }
+        }
+    }
+}
+
 static void
 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
                           uint32_t serial, uint32_t mods_depressed,
@@ -774,9 +822,18 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
                           uint32_t group)
 {
     struct SDL_WaylandInput *input = data;
+    Wayland_Keymap keymap;
 
     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
                           mods_locked, 0, 0, group);
+
+    keymap.layout = group;
+    SDL_GetDefaultKeymap(keymap.keymap);
+    WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
+                                    Wayland_keymap_iter,
+                                    &keymap);
+    SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES);
+    SDL_SendKeymapChangedEvent();
 }
 
 static void
diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h
index 5962ff68a..5e9bafefa 100644
--- a/src/video/wayland/SDL_waylandsym.h
+++ b/src/video/wayland/SDL_waylandsym.h
@@ -118,6 +118,13 @@ SDL_WAYLAND_SYM(enum xkb_state_component, xkb_state_update_mask, (struct xkb_sta
                       xkb_layout_index_t depressed_layout,\
                       xkb_layout_index_t latched_layout,\
                       xkb_layout_index_t locked_layout) )
+SDL_WAYLAND_SYM(void, xkb_keymap_key_for_each, (struct xkb_keymap *, xkb_keymap_key_iter_t, void*) )
+SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *,
+                                                        xkb_keycode_t,
+                                                        xkb_layout_index_t,
+                                                        xkb_layout_index_t,
+                                                        const xkb_keysym_t **) )
+SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) )
 
 #undef SDL_WAYLAND_MODULE
 #undef SDL_WAYLAND_SYM