aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-08-25 00:32:25 +0100
committerHarry Jeffery <harry@exec64.co.uk>2019-08-25 00:32:25 +0100
commita9b4be7e4a75a8e3d7041cedc99cb808d1da5e1d (patch)
treeade8de9ba6335b11a544a740b51764c790df6721 /src
parent1eb634953f018e45aeafde619141c635cd14502c (diff)
downloadimv-a9b4be7e4a75a8e3d7041cedc99cb808d1da5e1d.tar.gz
wl_window: Implement key repeating
Diffstat (limited to 'src')
-rw-r--r--src/keyboard.c5
-rw-r--r--src/keyboard.h3
-rw-r--r--src/wl_window.c87
3 files changed, 74 insertions, 21 deletions
diff --git a/src/keyboard.c b/src/keyboard.c
index 55e4e49..119f3f8 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -130,3 +130,8 @@ void imv_keyboard_set_keymap(struct imv_keyboard *keyboard, const char *keymap)
xkb_state_unref(keyboard->state);
keyboard->state = xkb_state_new(keyboard->keymap);
}
+
+bool imv_keyboard_should_key_repeat(struct imv_keyboard *keyboard, int scancode)
+{
+ return xkb_keymap_key_repeats(keyboard->keymap, scancode + scancode_offset);
+}
diff --git a/src/keyboard.h b/src/keyboard.h
index 05036c4..cba806b 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -31,4 +31,7 @@ size_t imv_keyboard_get_text(struct imv_keyboard *keyboard, int scancode, char *
/* Initialise the keymap from a string containing the description */
void imv_keyboard_set_keymap(struct imv_keyboard *keyboard, const char *keymap);
+/* Should the key on a given scancode repeat when held down */
+bool imv_keyboard_should_key_repeat(struct imv_keyboard *keyboard, int scancode);
+
#endif
diff --git a/src/wl_window.c b/src/wl_window.c
index 040aefb..cb61899 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -8,9 +8,11 @@
#include <limits.h>
#include <poll.h>
#include <pthread.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <time.h>
#include <unistd.h>
#include <wayland-client.h>
@@ -41,6 +43,11 @@ struct imv_window {
int display_fd;
int pipe_fds[2];
+ timer_t timer_id;
+ int repeat_scancode; /* scancode of key to repeat */
+ int repeat_delay; /* time before repeat in ms */
+ int repeat_interval; /* time between repeats in ms */
+
int width;
int height;
bool fullscreen;
@@ -140,28 +147,15 @@ static void cleanup_event(struct imv_event *event)
}
}
-static void keyboard_key(void *data, struct wl_keyboard *keyboard,
- uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+static void push_keypress(struct imv_window *window, int scancode)
{
- (void)serial;
- (void)keyboard;
- (void)time;
- (void)state;
- struct imv_window *window = data;
-
- imv_keyboard_update_key(window->keyboard, key, state);
-
- if (!state) {
- return;
- }
-
char keyname[32] = {0};
- imv_keyboard_keyname(window->keyboard, key, keyname, sizeof keyname);
+ imv_keyboard_keyname(window->keyboard, scancode, keyname, sizeof keyname);
char text[64] = {0};
- imv_keyboard_get_text(window->keyboard, key, text, sizeof text);
+ imv_keyboard_get_text(window->keyboard, scancode, text, sizeof text);
- char *desc = imv_keyboard_describe_key(window->keyboard, key);
+ char *desc = imv_keyboard_describe_key(window->keyboard, scancode);
if (!desc) {
desc = strdup("");
}
@@ -170,7 +164,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
.type = IMV_EVENT_KEYBOARD,
.data = {
.keyboard = {
- .scancode = key,
+ .scancode = scancode,
.keyname = strdup(keyname),
.description = desc,
.text = strdup(text),
@@ -180,6 +174,42 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
imv_window_push_event(window, &e);
}
+static void keyboard_key(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+ (void)serial;
+ (void)keyboard;
+ (void)time;
+ struct imv_window *window = data;
+
+ imv_keyboard_update_key(window->keyboard, key, state);
+
+ if (!state) {
+ /* If a key repeat timer is running, stop it */
+ struct itimerspec off = {0};
+ timer_settime(window->timer_id, 0, &off, NULL);
+ return;
+ }
+
+ push_keypress(window, key);
+
+ if (imv_keyboard_should_key_repeat(window->keyboard, key)) {
+ /* Kick off the key-repeat timer for the current key */
+ window->repeat_scancode = key;
+ struct itimerspec period = {
+ .it_value = {
+ .tv_sec = 0,
+ .tv_nsec = window->repeat_delay * 1000 * 1000,
+ },
+ .it_interval = {
+ .tv_sec = 0,
+ .tv_nsec = window->repeat_interval * 1000 * 1000,
+ },
+ };
+ timer_settime(window->timer_id, 0, &period, NULL);
+ }
+}
+
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
@@ -198,10 +228,10 @@ static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
static void keyboard_repeat(void *data, struct wl_keyboard *keyboard,
int32_t rate, int32_t delay)
{
- (void)data;
(void)keyboard;
- (void)rate;
- (void)delay;
+ struct imv_window *window = data;
+ window->repeat_delay = delay;
+ window->repeat_interval = 1000 / rate;
}
static const struct wl_keyboard_listener keyboard_listener = {
@@ -721,6 +751,12 @@ static void shutdown_wayland(struct imv_window *window)
}
}
+static void on_timer(union sigval sigval)
+{
+ struct imv_window *window = sigval.sival_ptr;
+ push_keypress(window, window->repeat_scancode);
+}
+
struct imv_window *imv_window_create(int width, int height, const char *title)
{
/* Ensure event writes will always be atomic */
@@ -734,11 +770,20 @@ struct imv_window *imv_window_create(int width, int height, const char *title)
window->wl_outputs = list_create();
connect_to_wayland(window);
create_window(window, width, height, title);
+
+ struct sigevent timer_handler = {
+ .sigev_notify = SIGEV_THREAD,
+ .sigev_value.sival_ptr = window,
+ .sigev_notify_function = on_timer,
+ };
+ int timer_rc = timer_create(CLOCK_MONOTONIC, &timer_handler, &window->timer_id);
+ assert(timer_rc == 0);
return window;
}
void imv_window_free(struct imv_window *window)
{
+ timer_delete(&window->timer_id);
imv_keyboard_free(window->keyboard);
free(window->keymap);
shutdown_wayland(window);