mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-22 01:40:17 -05:00
input: use a timer fd to handle keyboard key repeat
Instead of running a repeater thread that writes the key to repeat over a pipe, use a simple timer fd. No more locking or condition signalling. No need to track start/stop/exist states. We simply set up the initial timeout value to be the 'delay', and the interval to be the repeat 'rate'.
This commit is contained in:
parent
c62ce72778
commit
a82f12dd2b
3 changed files with 65 additions and 156 deletions
78
input.c
78
input.c
|
|
@ -7,6 +7,7 @@
|
|||
#include <locale.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include <linux/input-event-codes.h>
|
||||
|
||||
|
|
@ -65,49 +66,58 @@ keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
term_focus_in(term);
|
||||
}
|
||||
|
||||
static bool
|
||||
start_repeater(struct terminal *term, uint32_t key)
|
||||
{
|
||||
if (term->kbd.repeat.dont_re_repeat)
|
||||
return true;
|
||||
|
||||
struct itimerspec t = {
|
||||
.it_value = {.tv_sec = 0, .tv_nsec = term->kbd.repeat.delay * 1000000},
|
||||
.it_interval = {.tv_sec = 0, .tv_nsec = 1000000000 / term->kbd.repeat.rate},
|
||||
};
|
||||
|
||||
if (t.it_value.tv_nsec >= 1000000000) {
|
||||
t.it_value.tv_sec += t.it_value.tv_nsec / 1000000000;
|
||||
t.it_value.tv_nsec %= 1000000000;
|
||||
}
|
||||
if (t.it_interval.tv_nsec >= 1000000000) {
|
||||
t.it_interval.tv_sec += t.it_interval.tv_nsec / 1000000000;
|
||||
t.it_interval.tv_nsec %= 1000000000;
|
||||
}
|
||||
if (timerfd_settime(term->kbd.repeat.fd, 0, &t, NULL) < 0) {
|
||||
LOG_ERRNO("failed to arm keyboard repeat timer");
|
||||
return false;
|
||||
}
|
||||
|
||||
term->kbd.repeat.key = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
stop_repeater(struct terminal *term, uint32_t key)
|
||||
{
|
||||
if (key != -1 && key != term->kbd.repeat.key)
|
||||
return true;
|
||||
|
||||
if (timerfd_settime(term->kbd.repeat.fd, 0, &(struct itimerspec){{0}}, NULL) < 0) {
|
||||
LOG_ERRNO("failed to disarm keyboard repeat timer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
struct wl_surface *surface)
|
||||
{
|
||||
struct terminal *term = data;
|
||||
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_STOP;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
|
||||
stop_repeater(term, -1);
|
||||
term_focus_out(term);
|
||||
}
|
||||
|
||||
static void
|
||||
start_repeater(struct terminal *term, uint32_t key)
|
||||
{
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (!term->kbd.repeat.dont_re_repeat) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_START;
|
||||
term->kbd.repeat.key = key;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_repeater(struct terminal *term, uint32_t key)
|
||||
{
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (term->kbd.repeat.key == key) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_STOP;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
uint32_t time, uint32_t key, uint32_t state)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue