diff --git a/include/seat.h b/include/seat.h index 570b1da64..daddd421b 100644 --- a/include/seat.h +++ b/include/seat.h @@ -1,8 +1,12 @@ #ifndef _SWAYLOCK_SEAT_H #define _SWAYLOCK_SEAT_H #include +#include #include +struct loop; +struct loop_timer; + struct swaylock_xkb { bool caps_lock; bool control; @@ -16,6 +20,11 @@ struct swaylock_seat { struct wl_pointer *pointer; struct wl_keyboard *keyboard; struct wl_touch *touch; + int32_t repeat_period_ms; + int32_t repeat_delay_ms; + uint32_t repeat_sym; + uint32_t repeat_codepoint; + struct loop_timer *repeat_timer; }; extern const struct wl_seat_listener seat_listener; diff --git a/loop.c b/loop.c index 5dedfb2c7..5cce8677f 100644 --- a/loop.c +++ b/loop.c @@ -21,6 +21,7 @@ struct loop_timer { void (*callback)(void *data); void *data; struct timespec expiry; + bool removed; struct wl_list link; // struct loop_timer::link }; @@ -104,12 +105,19 @@ void loop_poll(struct loop *loop) { clock_gettime(CLOCK_MONOTONIC, &now); struct loop_timer *timer = NULL, *tmp_timer = NULL; wl_list_for_each_safe(timer, tmp_timer, &loop->timers, link) { + if (timer->removed) { + wl_list_remove(&timer->link); + free(timer); + continue; + } + bool expired = timer->expiry.tv_sec < now.tv_sec || (timer->expiry.tv_sec == now.tv_sec && timer->expiry.tv_nsec < now.tv_nsec); if (expired) { timer->callback(timer->data); - loop_remove_timer(loop, timer); + wl_list_remove(&timer->link); + free(timer); } } } @@ -184,8 +192,7 @@ bool loop_remove_timer(struct loop *loop, struct loop_timer *remove) { struct loop_timer *timer = NULL, *tmp_timer = NULL; wl_list_for_each_safe(timer, tmp_timer, &loop->timers, link) { if (timer == remove) { - wl_list_remove(&timer->link); - free(timer); + timer->removed = true; return true; } } diff --git a/main.c b/main.c index fd48ee60d..119f999e0 100644 --- a/main.c +++ b/main.c @@ -585,7 +585,7 @@ static void handle_global(void *data, struct wl_registry *registry, &wl_shm_interface, 1); } else if (strcmp(interface, wl_seat_interface.name) == 0) { struct wl_seat *seat = wl_registry_bind( - registry, name, &wl_seat_interface, 3); + registry, name, &wl_seat_interface, 4); struct swaylock_seat *swaylock_seat = calloc(1, sizeof(struct swaylock_seat)); swaylock_seat->state = state; diff --git a/seat.c b/seat.c index 9ff33fef5..ab249aff8 100644 --- a/seat.c +++ b/seat.c @@ -6,10 +6,12 @@ #include "log.h" #include "swaylock.h" #include "seat.h" +#include "loop.h" static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { - struct swaylock_state *state = data; + struct swaylock_seat *seat = data; + struct swaylock_state *state = seat->state; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); swaylock_log(LOG_ERROR, "Unknown keymap format %d, aborting", format); @@ -45,9 +47,18 @@ static void keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, // Who cares } +static void keyboard_repeat(void *data) { + struct swaylock_seat *seat = data; + struct swaylock_state *state = seat->state; + seat->repeat_timer = loop_add_timer( + state->eventloop, seat->repeat_period_ms, keyboard_repeat, seat); + swaylock_handle_key(state, seat->repeat_sym, seat->repeat_codepoint); +} + static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state) { - struct swaylock_state *state = data; + struct swaylock_seat *seat = data; + struct swaylock_state *state = seat->state; enum wl_keyboard_key_state key_state = _key_state; xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb.state, key + 8); uint32_t keycode = key_state == WL_KEYBOARD_KEY_STATE_PRESSED ? @@ -56,12 +67,25 @@ static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) { swaylock_handle_key(state, sym, codepoint); } + + if (seat->repeat_timer) { + loop_remove_timer(seat->state->eventloop, seat->repeat_timer); + seat->repeat_timer = NULL; + } + + if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED && seat->repeat_period_ms > 0) { + seat->repeat_sym = sym; + seat->repeat_codepoint = codepoint; + seat->repeat_timer = loop_add_timer( + seat->state->eventloop, seat->repeat_delay_ms, keyboard_repeat, seat); + } } static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { - struct swaylock_state *state = data; + struct swaylock_seat *seat = data; + struct swaylock_state *state = seat->state; int layout_same = xkb_state_layout_index_is_active(state->xkb.state, group, XKB_STATE_LAYOUT_EFFECTIVE); if (!layout_same) { @@ -82,7 +106,14 @@ static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, static void keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) { - // TODO + struct swaylock_seat *seat = data; + if (rate <= 0) { + seat->repeat_period_ms = -1; + } else { + // Keys per second -> milliseconds between keys + seat->repeat_period_ms = 1000 / rate; + } + seat->repeat_delay_ms = delay; } static const struct wl_keyboard_listener keyboard_listener = { @@ -199,7 +230,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { seat->keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(seat->keyboard, &keyboard_listener, seat->state); + wl_keyboard_add_listener(seat->keyboard, &keyboard_listener, seat); } if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { seat->touch = wl_seat_get_touch(wl_seat);