From cbff71f6e2bcfc64005bc49ea3e64a7e3aced6f0 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 9 Oct 2012 13:12:02 +0200 Subject: [PATCH] uterm: input: implement software key-repeat To allow users to specify key-repeat rates/delays, we now implement software key-repeat. This is mostly copied from wlt_toolkit.c which already does this. Signed-off-by: David Herrmann --- src/uterm_input.c | 24 +++++++++----- src/uterm_input.h | 7 ++++- src/uterm_input_uxkb.c | 85 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 99 insertions(+), 17 deletions(-) diff --git a/src/uterm_input.c b/src/uterm_input.c index a5e406d..083d4fb 100644 --- a/src/uterm_input.c +++ b/src/uterm_input.c @@ -60,16 +60,10 @@ static void notify_key(struct uterm_input_dev *dev, uint16_t code, int32_t value) { - int ret; - if (type != EV_KEY) return; - ret = uxkb_dev_process(dev, value, code); - if (ret) - return; - - shl_hook_call(dev->input->hook, dev->input, &dev->event); + uxkb_dev_process(dev, value, code); } static void input_data_dev(struct ev_fd *fd, int mask, void *data) @@ -172,6 +166,8 @@ static void input_new_dev(struct uterm_input *input, dev->input = input; dev->rfd = -1; dev->features = features; + dev->repeat_rate = 25; + dev->repeat_delay = 250; dev->node = strdup(node); if (!dev->node) @@ -184,10 +180,16 @@ static void input_new_dev(struct uterm_input *input, dev->event.codepoints = malloc(sizeof(uint32_t) * dev->num_syms); if (!dev->event.codepoints) goto err_syms; + dev->repeat_event.keysyms = malloc(sizeof(uint32_t) * dev->num_syms); + if (!dev->repeat_event.keysyms) + goto err_codepoints; + dev->repeat_event.codepoints = malloc(sizeof(uint32_t) * dev->num_syms); + if (!dev->repeat_event.codepoints) + goto err_rsyms; ret = uxkb_dev_init(dev); if (ret) - goto err_codepoints; + goto err_rcodepoints; if (input->awake > 0) { ret = input_wake_up_dev(dev); @@ -201,6 +203,10 @@ static void input_new_dev(struct uterm_input *input, err_kbd: uxkb_dev_destroy(dev); +err_rcodepoints: + free(dev->repeat_event.codepoints); +err_rsyms: + free(dev->repeat_event.keysyms); err_codepoints: free(dev->event.codepoints); err_syms: @@ -217,6 +223,8 @@ static void input_free_dev(struct uterm_input_dev *dev) input_sleep_dev(dev); shl_dlist_unlink(&dev->list); uxkb_dev_destroy(dev); + free(dev->repeat_event.codepoints); + free(dev->repeat_event.keysyms); free(dev->event.codepoints); free(dev->event.keysyms); free(dev->node); diff --git a/src/uterm_input.h b/src/uterm_input.h index 0798ff3..eed5b46 100644 --- a/src/uterm_input.h +++ b/src/uterm_input.h @@ -47,8 +47,13 @@ struct uterm_input_dev { struct ev_fd *fd; struct xkb_state *state; - struct uterm_input_event event; unsigned int num_syms; + struct uterm_input_event event; + struct uterm_input_event repeat_event; + + unsigned int repeat_rate; + unsigned int repeat_delay; + struct ev_timer *repeat_timer; }; struct uterm_input { diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c index 09b8a52..0d40274 100644 --- a/src/uterm_input_uxkb.c +++ b/src/uterm_input_uxkb.c @@ -32,6 +32,7 @@ #include #include #include "log.h" +#include "shl_hook.h" #include "shl_misc.h" #include "uterm.h" #include "uterm_input.h" @@ -91,18 +92,41 @@ void uxkb_desc_destroy(struct uterm_input *input) xkb_context_unref(input->ctx); } +static void timer_event(struct ev_timer *timer, uint64_t num, void *data) +{ + struct uterm_input_dev *dev = data; + + dev->repeat_event.handled = false; + shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event); +} + int uxkb_dev_init(struct uterm_input_dev *dev) { + int ret; + + ret = ev_eloop_new_timer(dev->input->eloop, &dev->repeat_timer, NULL, + timer_event, dev); + if (ret) + return ret; + dev->state = xkb_state_new(dev->input->keymap); - if (!dev->state) - return -ENOMEM; + if (!dev->state) { + log_error("cannot create XKB state"); + ret = -ENOMEM; + goto err_timer; + } return 0; + +err_timer: + ev_eloop_rm_timer(dev->repeat_timer); + return ret; } void uxkb_dev_destroy(struct uterm_input_dev *dev) { xkb_state_unref(dev->state); + ev_eloop_rm_timer(dev->repeat_timer); } #define EVDEV_KEYCODE_OFFSET 8 @@ -121,6 +145,10 @@ int uxkb_dev_process(struct uterm_input_dev *dev, const xkb_keysym_t *keysyms; int num_keysyms, i; uint32_t *tmp; + struct itimerspec spec; + + if (key_state == KEY_REPEATED) + return -ENOKEY; state = dev->state; keymap = xkb_state_get_map(state); @@ -133,12 +161,6 @@ int uxkb_dev_process(struct uterm_input_dev *dev, else if (key_state == KEY_RELEASED) xkb_state_update_key(state, keycode, XKB_KEY_UP); - if (key_state == KEY_RELEASED) - return -ENOKEY; - - if (key_state == KEY_REPEATED && !xkb_key_repeats(keymap, keycode)) - return -ENOKEY; - if (num_keysyms <= 0) return -ENOKEY; @@ -159,6 +181,22 @@ int uxkb_dev_process(struct uterm_input_dev *dev, } dev->event.codepoints = tmp; + tmp = realloc(dev->repeat_event.keysyms, + sizeof(uint32_t) * num_keysyms); + if (!tmp) { + log_warning("cannot reallocate keysym buffer"); + return -ENOKEY; + } + dev->repeat_event.keysyms = tmp; + + tmp = realloc(dev->repeat_event.codepoints, + sizeof(uint32_t) * num_keysyms); + if (!tmp) { + log_warning("cannot reallocate codepoints buffer"); + return -ENOKEY; + } + dev->repeat_event.codepoints = tmp; + dev->num_syms = num_keysyms; } @@ -175,6 +213,37 @@ int uxkb_dev_process(struct uterm_input_dev *dev, dev->event.codepoints[i] = UTERM_INPUT_INVALID; } + if (key_state == KEY_RELEASED && + dev->repeat_event.num_syms == num_keysyms && + !memcmp(dev->repeat_event.keysyms, + keysyms, + sizeof(uint32_t) * num_keysyms)) { + ev_timer_update(dev->repeat_timer, NULL); + } else if (key_state == KEY_PRESSED && + xkb_key_repeats(keymap, keycode)) { + dev->repeat_event.keycode = code; + dev->repeat_event.ascii = dev->event.ascii; + dev->repeat_event.mods = dev->event.mods; + dev->repeat_event.num_syms = num_keysyms; + + for (i = 0; i < num_keysyms; ++i) { + dev->repeat_event.keysyms[i] = dev->event.keysyms[i]; + dev->repeat_event.codepoints[i] = + dev->event.codepoints[i]; + } + + spec.it_interval.tv_sec = 0; + spec.it_interval.tv_nsec = dev->repeat_rate * 1000000; + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = dev->repeat_delay * 1000000; + ev_timer_update(dev->repeat_timer, &spec); + } + + if (key_state == KEY_RELEASED) + return -ENOKEY; + + shl_hook_call(dev->input->hook, dev->input, &dev->event); + return 0; } -- 2.7.4