From: David Herrmann Date: Thu, 11 Oct 2012 23:22:47 +0000 (+0200) Subject: uterm: input: fix key-repeat handling X-Git-Tag: kmscon-7~348 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d904eb929a598568c4118ac2bcd2783bad4154a7;p=platform%2Fupstream%2Fkmscon.git uterm: input: fix key-repeat handling We currently do not handle modifier-changes during key-repeats. This is odd as pressing shift should change a repeating key. To avoid duplicating a lot of code, this patch puts most of the key-handling into helper functions and cleans it up. We now handle all kinds of key-repeat specialties and everything should work fine. Reported-by: Ran Benity Signed-off-by: David Herrmann --- diff --git a/src/uterm_input.h b/src/uterm_input.h index 9c126e4..e9c1916 100644 --- a/src/uterm_input.h +++ b/src/uterm_input.h @@ -51,6 +51,7 @@ struct uterm_input_dev { struct uterm_input_event event; struct uterm_input_event repeat_event; + bool repeating; struct ev_timer *repeat_timer; }; diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c index 77d3085..72bb652 100644 --- a/src/uterm_input_uxkb.c +++ b/src/uterm_input_uxkb.c @@ -136,37 +136,13 @@ enum { KEY_REPEATED = 2, }; -int uxkb_dev_process(struct uterm_input_dev *dev, - uint16_t key_state, uint16_t code) +static inline int uxkb_dev_resize_event(struct uterm_input_dev *dev, size_t s) { - struct xkb_state *state; - struct xkb_keymap *keymap; - xkb_keycode_t keycode; - 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); - keycode = code + EVDEV_KEYCODE_OFFSET; - - num_keysyms = xkb_key_get_syms(state, keycode, &keysyms); - - if (key_state == KEY_PRESSED) - xkb_state_update_key(state, keycode, XKB_KEY_DOWN); - else if (key_state == KEY_RELEASED) - xkb_state_update_key(state, keycode, XKB_KEY_UP); - if (num_keysyms <= 0) - return -ENOKEY; - - if (dev->num_syms < num_keysyms) { + if (s > dev->num_syms) { tmp = realloc(dev->event.keysyms, - sizeof(uint32_t) * num_keysyms); + sizeof(uint32_t) * s); if (!tmp) { log_warning("cannot reallocate keysym buffer"); return -ENOKEY; @@ -174,7 +150,7 @@ int uxkb_dev_process(struct uterm_input_dev *dev, dev->event.keysyms = tmp; tmp = realloc(dev->event.codepoints, - sizeof(uint32_t) * num_keysyms); + sizeof(uint32_t) * s); if (!tmp) { log_warning("cannot reallocate codepoints buffer"); return -ENOKEY; @@ -182,7 +158,7 @@ int uxkb_dev_process(struct uterm_input_dev *dev, dev->event.codepoints = tmp; tmp = realloc(dev->repeat_event.keysyms, - sizeof(uint32_t) * num_keysyms); + sizeof(uint32_t) * s); if (!tmp) { log_warning("cannot reallocate keysym buffer"); return -ENOKEY; @@ -190,55 +166,136 @@ int uxkb_dev_process(struct uterm_input_dev *dev, dev->repeat_event.keysyms = tmp; tmp = realloc(dev->repeat_event.codepoints, - sizeof(uint32_t) * num_keysyms); + sizeof(uint32_t) * s); if (!tmp) { log_warning("cannot reallocate codepoints buffer"); return -ENOKEY; } dev->repeat_event.codepoints = tmp; - dev->num_syms = num_keysyms; + dev->num_syms = s; } - dev->event.handled = false; - dev->event.keycode = code; - dev->event.ascii = shl_get_ascii(state, keycode, keysyms, num_keysyms); - dev->event.mods = shl_get_xkb_mods(state); - dev->event.num_syms = num_keysyms; - memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms); - - for (i = 0; i < num_keysyms; ++i) { - dev->event.codepoints[i] = xkb_keysym_to_utf32(keysyms[i]); - if (!dev->event.codepoints[i]) - dev->event.codepoints[i] = UTERM_INPUT_INVALID; + return 0; +} + +static int uxkb_dev_fill_event(struct uterm_input_dev *dev, + struct uterm_input_event *ev, + xkb_keycode_t code, + int num_syms, + const xkb_keysym_t *syms) +{ + int ret, i; + + ret = uxkb_dev_resize_event(dev, num_syms); + if (ret) + return ret; + + ev->keycode = code; + ev->ascii = shl_get_ascii(dev->state, code, syms, num_syms); + ev->mods = shl_get_xkb_mods(dev->state); + ev->num_syms = num_syms; + memcpy(ev->keysyms, syms, sizeof(uint32_t) * num_syms); + + for (i = 0; i < num_syms; ++i) { + ev->codepoints[i] = xkb_keysym_to_utf32(syms[i]); + if (!ev->codepoints[i]) + ev->codepoints[i] = UTERM_INPUT_INVALID; } - if (key_state == KEY_RELEASED && - dev->repeat_event.keycode == code) { + return 0; +} + +static void uxkb_dev_repeat(struct uterm_input_dev *dev, unsigned int state) +{ + struct xkb_keymap *keymap = xkb_state_get_map(dev->state); + unsigned int i; + int num_keysyms, ret; + const uint32_t *keysyms; + struct itimerspec spec; + + if (state == KEY_RELEASED && + dev->repeat_event.keycode == dev->event.keycode) { + dev->repeating = false; ev_timer_update(dev->repeat_timer, NULL); - } else if (key_state == KEY_PRESSED && - xkb_key_repeats(keymap, keycode)) { - dev->repeat_event.keycode = code; + return; + } + + if (state == KEY_PRESSED && + xkb_key_repeats(keymap, dev->event.keycode)) { + dev->repeat_event.keycode = dev->event.keycode; dev->repeat_event.ascii = dev->event.ascii; dev->repeat_event.mods = dev->event.mods; - dev->repeat_event.num_syms = num_keysyms; + dev->repeat_event.num_syms = dev->event.num_syms; - for (i = 0; i < num_keysyms; ++i) { + for (i = 0; i < dev->event.num_syms; ++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->input->repeat_rate * 1000000; - spec.it_value.tv_sec = 0; - spec.it_value.tv_nsec = dev->input->repeat_delay * 1000000; - ev_timer_update(dev->repeat_timer, &spec); + } else if (dev->repeating && + !xkb_key_repeats(keymap, dev->event.keycode)) { + num_keysyms = xkb_key_get_syms(dev->state, + dev->repeat_event.keycode, + &keysyms); + if (num_keysyms <= 0) + return; + + ret = uxkb_dev_fill_event(dev, &dev->repeat_event, + dev->repeat_event.keycode, + num_keysyms, keysyms); + if (ret) + return; + } else { + return; } + if (dev->repeating) + return; + + dev->repeating = true; + spec.it_interval.tv_sec = 0; + spec.it_interval.tv_nsec = dev->input->repeat_rate * 1000000; + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = dev->input->repeat_delay * 1000000; + ev_timer_update(dev->repeat_timer, &spec); +} + +int uxkb_dev_process(struct uterm_input_dev *dev, + uint16_t key_state, uint16_t code) +{ + struct xkb_state *state; + xkb_keycode_t keycode; + const xkb_keysym_t *keysyms; + int num_keysyms, ret; + + if (key_state == KEY_REPEATED) + return -ENOKEY; + + state = dev->state; + keycode = code + EVDEV_KEYCODE_OFFSET; + + num_keysyms = xkb_key_get_syms(state, keycode, &keysyms); + + if (key_state == KEY_PRESSED) + xkb_state_update_key(state, keycode, XKB_KEY_DOWN); + else if (key_state == KEY_RELEASED) + xkb_state_update_key(state, keycode, XKB_KEY_UP); + + if (num_keysyms <= 0) + return -ENOKEY; + + ret = uxkb_dev_fill_event(dev, &dev->event, keycode, num_keysyms, + keysyms); + if (ret) + return -ENOKEY; + + uxkb_dev_repeat(dev, key_state); + if (key_state == KEY_RELEASED) return -ENOKEY; + dev->event.handled = false; shl_hook_call(dev->input->hook, dev->input, &dev->event); return 0;