uterm: input: implement software key-repeat
authorDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 9 Oct 2012 11:12:02 +0000 (13:12 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 9 Oct 2012 11:12:02 +0000 (13:12 +0200)
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 <dh.herrmann@googlemail.com>
src/uterm_input.c
src/uterm_input.h
src/uterm_input_uxkb.c

index a5e406d..083d4fb 100644 (file)
@@ -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);
index 0798ff3..eed5b46 100644 (file)
@@ -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 {
index 09b8a52..0d40274 100644 (file)
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <xkbcommon/xkbcommon.h>
 #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;
 }