Skip to content

Commit e3d44cd

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.
1 parent b512735 commit e3d44cd

File tree

2 files changed

+20
-26
lines changed

2 files changed

+20
-26
lines changed

src/video/wayland/SDL_waylandevents.c

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,10 @@ static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
229229
* to accumulate the rollover offset if needed later.
230230
*/
231231

232-
static Uint64 Wayland_GetKeyboardTimestampRaw(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
232+
static Uint64 Wayland_GetKeyboardTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
233233
{
234-
const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
235-
return seat->keyboard.timestamps ? seat->keyboard.highres_timestamp_ns : adjustedTimestampMS;
234+
const Uint64 adjustedTimestampNS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
235+
return Wayland_AdjustEventTimestampBase(seat->keyboard.timestamps ? seat->keyboard.highres_timestamp_ns : adjustedTimestampNS);
236236
}
237237

238238
static Uint64 Wayland_GetPointerTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
@@ -309,17 +309,9 @@ static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint6
309309
{
310310
bool ret = false;
311311

312-
/* Cap the elapsed time to something sane in case the compositor sends a bad timestamp,
313-
* which can result it in it looking like the key has been pressed for a *very* long time,
314-
* bringing everything to a halt while it tries to enqueue all the repeat events.
315-
*
316-
* 3 seconds seems reasonable.
317-
*/
318-
elapsed = SDL_min(elapsed, SDL_MS_TO_NS(3000));
319-
320312
while (elapsed >= repeat_info->next_repeat_ns) {
321313
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
322-
const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns;
314+
const Uint64 timestamp = repeat_info->base_time_ns + repeat_info->next_repeat_ns;
323315
SDL_SendKeyboardKeyIgnoreModifiers(Wayland_AdjustEventTimestampBase(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
324316
}
325317
if (repeat_info->text[0]) {
@@ -339,16 +331,17 @@ static void keyboard_repeat_clear(SDL_WaylandKeyboardRepeat *repeat_info)
339331
repeat_info->is_key_down = false;
340332
}
341333

342-
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint64 wl_press_time_ns,
343-
uint32_t scancode, bool has_text, char text[8])
334+
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint32 wl_press_time_ms,
335+
Uint64 base_time_ns, uint32_t scancode, bool has_text, char text[8])
344336
{
345337
if (!repeat_info->is_initialized || !repeat_info->repeat_rate) {
346338
return;
347339
}
348340
repeat_info->is_key_down = true;
349341
repeat_info->keyboard_id = keyboard_id;
350342
repeat_info->key = key;
351-
repeat_info->wl_press_time_ns = wl_press_time_ns;
343+
repeat_info->wl_press_time_ms = wl_press_time_ms;
344+
repeat_info->base_time_ns = base_time_ns;
352345
repeat_info->sdl_press_time_ns = SDL_GetTicksNS();
353346
repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms);
354347
repeat_info->scancode = scancode;
@@ -1975,7 +1968,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
19751968
char text[8];
19761969
bool has_text = false;
19771970
bool handled_by_ime = false;
1978-
const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(seat, time);
1971+
const Uint64 timestamp_ns = Wayland_GetKeyboardTimestamp(seat, time);
19791972

19801973
Wayland_UpdateImplicitGrabSerial(seat, serial);
19811974

@@ -1996,17 +1989,17 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
19961989
* Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
19971990
* which may be off if the application hasn't pumped events for a while.
19981991
*/
1999-
keyboard_repeat_handle(&seat->keyboard.repeat, timestamp_raw_ns - seat->keyboard.repeat.wl_press_time_ns);
1992+
const Uint64 elapsed = SDL_MS_TO_NS(time - seat->keyboard.repeat.wl_press_time_ms);
1993+
keyboard_repeat_handle(&seat->keyboard.repeat, elapsed);
20001994
keyboard_repeat_clear(&seat->keyboard.repeat);
20011995
}
20021996
keyboard_input_get_text(text, seat, key, false, &handled_by_ime);
20031997
}
20041998

20051999
const SDL_Scancode scancode = Wayland_GetScancodeForKey(seat, key);
20062000
Wayland_HandleModifierKeys(seat, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
2007-
Uint64 timestamp = Wayland_AdjustEventTimestampBase(timestamp_raw_ns);
20082001

2009-
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, seat->keyboard.sdl_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
2002+
SDL_SendKeyboardKeyIgnoreModifiers(timestamp_ns, seat->keyboard.sdl_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
20102003

20112004
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
20122005
if (has_text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
@@ -2015,7 +2008,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
20152008
}
20162009
}
20172010
if (seat->keyboard.xkb.keymap && WAYLAND_xkb_keymap_key_repeats(seat->keyboard.xkb.keymap, key + 8)) {
2018-
keyboard_repeat_set(&seat->keyboard.repeat, seat->keyboard.sdl_id, key, timestamp_raw_ns, scancode, has_text, text);
2011+
keyboard_repeat_set(&seat->keyboard.repeat, seat->keyboard.sdl_id, key, time, timestamp_ns, scancode, has_text, text);
20192012
}
20202013
}
20212014
}

src/video/wayland/SDL_waylandevents_c.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,18 @@ enum SDL_WaylandAxisEvent
4242

4343
typedef struct
4444
{
45-
int32_t repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
46-
int32_t repeat_delay_ms; // Time to first repeat event in milliseconds
47-
Uint32 keyboard_id; // ID of the source keyboard.
45+
Sint32 repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
46+
Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
47+
Uint32 keyboard_id; // ID of the source keyboard.
4848
bool is_initialized;
4949

5050
bool is_key_down;
51-
uint32_t key;
52-
Uint64 wl_press_time_ns; // Key press time as reported by the Wayland API
51+
Uint32 key;
52+
Uint32 wl_press_time_ms; // Key press time as reported by the Wayland API in milliseconds
53+
Uint64 base_time_ns; // Key press time as reported by the Wayland API in nanoseconds
5354
Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
5455
Uint64 next_repeat_ns; // Next repeat event in nanoseconds
55-
uint32_t scancode;
56+
Uint32 scancode;
5657
char text[8];
5758
} SDL_WaylandKeyboardRepeat;
5859

0 commit comments

Comments
 (0)