Refactor input backend-system
This is a rewrite of the input system. The backends itself are not modified. However, it is now possible to have multiple backends and change them on runtime. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
a0217124e5
commit
741b8d33df
10
Makefile.am
10
Makefile.am
@ -152,6 +152,9 @@ libuterm_la_SOURCES = \
|
||||
src/uterm_video.c \
|
||||
src/uterm_monitor.c \
|
||||
src/uterm_input.c \
|
||||
src/uterm_input_plain.c \
|
||||
external/imKStoUCS.h \
|
||||
external/imKStoUCS.c \
|
||||
src/uterm_vt.c \
|
||||
src/vt.h \
|
||||
src/vt.c
|
||||
@ -195,12 +198,7 @@ endif
|
||||
|
||||
if UTERM_HAVE_XKBCOMMON
|
||||
libuterm_la_SOURCES += \
|
||||
src/uterm_input_xkb.c
|
||||
else
|
||||
libuterm_la_SOURCES += \
|
||||
src/uterm_input_dumb.c \
|
||||
external/imKStoUCS.h \
|
||||
external/imKStoUCS.c
|
||||
src/uterm_input_uxkb.c
|
||||
endif
|
||||
|
||||
include_HEADERS += \
|
||||
|
@ -336,7 +336,8 @@ if test ! x$enable_xkbcommon = xno ; then
|
||||
fi
|
||||
|
||||
if test x$xkbcommon_enabled = xyes ; then
|
||||
test # dummy
|
||||
AC_DEFINE([UTERM_HAVE_XKBCOMMON], [1],
|
||||
[Use xkbcommon as input keyboard handling backend])
|
||||
else
|
||||
XKBCOMMON_CFLAGS=""
|
||||
XKBCOMMON_LIBS=""
|
||||
|
@ -182,8 +182,10 @@ static void seat_add_video(struct kmscon_seat *seat,
|
||||
|
||||
ret = kmscon_ui_new(&seat->ui, seat->app->eloop, seat->video,
|
||||
seat->input);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
log_error("cannot create UI object");
|
||||
goto err_video;
|
||||
}
|
||||
|
||||
seat->vdev = dev;
|
||||
log_debug("new graphics device on seat %s", seat->sname);
|
||||
|
@ -88,7 +88,7 @@ static void notify_key(struct uterm_input_dev *dev,
|
||||
if (type != EV_KEY)
|
||||
return;
|
||||
|
||||
ret = kbd_dev_process_key(dev->kbd, value, code, &ev);
|
||||
ret = kbd_dev_process(dev->kbd, value, code, &ev);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@ -200,7 +200,7 @@ static void input_new_dev(struct uterm_input *input,
|
||||
if (!dev->node)
|
||||
goto err_free;
|
||||
|
||||
ret = kbd_dev_new(&dev->kbd, input->desc);
|
||||
ret = kbd_desc_alloc(input->desc, &dev->kbd);
|
||||
if (ret)
|
||||
goto err_node;
|
||||
|
||||
@ -254,11 +254,22 @@ int uterm_input_new(struct uterm_input **out,
|
||||
goto err_free;
|
||||
|
||||
ret = kbd_desc_new(&input->desc,
|
||||
conf_global.xkb_layout,
|
||||
conf_global.xkb_variant,
|
||||
conf_global.xkb_options);
|
||||
if (ret)
|
||||
conf_global.xkb_layout,
|
||||
conf_global.xkb_variant,
|
||||
conf_global.xkb_options,
|
||||
KBD_UXKB);
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
log_info("XKB keyboard backend not available, trying plain backend");
|
||||
ret = kbd_desc_new(&input->desc,
|
||||
conf_global.xkb_layout,
|
||||
conf_global.xkb_variant,
|
||||
conf_global.xkb_options,
|
||||
KBD_PLAIN);
|
||||
if (ret)
|
||||
goto err_hook;
|
||||
} else if (ret) {
|
||||
goto err_hook;
|
||||
}
|
||||
|
||||
log_debug("new object %p", input);
|
||||
ev_eloop_ref(input->eloop);
|
||||
|
@ -47,12 +47,7 @@
|
||||
#include "uterm.h"
|
||||
#include "uterm_internal.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "input_dumb"
|
||||
|
||||
struct kbd_dev {
|
||||
unsigned long ref;
|
||||
unsigned int mods;
|
||||
};
|
||||
#define LOG_SUBSYSTEM "input_plain"
|
||||
|
||||
/*
|
||||
* These tables do not contain all possible keys from linux/input.h.
|
||||
@ -284,21 +279,7 @@ static const struct {
|
||||
[KEY_RIGHTMETA] = { UTERM_MOD4_MASK, MOD_NORMAL },
|
||||
};
|
||||
|
||||
int kbd_dev_new(struct kbd_dev **out, struct kbd_desc *desc)
|
||||
{
|
||||
struct kbd_dev *kbd;
|
||||
|
||||
kbd = malloc(sizeof(*kbd));
|
||||
if (!kbd)
|
||||
return -ENOMEM;
|
||||
memset(kbd, 0, sizeof(*kbd));
|
||||
kbd->ref = 1;
|
||||
|
||||
*out = kbd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbd_dev_ref(struct kbd_dev *kbd)
|
||||
static void plain_dev_ref(struct kbd_dev *kbd)
|
||||
{
|
||||
if (!kbd || !kbd->ref)
|
||||
return;
|
||||
@ -306,7 +287,7 @@ void kbd_dev_ref(struct kbd_dev *kbd)
|
||||
++kbd->ref;
|
||||
}
|
||||
|
||||
void kbd_dev_unref(struct kbd_dev *kbd)
|
||||
static void plain_dev_unref(struct kbd_dev *kbd)
|
||||
{
|
||||
if (!kbd || !kbd->ref || --kbd->ref)
|
||||
return;
|
||||
@ -314,23 +295,23 @@ void kbd_dev_unref(struct kbd_dev *kbd)
|
||||
free(kbd);
|
||||
}
|
||||
|
||||
void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
|
||||
static void plain_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
|
||||
{
|
||||
if (!kbd)
|
||||
return;
|
||||
|
||||
kbd->mods = 0;
|
||||
kbd->plain.mods = 0;
|
||||
|
||||
if (input_bit_is_set(ledbits, LED_NUML))
|
||||
kbd->mods |= UTERM_MOD2_MASK;
|
||||
kbd->plain.mods |= UTERM_MOD2_MASK;
|
||||
if (input_bit_is_set(ledbits, LED_CAPSL))
|
||||
kbd->mods |= UTERM_LOCK_MASK;
|
||||
kbd->plain.mods |= UTERM_LOCK_MASK;
|
||||
}
|
||||
|
||||
int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
uint16_t key_state,
|
||||
uint16_t code,
|
||||
struct uterm_input_event *out)
|
||||
static int plain_dev_process(struct kbd_dev *kbd,
|
||||
uint16_t key_state,
|
||||
uint16_t code,
|
||||
struct uterm_input_event *out)
|
||||
{
|
||||
uint32_t keysym;
|
||||
unsigned int mod;
|
||||
@ -353,12 +334,12 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
*/
|
||||
if (key_state == 1) {
|
||||
if (mod_type == MOD_NORMAL)
|
||||
kbd->mods |= mod;
|
||||
kbd->plain.mods |= mod;
|
||||
else if (mod_type == MOD_LOCK)
|
||||
kbd->mods ^= mod;
|
||||
kbd->plain.mods ^= mod;
|
||||
} else if (key_state == 0) {
|
||||
if (mod_type == MOD_NORMAL)
|
||||
kbd->mods &= ~mod;
|
||||
kbd->plain.mods &= ~mod;
|
||||
}
|
||||
|
||||
/* Don't deliver events purely for modifiers. */
|
||||
@ -370,11 +351,11 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
|
||||
keysym = 0;
|
||||
|
||||
if (!keysym && kbd->mods & UTERM_MOD2_MASK)
|
||||
if (!keysym && kbd->plain.mods & UTERM_MOD2_MASK)
|
||||
keysym = keytab_numlock[code];
|
||||
if (!keysym && kbd->mods & UTERM_SHIFT_MASK)
|
||||
if (!keysym && kbd->plain.mods & UTERM_SHIFT_MASK)
|
||||
keysym = keytab_shift[code];
|
||||
if (!keysym && kbd->mods & UTERM_LOCK_MASK)
|
||||
if (!keysym && kbd->plain.mods & UTERM_LOCK_MASK)
|
||||
keysym = keytab_capslock[code];
|
||||
if (!keysym)
|
||||
keysym = keytab_normal[code];
|
||||
@ -385,34 +366,81 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
out->keycode = code;
|
||||
out->keysym = keysym;
|
||||
out->unicode = KeysymToUcs4(keysym) ?: UTERM_INPUT_INVALID;
|
||||
out->mods = kbd->mods;
|
||||
out->mods = kbd->plain.mods;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kbd_desc_new(struct kbd_desc **out,
|
||||
const char *layout,
|
||||
const char *variant,
|
||||
const char *options)
|
||||
static int plain_desc_init(struct kbd_desc **out,
|
||||
const char *layout,
|
||||
const char *variant,
|
||||
const char *options)
|
||||
{
|
||||
struct kbd_desc *desc;
|
||||
|
||||
if (!out)
|
||||
return -EINVAL;
|
||||
|
||||
desc = malloc(sizeof(*desc));
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
desc->ops = &plain_desc_ops;
|
||||
|
||||
log_debug("new keyboard description (%s, %s, %s)",
|
||||
layout, variant, options);
|
||||
*out = NULL;
|
||||
layout, variant, options);
|
||||
*out = desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbd_desc_ref(struct kbd_desc *desc)
|
||||
static void plain_desc_ref(struct kbd_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->ref)
|
||||
return;
|
||||
|
||||
++desc->ref;
|
||||
}
|
||||
|
||||
void kbd_desc_unref(struct kbd_desc *desc)
|
||||
static void plain_desc_unref(struct kbd_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->ref || --desc->ref)
|
||||
return;
|
||||
|
||||
log_debug("destroying keyboard description");
|
||||
free(desc);
|
||||
}
|
||||
|
||||
void kbd_keysym_to_string(uint32_t keysym, char *str, size_t size)
|
||||
static int plain_desc_alloc(struct kbd_desc *desc, struct kbd_dev **out)
|
||||
{
|
||||
struct kbd_dev *kbd;
|
||||
|
||||
kbd = malloc(sizeof(*kbd));
|
||||
if (!kbd)
|
||||
return -ENOMEM;
|
||||
memset(kbd, 0, sizeof(*kbd));
|
||||
kbd->ref = 1;
|
||||
kbd->ops = &plain_dev_ops;
|
||||
|
||||
*out = kbd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void plain_keysym_to_string(uint32_t keysym, char *str, size_t size)
|
||||
{
|
||||
snprintf(str, size, "%#x", keysym);
|
||||
}
|
||||
|
||||
const struct kbd_desc_ops plain_desc_ops = {
|
||||
.init = plain_desc_init,
|
||||
.ref = plain_desc_ref,
|
||||
.unref = plain_desc_unref,
|
||||
.alloc = plain_desc_alloc,
|
||||
.keysym_to_string = plain_keysym_to_string,
|
||||
};
|
||||
|
||||
const struct kbd_dev_ops plain_dev_ops = {
|
||||
.ref = plain_dev_ref,
|
||||
.unref = plain_dev_unref,
|
||||
.reset = plain_dev_reset,
|
||||
.process = plain_dev_process,
|
||||
};
|
@ -35,44 +35,9 @@
|
||||
#include "uterm.h"
|
||||
#include "uterm_internal.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "input_xkb"
|
||||
#define LOG_SUBSYSTEM "input_uxkb"
|
||||
|
||||
struct kbd_desc {
|
||||
unsigned long ref;
|
||||
struct xkb_context *ctx;
|
||||
struct xkb_keymap *keymap;
|
||||
};
|
||||
|
||||
struct kbd_dev {
|
||||
unsigned long ref;
|
||||
struct kbd_desc *desc;
|
||||
struct xkb_state *state;
|
||||
};
|
||||
|
||||
int kbd_dev_new(struct kbd_dev **out, struct kbd_desc *desc)
|
||||
{
|
||||
struct kbd_dev *kbd;
|
||||
|
||||
kbd = malloc(sizeof(*kbd));
|
||||
if (!kbd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(kbd, 0, sizeof(*kbd));
|
||||
kbd->ref = 1;
|
||||
kbd->desc = desc;
|
||||
|
||||
kbd->state = xkb_state_new(desc->keymap);
|
||||
if (!kbd->state) {
|
||||
free(kbd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kbd_desc_ref(desc);
|
||||
*out = kbd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbd_dev_ref(struct kbd_dev *kbd)
|
||||
static void uxkb_dev_ref(struct kbd_dev *kbd)
|
||||
{
|
||||
if (!kbd || !kbd->ref)
|
||||
return;
|
||||
@ -80,12 +45,12 @@ void kbd_dev_ref(struct kbd_dev *kbd)
|
||||
++kbd->ref;
|
||||
}
|
||||
|
||||
void kbd_dev_unref(struct kbd_dev *kbd)
|
||||
static void uxkb_dev_unref(struct kbd_dev *kbd)
|
||||
{
|
||||
if (!kbd || !kbd->ref || --kbd->ref)
|
||||
return;
|
||||
|
||||
xkb_state_unref(kbd->state);
|
||||
xkb_state_unref(kbd->uxkb.state);
|
||||
kbd_desc_unref(kbd->desc);
|
||||
free(kbd);
|
||||
}
|
||||
@ -120,10 +85,10 @@ static unsigned int get_effective_modmask(struct xkb_state *state)
|
||||
return mods;
|
||||
}
|
||||
|
||||
int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
uint16_t key_state,
|
||||
uint16_t code,
|
||||
struct uterm_input_event *out)
|
||||
static int uxkb_dev_process(struct kbd_dev *kbd,
|
||||
uint16_t key_state,
|
||||
uint16_t code,
|
||||
struct uterm_input_event *out)
|
||||
{
|
||||
struct xkb_state *state;
|
||||
struct xkb_keymap *keymap;
|
||||
@ -134,7 +99,7 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
if (!kbd)
|
||||
return -EINVAL;
|
||||
|
||||
state = kbd->state;
|
||||
state = kbd->uxkb.state;
|
||||
keymap = xkb_state_get_map(state);
|
||||
keycode = code + EVDEV_KEYCODE_OFFSET;
|
||||
|
||||
@ -161,8 +126,8 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
*/
|
||||
out->keycode = code;
|
||||
out->keysym = keysyms[0];
|
||||
out->mods = get_effective_modmask(state);;
|
||||
out->unicode = xkb_keysym_to_utf32(out->keysym) ?: UTERM_INPUT_INVALID;
|
||||
out->mods = get_effective_modmask(state);
|
||||
out->unicode = xkb_keysym_to_utf32(out->keysym) ? : UTERM_INPUT_INVALID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -172,7 +137,7 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
* We don't reset the locked group, this should survive a VT switch, etc. The
|
||||
* locked modifiers are reset according to the keyboard LEDs.
|
||||
*/
|
||||
void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
|
||||
static void uxkb_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
|
||||
{
|
||||
unsigned int i;
|
||||
struct xkb_state *state;
|
||||
@ -188,7 +153,7 @@ void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
|
||||
if (!kbd)
|
||||
return;
|
||||
|
||||
state = kbd->state;
|
||||
state = kbd->uxkb.state;
|
||||
|
||||
for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
|
||||
if (!input_bit_is_set(ledbits, led_names[i].led))
|
||||
@ -205,10 +170,10 @@ void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
|
||||
(void)state;
|
||||
}
|
||||
|
||||
int kbd_desc_new(struct kbd_desc **out,
|
||||
const char *layout,
|
||||
const char *variant,
|
||||
const char *options)
|
||||
static int uxkb_desc_init(struct kbd_desc **out,
|
||||
const char *layout,
|
||||
const char *variant,
|
||||
const char *options)
|
||||
{
|
||||
int ret;
|
||||
struct kbd_desc *desc;
|
||||
@ -229,15 +194,16 @@ int kbd_desc_new(struct kbd_desc **out,
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
desc->ref = 1;
|
||||
desc->ops = &uxkb_desc_ops;
|
||||
|
||||
desc->ctx = xkb_context_new(0);
|
||||
if (!desc->ctx) {
|
||||
desc->uxkb.ctx = xkb_context_new(0);
|
||||
if (!desc->uxkb.ctx) {
|
||||
ret = -ENOMEM;
|
||||
goto err_desc;
|
||||
}
|
||||
|
||||
desc->keymap = xkb_map_new_from_names(desc->ctx, &rmlvo, 0);
|
||||
if (!desc->keymap) {
|
||||
desc->uxkb.keymap = xkb_map_new_from_names(desc->uxkb.ctx, &rmlvo, 0);
|
||||
if (!desc->uxkb.keymap) {
|
||||
log_warn("failed to create keymap (%s, %s, %s), "
|
||||
"reverting to default US keymap",
|
||||
layout, variant, options);
|
||||
@ -246,8 +212,9 @@ int kbd_desc_new(struct kbd_desc **out,
|
||||
rmlvo.variant = "";
|
||||
rmlvo.options = "";
|
||||
|
||||
desc->keymap = xkb_map_new_from_names(desc->ctx, &rmlvo, 0);
|
||||
if (!desc->keymap) {
|
||||
desc->uxkb.keymap = xkb_map_new_from_names(desc->uxkb.ctx,
|
||||
&rmlvo, 0);
|
||||
if (!desc->uxkb.keymap) {
|
||||
log_warn("failed to create keymap");
|
||||
ret = -EFAULT;
|
||||
goto err_ctx;
|
||||
@ -260,13 +227,13 @@ int kbd_desc_new(struct kbd_desc **out,
|
||||
return 0;
|
||||
|
||||
err_ctx:
|
||||
xkb_context_unref(desc->ctx);
|
||||
xkb_context_unref(desc->uxkb.ctx);
|
||||
err_desc:
|
||||
free(desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kbd_desc_ref(struct kbd_desc *desc)
|
||||
static void uxkb_desc_ref(struct kbd_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->ref)
|
||||
return;
|
||||
@ -274,18 +241,57 @@ void kbd_desc_ref(struct kbd_desc *desc)
|
||||
++desc->ref;
|
||||
}
|
||||
|
||||
void kbd_desc_unref(struct kbd_desc *desc)
|
||||
static void uxkb_desc_unref(struct kbd_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->ref || --desc->ref)
|
||||
return;
|
||||
|
||||
log_debug("destroying keyboard description");
|
||||
xkb_map_unref(desc->keymap);
|
||||
xkb_context_unref(desc->ctx);
|
||||
xkb_map_unref(desc->uxkb.keymap);
|
||||
xkb_context_unref(desc->uxkb.ctx);
|
||||
free(desc);
|
||||
}
|
||||
|
||||
void kbd_keysym_to_string(uint32_t keysym, char *str, size_t size)
|
||||
static int uxkb_desc_alloc(struct kbd_desc *desc, struct kbd_dev **out)
|
||||
{
|
||||
struct kbd_dev *kbd;
|
||||
|
||||
kbd = malloc(sizeof(*kbd));
|
||||
if (!kbd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(kbd, 0, sizeof(*kbd));
|
||||
kbd->ref = 1;
|
||||
kbd->desc = desc;
|
||||
kbd->ops = &uxkb_dev_ops;
|
||||
|
||||
kbd->uxkb.state = xkb_state_new(desc->uxkb.keymap);
|
||||
if (!kbd->uxkb.state) {
|
||||
free(kbd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kbd_desc_ref(desc);
|
||||
*out = kbd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uxkb_keysym_to_string(uint32_t keysym, char *str, size_t size)
|
||||
{
|
||||
xkb_keysym_get_name(keysym, str, size);
|
||||
}
|
||||
|
||||
const struct kbd_desc_ops uxkb_desc_ops = {
|
||||
.init = uxkb_desc_init,
|
||||
.ref = uxkb_desc_ref,
|
||||
.unref = uxkb_desc_unref,
|
||||
.alloc = uxkb_desc_alloc,
|
||||
.keysym_to_string = uxkb_keysym_to_string,
|
||||
};
|
||||
|
||||
const struct kbd_dev_ops uxkb_dev_ops = {
|
||||
.ref = uxkb_dev_ref,
|
||||
.unref = uxkb_dev_unref,
|
||||
.reset = uxkb_dev_reset,
|
||||
.process = uxkb_dev_process,
|
||||
};
|
@ -372,37 +372,189 @@ static inline bool input_bit_is_set(const unsigned long *array, int bit)
|
||||
struct kbd_desc;
|
||||
struct kbd_dev;
|
||||
|
||||
int kbd_desc_new(struct kbd_desc **out,
|
||||
const char *layout,
|
||||
const char *variant,
|
||||
const char *options);
|
||||
void kbd_desc_ref(struct kbd_desc *desc);
|
||||
void kbd_desc_unref(struct kbd_desc *desc);
|
||||
struct kbd_desc_ops {
|
||||
int (*init) (struct kbd_desc **out, const char *layout,
|
||||
const char *variant, const char *options);
|
||||
void (*ref) (struct kbd_desc *desc);
|
||||
void (*unref) (struct kbd_desc *desc);
|
||||
int (*alloc) (struct kbd_desc *desc, struct kbd_dev **out);
|
||||
void (*keysym_to_string) (uint32_t keysym, char *str, size_t size);
|
||||
};
|
||||
|
||||
int kbd_dev_new(struct kbd_dev **out, struct kbd_desc *desc);
|
||||
void kbd_dev_ref(struct kbd_dev *state);
|
||||
void kbd_dev_unref(struct kbd_dev *state);
|
||||
|
||||
/*
|
||||
* This resets the keyboard state in case it got out of sync. It's mainly used
|
||||
* to sync our notion of the keyboard state with what the keyboard LEDs show.
|
||||
*/
|
||||
void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits);
|
||||
|
||||
/*
|
||||
* This is the entry point to the keyboard processing.
|
||||
* We get an evdev scancode and the keyboard state, and should put out a
|
||||
* proper input event.
|
||||
* Some evdev input events shouldn't result in us sending an input event
|
||||
* (e.g. a key release):
|
||||
* - If the event was filled out, 0 is returned.
|
||||
* - Otherwise, if there was no error, -ENOKEY is returned.
|
||||
*/
|
||||
int kbd_dev_process_key(struct kbd_dev *kbd,
|
||||
uint16_t key_state,
|
||||
uint16_t code,
|
||||
struct kbd_dev_ops {
|
||||
void (*ref) (struct kbd_dev *dev);
|
||||
void (*unref) (struct kbd_dev *dev);
|
||||
void (*reset) (struct kbd_dev *dev, const unsigned long *ledbits);
|
||||
int (*process) (struct kbd_dev *dev, uint16_t state, uint16_t code,
|
||||
struct uterm_input_event *out);
|
||||
};
|
||||
|
||||
void kbd_dev_keysym_to_string(uint32_t keysym, char *str, size_t size);
|
||||
struct plain_desc {
|
||||
int unused;
|
||||
};
|
||||
|
||||
struct plain_dev {
|
||||
unsigned int mods;
|
||||
};
|
||||
|
||||
static const bool plain_available = true;
|
||||
extern const struct kbd_desc_ops plain_desc_ops;
|
||||
extern const struct kbd_dev_ops plain_dev_ops;
|
||||
|
||||
#ifdef UTERM_HAVE_XKBCOMMON
|
||||
|
||||
struct uxkb_desc {
|
||||
struct xkb_context *ctx;
|
||||
struct xkb_keymap *keymap;
|
||||
};
|
||||
|
||||
struct uxkb_dev {
|
||||
struct xkb_state *state;
|
||||
};
|
||||
|
||||
static const bool uxkb_available = true;
|
||||
extern const struct kbd_desc_ops uxkb_desc_ops;
|
||||
extern const struct kbd_dev_ops uxkb_dev_ops;
|
||||
|
||||
#else /* !UTERM_HAVE_XKBCOMMON */
|
||||
|
||||
struct uxkb_desc {
|
||||
int unused;
|
||||
};
|
||||
|
||||
struct uxkb_dev {
|
||||
int unused;
|
||||
};
|
||||
|
||||
static const bool xkb_available = false;
|
||||
static const struct kbd_desc_ops uxkb_desc_ops;
|
||||
static const struct kbd_dev_ops uxkb_dev_ops;
|
||||
|
||||
#endif /* UTERM_HAVE_XKBCOMMON */
|
||||
|
||||
struct kbd_desc {
|
||||
unsigned long ref;
|
||||
const struct kbd_desc_ops *ops;
|
||||
|
||||
union {
|
||||
struct plain_desc plain;
|
||||
struct uxkb_desc uxkb;
|
||||
};
|
||||
};
|
||||
|
||||
struct kbd_dev {
|
||||
unsigned long ref;
|
||||
struct kbd_desc *desc;
|
||||
const struct kbd_dev_ops *ops;
|
||||
|
||||
union {
|
||||
struct plain_dev plain;
|
||||
struct uxkb_dev uxkb;
|
||||
};
|
||||
};
|
||||
|
||||
enum kbd_mode {
|
||||
KBD_PLAIN,
|
||||
KBD_UXKB,
|
||||
};
|
||||
|
||||
static inline int kbd_desc_new(struct kbd_desc **out, const char *layout,
|
||||
const char *variant, const char *options,
|
||||
unsigned int mode)
|
||||
{
|
||||
const struct kbd_desc_ops *ops;
|
||||
|
||||
switch (mode) {
|
||||
case KBD_UXKB:
|
||||
if (!uxkb_available) {
|
||||
log_error("XKB KBD backend not available");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
ops = &uxkb_desc_ops;
|
||||
break;
|
||||
case KBD_PLAIN:
|
||||
if (!plain_available) {
|
||||
log_error("plain KBD backend not available");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
ops = &plain_desc_ops;
|
||||
break;
|
||||
default:
|
||||
log_error("unknown KBD backend %u", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ops->init(out, layout, variant, options);
|
||||
}
|
||||
|
||||
static inline void kbd_desc_ref(struct kbd_desc *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
return desc->ops->ref(desc);
|
||||
}
|
||||
|
||||
static inline void kbd_desc_unref(struct kbd_desc *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
return desc->ops->unref(desc);
|
||||
}
|
||||
|
||||
static inline int kbd_desc_alloc(struct kbd_desc *desc, struct kbd_dev **out)
|
||||
{
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
return desc->ops->alloc(desc, out);
|
||||
}
|
||||
|
||||
static inline void kbd_desc_keysym_to_string(struct kbd_desc *desc,
|
||||
uint32_t keysym,
|
||||
char *str, size_t size)
|
||||
{
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
return desc->ops->keysym_to_string(keysym, str, size);
|
||||
}
|
||||
|
||||
static inline void kbd_dev_ref(struct kbd_dev *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
return dev->ops->ref(dev);
|
||||
}
|
||||
|
||||
static inline void kbd_dev_unref(struct kbd_dev *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
return dev->ops->unref(dev);
|
||||
}
|
||||
|
||||
static inline void kbd_dev_reset(struct kbd_dev *dev,
|
||||
const unsigned long *ledbits)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
return dev->ops->reset(dev, ledbits);
|
||||
}
|
||||
|
||||
static inline int kbd_dev_process(struct kbd_dev *dev,
|
||||
uint16_t key_state,
|
||||
uint16_t code,
|
||||
struct uterm_input_event *out)
|
||||
{
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
return dev->ops->process(dev, key_state, code, out);
|
||||
}
|
||||
|
||||
#endif /* UTERM_INTERNAL_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user