From 90f5edc0b8fa3c30061df85832779bd14933155e Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 30 Jan 2018 16:22:25 +0100 Subject: [PATCH] Wayland: Use a timerfd for key repeat --- src/wl_init.c | 19 +++++++++++++++++++ src/wl_platform.h | 3 +++ src/wl_window.c | 26 +++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index cc115ffa..2a4edb03 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -365,6 +366,7 @@ static void keyboardHandleKey(void* data, int keyCode; int action; _GLFWwindow* window = _glfw.wl.keyboardFocus; + struct itimerspec timer = {}; if (!window) return; @@ -377,7 +379,20 @@ static void keyboardHandleKey(void* data, _glfw.wl.xkb.modifiers); if (action == GLFW_PRESS) + { inputChar(window, key); + + if (_glfw.wl.keyboardRepeatRate > 0) + { + _glfw.wl.keyboardLastKey = keyCode; + _glfw.wl.keyboardLastScancode = key; + timer.it_interval.tv_sec = _glfw.wl.keyboardRepeatRate / 1000; + timer.it_interval.tv_nsec = (_glfw.wl.keyboardRepeatRate % 1000) * 1000000; + timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000; + timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000; + } + } + timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL); } static void keyboardHandleModifiers(void* data, @@ -822,6 +837,10 @@ int _glfwPlatformInit(void) _glfwInitTimerPOSIX(); + _glfw.wl.timerfd = -1; + if (_glfw.wl.seatVersion >= 4) + _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, 0); + if (_glfw.wl.pointer && _glfw.wl.shm) { _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); diff --git a/src/wl_platform.h b/src/wl_platform.h index 22d2ff72..eee0e15e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -208,6 +208,9 @@ typedef struct _GLFWlibraryWayland int32_t keyboardRepeatRate; int32_t keyboardRepeatDelay; + int keyboardLastKey; + int keyboardLastScancode; + int timerfd; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1]; diff --git a/src/wl_window.c b/src/wl_window.c index 62d38673..ba3b43b2 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -442,7 +443,9 @@ handleEvents(int timeout) struct wl_display* display = _glfw.wl.display; struct pollfd fds[] = { { wl_display_get_fd(display), POLLIN }, + { _glfw.wl.timerfd, POLLIN }, }; + char buf[8]; while (wl_display_prepare_read(display) != 0) wl_display_dispatch_pending(display); @@ -462,10 +465,27 @@ handleEvents(int timeout) return; } - if (poll(fds, 1, timeout) > 0) + if (poll(fds, 2, timeout) > 0) { - wl_display_read_events(display); - wl_display_dispatch_pending(display); + if (fds[0].revents & POLLIN) + { + wl_display_read_events(display); + wl_display_dispatch_pending(display); + } + else + { + wl_display_cancel_read(display); + } + + if (fds[1].revents & POLLIN) + { + _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey, + _glfw.wl.keyboardLastScancode, GLFW_REPEAT, + _glfw.wl.xkb.modifiers); + + // Required to mark the fd as clean. + read(_glfw.wl.timerfd, &buf, 8); + } } else {