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:
David Herrmann 2012-07-21 19:06:50 +02:00
parent a0217124e5
commit 741b8d33df
7 changed files with 351 additions and 153 deletions

View File

@ -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 += \

View File

@ -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=""

View File

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

View File

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

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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 */