From a9b4be7e4a75a8e3d7041cedc99cb808d1da5e1d Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Sun, 25 Aug 2019 00:32:25 +0100 Subject: wl_window: Implement key repeating --- src/keyboard.c | 5 ++++ src/keyboard.h | 3 ++ src/wl_window.c | 87 +++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 74 insertions(+), 21 deletions(-) (limited to 'src') 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 #include #include +#include #include #include #include +#include #include #include @@ -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); -- cgit v1.2.3