Wayland: Fix doubled key repeat events when compositor sends repeat events

Fixes #9374
This commit is contained in:
Kovid Goyal 2026-01-15 08:13:37 +05:30
parent f9e3de66d5
commit c389f4d5b8
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 14 additions and 4 deletions

View file

@ -184,6 +184,10 @@ Detailed list of changes
- Fix another rendering glitch caused by :opt:`tab_bar_filter` when adding tabs
from a session (:iss:`9382`)
- Wayland: Fix a regression in the previous release that caused doubled key
repeats on compositors that implement compositor side key repeat events
(:iss:`9374`)
0.45.0 [2025-12-24]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

13
glfw/wl_init.c vendored
View file

@ -315,9 +315,11 @@ static void keyboardHandleKeymap(void* data UNUSED,
}
static bool
needs_synthetic_key_repeat(void) { return _glfw.wl.keyboardRepeatRate > 0 && !_glfw.wl.has_key_repeat_events; }
static void
start_key_repeat_timer(bool initial) {
if (_glfw.wl.keyboardRepeatRate <= 0) return;
#ifdef HAS_TIMER_FD
(void)initial;
struct itimerspec new_value = {.it_value={.tv_nsec = _glfw.wl.keyboardRepeatDelay}, .it_interval={.tv_nsec = (s_to_monotonic_t(1ll) / (monotonic_t)_glfw.wl.keyboardRepeatRate)}};
@ -346,7 +348,7 @@ static void
send_key_repeat_timer_event(id_type timer_id UNUSED, void *data UNUSED) {
char b = 1;
b += write(_glfw.wl.eventLoopData.key_repeat_fds[1], &b, 1);
if (_glfw.wl.keyboardRepeatRate > 0) start_key_repeat_timer(false);
if (needs_synthetic_key_repeat()) start_key_repeat_timer(false);
}
#endif
@ -366,7 +368,7 @@ static void keyboardHandleEnter(void* data UNUSED,
if (keys && _glfw.wl.keyRepeatInfo.key) {
wl_array_for_each(key, keys) {
if (*key == _glfw.wl.keyRepeatInfo.key) {
if (_glfw.wl.keyboardRepeatRate > 0) start_key_repeat_timer(true);
if (needs_synthetic_key_repeat()) start_key_repeat_timer(true);
break;
}
}
@ -411,7 +413,7 @@ static void keyboardHandleKey(void* data UNUSED,
_glfw.wl.serial = serial; _glfw.wl.input_serial = serial;
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
if (action == GLFW_PRESS && needs_synthetic_key_repeat() && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
{
_glfw.wl.keyRepeatInfo.key = key;
_glfw.wl.keyRepeatInfo.keyboardFocusId = window->id;
@ -592,8 +594,10 @@ static void registryHandleGlobal(void* data UNUSED,
{
if (!_glfw.wl.seat)
{
_glfw.wl.has_key_repeat_events = false;
#if defined(WL_KEYBOARD_KEY_STATE_REPEATED_SINCE_VERSION)
_glfw.wl.seatVersion = MIN(WL_KEYBOARD_KEY_STATE_REPEATED_SINCE_VERSION, (int)version);
_glfw.wl.has_key_repeat_events = _glfw.wl.seatVersion >= WL_KEYBOARD_KEY_STATE_REPEATED_SINCE_VERSION;
#elif defined(WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION)
_glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION, (int)version);
#elif defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION)
@ -819,6 +823,7 @@ get_compositor_missing_capabilities(void) {
C(single_pixel_buffer, wp_single_pixel_buffer_manager_v1); C(preferred_scale, has_preferred_buffer_scale);
C(idle_inhibit, idle_inhibit_manager); C(icon, xdg_toplevel_icon_manager_v1); C(bell, xdg_system_bell_v1);
C(window-tag, xdg_toplevel_tag_manager_v1); C(keyboard_shortcuts_inhibit, keyboard_shortcuts_inhibit_manager);
C(key-repeat, has_key_repeat_events);
#define P(x) p += snprintf(p, sizeof(buf) - (p - buf), "%s ", x);
if (_glfw.wl.xdg_wm_base_version < 6) P("window-state-suspended");
if (_glfw.wl.xdg_wm_base_version < 5) P("window-capabilities");

1
glfw/wl_platform.h vendored
View file

@ -361,6 +361,7 @@ typedef struct _GLFWlibraryWayland
int compositorVersion;
int seatVersion;
bool has_key_repeat_events;
struct wl_surface* cursorSurface;
GLFWCursorShape cursorPreviousShape;