From a98badf088284a29c5adbb9d2376d6e5935b5c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 9 Feb 2026 19:48:45 +0100 Subject: [PATCH] Wayland: Fix key repeat on very old compositors The client-side key repeat timer fd was only created for wl_seat version 4 or later, but was then used unconditionally during event processing. Rather than have this mechanism do nothing in a more correct way on wl_seat version 3 or earlier (which is very old by now), this commit creates the key repeat timer fd and then sets (hopefully gentle) hardcoded repeat delay and rate. --- README.md | 1 + src/wl_init.c | 17 ++++++++++------- src/wl_window.c | 7 +++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b05132e7..a5689a5c 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ information on what to include when reporting a bug. potential segmentation fault (#2744) - [Wayland] Bugfix: Confining or disabling the cursor could segfault on compositors without `pointer-constraints-unstable-v1` + - [Wayland] Bugfix: Key repeat did not function on very old compositors - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale diff --git a/src/wl_init.c b/src/wl_init.c index 1d0d3ef8..41cbc57c 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -137,13 +137,6 @@ static void registryHandleGlobal(void* userData, wl_registry_bind(registry, name, &wl_seat_interface, _glfw_min(4, version)); _glfwAddSeatListenerWayland(_glfw.wl.seat); - - if (wl_seat_get_version(_glfw.wl.seat) >= - WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) - { - _glfw.wl.keyRepeatTimerfd = - timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); - } } } else if (strcmp(interface, "wl_data_device_manager") == 0) @@ -834,6 +827,16 @@ int _glfwInitWayland(void) createKeyTables(); + _glfw.wl.keyRepeatTimerfd = + timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + if (_glfw.wl.keyRepeatTimerfd == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create timerfd: %s", + strerror(errno)); + return GLFW_FALSE; + } + _glfw.wl.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!_glfw.wl.xkb.context) { diff --git a/src/wl_window.c b/src/wl_window.c index b00b8ced..1efb7256 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1942,6 +1942,13 @@ static void seatHandleCapabilities(void* userData, { _glfw.wl.keyboard = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); + + if (wl_keyboard_get_version(_glfw.wl.keyboard) < + WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) + { + _glfw.wl.keyRepeatRate = 4; + _glfw.wl.keyRepeatDelay = 500; + } } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) {