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
     {