SDL: wayland: Apply modifier changes to the text of repeated keys

From 4a06cc0f75af431d1eb05e4d5cbbdd34bdc1e1fc Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Thu, 22 Sep 2022 13:03:09 -0400
Subject: [PATCH] wayland: Apply modifier changes to the text of repeated keys

The text component of a repeated keystroke is initially set when a key is first pressed and the cached value remains static until the repeated key is released and another repeatable key is pressed. If the state of a modifier such as shift or capslock is changed while a key is being repeated, the text emitted will not have the modifier applied to it until the repeated key is released and pressed again.

Update the text to be repeated by a key if a modifier is changed while a key is actively being repeated.
---
 src/video/wayland/SDL_waylandevents.c | 36 +++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 308e41a3116..94b13c13eda 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -253,6 +253,24 @@ keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t key, uint32
     }
 }
 
+static uint32_t
+keyboard_repeat_get_key(SDL_WaylandKeyboardRepeat *repeat_info)
+{
+    if (repeat_info->is_initialized && repeat_info->is_key_down) {
+        return repeat_info->key;
+    }
+
+    return 0;
+}
+
+static void
+keyboard_repeat_set_text(SDL_WaylandKeyboardRepeat *repeat_info, const char text[8])
+{
+    if (repeat_info->is_initialized) {
+        SDL_memcpy(repeat_info->text, text, 8);
+    }
+}
+
 static SDL_bool keyboard_repeat_is_set(SDL_WaylandKeyboardRepeat* repeat_info) {
     return repeat_info->is_initialized && repeat_info->is_key_down;
 }
@@ -1048,7 +1066,9 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint
 
 #ifdef SDL_USE_IME
     if (SDL_IME_ProcessKeyEvent(sym, key + 8, state)) {
-        *handled_by_ime = SDL_TRUE;
+        if (handled_by_ime) {
+            *handled_by_ime = SDL_TRUE;
+        }
         return SDL_TRUE;
     }
 #endif
@@ -1060,7 +1080,9 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint
     if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) {
         switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) {
             case XKB_COMPOSE_COMPOSING:
-                *handled_by_ime = SDL_TRUE;
+                if (handled_by_ime) {
+                    *handled_by_ime = SDL_TRUE;
+                }
                 return SDL_TRUE;
             case XKB_COMPOSE_CANCELLED:
             default:
@@ -1199,6 +1221,16 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
     SDL_ToggleModState(KMOD_NUM, modstate & input->xkb.idx_num);
     SDL_ToggleModState(KMOD_CAPS, modstate & input->xkb.idx_caps);
 
+    /* If a key is repeating, update the text to apply the modifier. */
+    if(keyboard_repeat_is_set(&input->keyboard_repeat)) {
+        char text[8];
+        const uint32_t key = keyboard_repeat_get_key(&input->keyboard_repeat);
+
+        if (keyboard_input_get_text(text, input, key, SDL_PRESSED, NULL)) {
+            keyboard_repeat_set_text(&input->keyboard_repeat, text);
+        }
+    }
+
     if (group == input->xkb.current_group) {
         return;
     }