Skip to content

Commit 31267fe

Browse files
committed
wayland: Use raw timestamps to calculate the elapsed repeat time on a key up event
Using processed timestamps can result in anomalies that cause excessive repeat events, and hard caps can cause issues. In the key event handler, use the raw elapsed time to calculate any remaining repeat events to avoid the artifacts that can result from using processed timestamps. The Wayland key repeat rate ranges from 0 to 1000 per second, so millisecond resolution doesn't lose any precision. (cherry picked from commit e3d44cd)
1 parent 6a5bac7 commit 31267fe

File tree

2 files changed

+18
-29
lines changed

2 files changed

+18
-29
lines changed

src/video/wayland/SDL_waylandevents.c

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,6 @@ static Uint64 Wayland_GetKeyboardTimestamp(struct SDL_WaylandInput *input, Uint3
212212
return 0;
213213
}
214214

215-
static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
216-
{
217-
return input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms);
218-
}
219-
220215
static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
221216
{
222217
if (wl_timestamp_ms) {
@@ -273,18 +268,10 @@ static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint6
273268
{
274269
bool ret = false;
275270

276-
/* Cap the elapsed time to something sane in case the compositor sends a bad timestamp,
277-
* which can result it in it looking like the key has been pressed for a *very* long time,
278-
* bringing everything to a halt while it tries to enqueue all the repeat events.
279-
*
280-
* 3 seconds seems reasonable.
281-
*/
282-
elapsed = SDL_min(elapsed, SDL_MS_TO_NS(3000));
283-
284271
while (elapsed >= repeat_info->next_repeat_ns) {
285272
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
286-
const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns;
287-
SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
273+
const Uint64 timestamp = repeat_info->base_time_ns + repeat_info->next_repeat_ns;
274+
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
288275
}
289276
if (repeat_info->text[0]) {
290277
SDL_SendKeyboardText(repeat_info->text);
@@ -303,16 +290,17 @@ static void keyboard_repeat_clear(SDL_WaylandKeyboardRepeat *repeat_info)
303290
repeat_info->is_key_down = false;
304291
}
305292

306-
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint64 wl_press_time_ns,
307-
uint32_t scancode, bool has_text, char text[8])
293+
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint32 wl_press_time_ms,
294+
Uint64 base_time_ns, uint32_t scancode, bool has_text, char text[8])
308295
{
309296
if (!repeat_info->is_initialized || !repeat_info->repeat_rate) {
310297
return;
311298
}
312299
repeat_info->is_key_down = true;
313300
repeat_info->keyboard_id = keyboard_id;
314301
repeat_info->key = key;
315-
repeat_info->wl_press_time_ns = wl_press_time_ns;
302+
repeat_info->wl_press_time_ms = wl_press_time_ms;
303+
repeat_info->base_time_ns = base_time_ns;
316304
repeat_info->sdl_press_time_ns = SDL_GetTicksNS();
317305
repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms);
318306
repeat_info->scancode = scancode;
@@ -1867,7 +1855,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
18671855
char text[8];
18681856
bool has_text = false;
18691857
bool handled_by_ime = false;
1870-
const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(input, time);
1858+
const Uint64 timestamp_ns = Wayland_GetKeyboardTimestamp(input, time);
18711859

18721860
Wayland_UpdateImplicitGrabSerial(input, serial);
18731861

@@ -1883,17 +1871,17 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
18831871
* Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
18841872
* which may be off if the application hasn't pumped events for a while.
18851873
*/
1886-
keyboard_repeat_handle(&input->keyboard_repeat, timestamp_raw_ns - input->keyboard_repeat.wl_press_time_ns);
1874+
const Uint64 elapsed = SDL_MS_TO_NS(time - input->keyboard_repeat.wl_press_time_ms);
1875+
keyboard_repeat_handle(&input->keyboard_repeat, elapsed);
18871876
keyboard_repeat_clear(&input->keyboard_repeat);
18881877
}
18891878
keyboard_input_get_text(text, input, key, false, &handled_by_ime);
18901879
}
18911880

18921881
const SDL_Scancode scancode = Wayland_GetScancodeForKey(input, key);
18931882
Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
1894-
Uint64 timestamp = Wayland_GetKeyboardTimestamp(input, time);
18951883

1896-
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
1884+
SDL_SendKeyboardKeyIgnoreModifiers(timestamp_ns, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
18971885

18981886
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
18991887
if (has_text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
@@ -1902,7 +1890,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
19021890
}
19031891
}
19041892
if (input->xkb.keymap && WAYLAND_xkb_keymap_key_repeats(input->xkb.keymap, key + 8)) {
1905-
keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, timestamp_raw_ns, scancode, has_text, text);
1893+
keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, time, timestamp_ns, scancode, has_text, text);
19061894
}
19071895
}
19081896
}

src/video/wayland/SDL_waylandevents_c.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,18 @@ typedef struct SDL_WaylandTabletInput
4949

5050
typedef struct
5151
{
52-
int32_t repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
53-
int32_t repeat_delay_ms; // Time to first repeat event in milliseconds
54-
Uint32 keyboard_id; // ID of the source keyboard.
52+
Sint32 repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
53+
Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
54+
Uint32 keyboard_id; // ID of the source keyboard.
5555
bool is_initialized;
5656

5757
bool is_key_down;
58-
uint32_t key;
59-
Uint64 wl_press_time_ns; // Key press time as reported by the Wayland API
58+
Uint32 key;
59+
Uint32 wl_press_time_ms; // Key press time as reported by the Wayland API in milliseconds
60+
Uint64 base_time_ns; // Key press time as reported by the Wayland API in nanoseconds
6061
Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
6162
Uint64 next_repeat_ns; // Next repeat event in nanoseconds
62-
uint32_t scancode;
63+
Uint32 scancode;
6364
char text[8];
6465
} SDL_WaylandKeyboardRepeat;
6566

0 commit comments

Comments
 (0)