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:
parent
998a43455b
commit
cbff71f6e2
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user