Просмотр исходного кода

wayland: Simplify key repeat handling

Remove redundant state variables, remove trivial helper functions, and guard against the unlikely case where a compositor may set the repeat rate to zero while a repeat is active, which would result in a divide-by-zero error.

Key repeat is increasingly handled server-side with seat v10 and above, so consider that the most common path for the future.
Frank Praznik 13 часов назад
Родитель
Сommit
a3a8141557
2 измененных файлов с 23 добавлено и 62 удалено
  1. 20 57
      src/video/wayland/SDL_waylandevents.c
  2. 3 5
      src/video/wayland/SDL_waylandevents_c.h

+ 20 - 57
src/video/wayland/SDL_waylandevents.c

@@ -411,11 +411,9 @@ static void Wayland_SeatSetKeymap(SDL_WaylandSeat *seat)
     }
     }
 }
 }
 
 
-// Returns true if a key repeat event was due
-static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
+// Synthesize key repeat events
+static void keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
 {
 {
-    bool ret = false;
-
     while (elapsed >= repeat_info->next_repeat_ns) {
     while (elapsed >= repeat_info->next_repeat_ns) {
         if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
         if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
             const Uint64 timestamp = repeat_info->base_time_ns + repeat_info->next_repeat_ns;
             const Uint64 timestamp = repeat_info->base_time_ns + repeat_info->next_repeat_ns;
@@ -425,26 +423,15 @@ static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint6
             SDL_SendKeyboardText(repeat_info->text);
             SDL_SendKeyboardText(repeat_info->text);
         }
         }
         repeat_info->next_repeat_ns += SDL_NS_PER_SECOND / (Uint64)repeat_info->repeat_rate;
         repeat_info->next_repeat_ns += SDL_NS_PER_SECOND / (Uint64)repeat_info->repeat_rate;
-        ret = true;
-    }
-    return ret;
-}
-
-static void keyboard_repeat_clear(SDL_WaylandKeyboardRepeat *repeat_info)
-{
-    if (!repeat_info->is_initialized) {
-        return;
     }
     }
-    repeat_info->is_key_down = false;
 }
 }
 
 
 static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint32 wl_press_time_ms,
 static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint32 wl_press_time_ms,
-                                Uint64 base_time_ns, uint32_t scancode, bool has_text, char text[8])
+                                Uint64 base_time_ns, uint32_t scancode, const char *text)
 {
 {
-    if (!repeat_info->is_initialized || !repeat_info->repeat_rate) {
+    if (!repeat_info->repeat_rate) {
         return;
         return;
     }
     }
-    repeat_info->is_key_down = true;
     repeat_info->keyboard_id = keyboard_id;
     repeat_info->keyboard_id = keyboard_id;
     repeat_info->key = key;
     repeat_info->key = key;
     repeat_info->wl_press_time_ms = wl_press_time_ms;
     repeat_info->wl_press_time_ms = wl_press_time_ms;
@@ -452,39 +439,13 @@ static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 k
     repeat_info->sdl_press_time_ns = SDL_GetTicksNS();
     repeat_info->sdl_press_time_ns = SDL_GetTicksNS();
     repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms);
     repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms);
     repeat_info->scancode = scancode;
     repeat_info->scancode = scancode;
-    if (has_text) {
-        SDL_memcpy(repeat_info->text, text, sizeof(repeat_info->text));
+    if (text) {
+        SDL_strlcpy(repeat_info->text, text, SDL_arraysize(repeat_info->text));
     } else {
     } else {
         repeat_info->text[0] = '\0';
         repeat_info->text[0] = '\0';
     }
     }
 }
 }
 
 
-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_copyp(repeat_info->text, text);
-    }
-}
-
-static bool keyboard_repeat_is_set(SDL_WaylandKeyboardRepeat *repeat_info)
-{
-    return repeat_info->is_initialized && repeat_info->is_key_down;
-}
-
-static bool keyboard_repeat_key_is_set(SDL_WaylandKeyboardRepeat *repeat_info, uint32_t key)
-{
-    return repeat_info->is_initialized && repeat_info->is_key_down && key == repeat_info->key;
-}
-
 static void sync_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data)
 static void sync_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data)
 {
 {
     // Nothing to do, just destroy the callback
     // Nothing to do, just destroy the callback
@@ -527,7 +488,7 @@ int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
 
 
     // If key repeat is active, we'll need to cap our maximum wait time to handle repeats
     // If key repeat is active, we'll need to cap our maximum wait time to handle repeats
     wl_list_for_each (seat, &d->seat_list, link) {
     wl_list_for_each (seat, &d->seat_list, link) {
-        if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
+        if (seat->keyboard.repeat.key) {
             const Uint64 elapsed = start - seat->keyboard.repeat.sdl_press_time_ns;
             const Uint64 elapsed = start - seat->keyboard.repeat.sdl_press_time_ns;
             const Uint64 next_repeat_wait_time = (seat->keyboard.repeat.next_repeat_ns - elapsed) + 1;
             const Uint64 next_repeat_wait_time = (seat->keyboard.repeat.next_repeat_ns - elapsed) + 1;
             if (timeoutNS < 0 || next_repeat_wait_time <= timeoutNS) {
             if (timeoutNS < 0 || next_repeat_wait_time <= timeoutNS) {
@@ -664,7 +625,7 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this)
     if (ret >= 0) {
     if (ret >= 0) {
         // Synthesize key repeat events.
         // Synthesize key repeat events.
         wl_list_for_each (seat, &d->seat_list, link) {
         wl_list_for_each (seat, &d->seat_list, link) {
-            if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
+            if (seat->keyboard.repeat.key) {
                 Wayland_SeatSetKeymap(seat);
                 Wayland_SeatSetKeymap(seat);
 
 
                 const Uint64 elapsed = SDL_GetTicksNS() - seat->keyboard.repeat.sdl_press_time_ns;
                 const Uint64 elapsed = SDL_GetTicksNS() - seat->keyboard.repeat.sdl_press_time_ns;
@@ -2181,7 +2142,7 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
     }
     }
 
 
     // Stop key repeat before clearing keyboard focus
     // Stop key repeat before clearing keyboard focus
-    keyboard_repeat_clear(&seat->keyboard.repeat);
+    seat->keyboard.repeat.key = 0;
 
 
     SDL_Window *keyboard_focus = SDL_GetKeyboardFocus();
     SDL_Window *keyboard_focus = SDL_GetKeyboardFocus();
 
 
@@ -2304,7 +2265,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
             has_text = keyboard_input_get_text(text, seat, key, true, &handled_by_ime);
             has_text = keyboard_input_get_text(text, seat, key, true, &handled_by_ime);
         }
         }
     } else {
     } else {
-        if (keyboard_repeat_key_is_set(&seat->keyboard.repeat, key)) {
+        if (key == seat->keyboard.repeat.key) {
             /* Send any due key repeat events before stopping the repeat and generating the key up event.
             /* Send any due key repeat events before stopping the repeat and generating the key up event.
              * Compute time based on the Wayland time, as it reports when the release event happened.
              * Compute time based on the Wayland time, as it reports when the release event happened.
              * Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
              * Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
@@ -2312,7 +2273,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
              */
              */
             const Uint64 elapsed = SDL_MS_TO_NS(time - seat->keyboard.repeat.wl_press_time_ms);
             const Uint64 elapsed = SDL_MS_TO_NS(time - seat->keyboard.repeat.wl_press_time_ms);
             keyboard_repeat_handle(&seat->keyboard.repeat, elapsed);
             keyboard_repeat_handle(&seat->keyboard.repeat, elapsed);
-            keyboard_repeat_clear(&seat->keyboard.repeat);
+            seat->keyboard.repeat.key = 0;
         }
         }
         keyboard_input_get_text(text, seat, key, false, &handled_by_ime);
         keyboard_input_get_text(text, seat, key, false, &handled_by_ime);
     }
     }
@@ -2348,7 +2309,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
             SDL_SendKeyboardText(text);
             SDL_SendKeyboardText(text);
         }
         }
         if (seat->keyboard.xkb.keymap && WAYLAND_xkb_keymap_key_repeats(seat->keyboard.xkb.keymap, key + 8)) {
         if (seat->keyboard.xkb.keymap && WAYLAND_xkb_keymap_key_repeats(seat->keyboard.xkb.keymap, key + 8)) {
-            keyboard_repeat_set(&seat->keyboard.repeat, seat->keyboard.sdl_id, key, time, timestamp_ns, scancode, has_text, text);
+            keyboard_repeat_set(&seat->keyboard.repeat, seat->keyboard.sdl_id, key, time, timestamp_ns, scancode, has_text ? text : NULL);
         }
         }
     }
     }
 }
 }
@@ -2378,12 +2339,11 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
                                   0, 0, group);
                                   0, 0, group);
 
 
     // If a key is repeating, update the text to apply the modifier.
     // If a key is repeating, update the text to apply the modifier.
-    if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
+    if (seat->keyboard.repeat.key) {
         char text[8];
         char text[8];
-        const uint32_t key = keyboard_repeat_get_key(&seat->keyboard.repeat);
 
 
-        if (keyboard_input_get_text(text, seat, key, true, NULL)) {
-            keyboard_repeat_set_text(&seat->keyboard.repeat, text);
+        if (keyboard_input_get_text(text, seat, seat->keyboard.repeat.key, true, NULL)) {
+            SDL_strlcpy(seat->keyboard.repeat.text, text, SDL_arraysize(seat->keyboard.repeat.text));
         }
         }
     }
     }
 
 
@@ -2401,9 +2361,12 @@ static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keybo
                                         int32_t rate, int32_t delay)
                                         int32_t rate, int32_t delay)
 {
 {
     SDL_WaylandSeat *seat = data;
     SDL_WaylandSeat *seat = data;
-    seat->keyboard.repeat.repeat_rate = SDL_clamp(rate, 0, 1000);
+    seat->keyboard.repeat.repeat_rate = rate;
     seat->keyboard.repeat.repeat_delay_ms = delay;
     seat->keyboard.repeat.repeat_delay_ms = delay;
-    seat->keyboard.repeat.is_initialized = true;
+
+    if (!rate) {
+        seat->keyboard.repeat.key = 0; // Cancel the repeat to avoid dividing by a rate of zero.
+    }
 }
 }
 
 
 static const struct wl_keyboard_listener keyboard_listener = {
 static const struct wl_keyboard_listener keyboard_listener = {

+ 3 - 5
src/video/wayland/SDL_waylandevents_c.h

@@ -43,16 +43,14 @@ typedef struct
 {
 {
     Sint32 repeat_rate;     // Repeat rate in range of [1, 1000] character(s) per second
     Sint32 repeat_rate;     // Repeat rate in range of [1, 1000] character(s) per second
     Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
     Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
-    Uint32 keyboard_id;     // ID of the source keyboard.
-    bool is_initialized;
 
 
-    bool is_key_down;
-    Uint32 key;
+    Uint32 key;               // Key code of the repeating key
+    Uint32 scancode;          // Scancode of the repeating key
+    Uint32 keyboard_id;       // ID of the source keyboard
     Uint32 wl_press_time_ms;  // Key press time as reported by the Wayland API in milliseconds
     Uint32 wl_press_time_ms;  // Key press time as reported by the Wayland API in milliseconds
     Uint64 base_time_ns;      // Key press time as reported by the Wayland API in nanoseconds
     Uint64 base_time_ns;      // Key press time as reported by the Wayland API in nanoseconds
     Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
     Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
     Uint64 next_repeat_ns;    // Next repeat event in nanoseconds
     Uint64 next_repeat_ns;    // Next repeat event in nanoseconds
-    Uint32 scancode;
     char text[8];
     char text[8];
 } SDL_WaylandKeyboardRepeat;
 } SDL_WaylandKeyboardRepeat;