Wayland: Use a timerfd for key repeat
diff --git a/src/wl_init.c b/src/wl_init.c
index cc115ff..2a4edb0 100644
--- a/src/wl_init.c
+++ b/src/wl_init.c
@@ -32,6 +32,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/timerfd.h>
#include <unistd.h>
#include <wayland-client.h>
@@ -365,6 +366,7 @@
int keyCode;
int action;
_GLFWwindow* window = _glfw.wl.keyboardFocus;
+ struct itimerspec timer = {};
if (!window)
return;
@@ -377,7 +379,20 @@
_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 @@
_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 22d2ff7..eee0e15 100644
--- a/src/wl_platform.h
+++ b/src/wl_platform.h
@@ -208,6 +208,9 @@
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 62d3867..ba3b43b 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -35,6 +35,7 @@
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
+#include <sys/timerfd.h>
#include <poll.h>
@@ -442,7 +443,9 @@
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 @@
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
{