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 <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-10-09 13:12:02 +02:00
parent 998a43455b
commit cbff71f6e2
3 changed files with 99 additions and 17 deletions

View 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);

View 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 {

View 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;
}