uterm: input: use uxkb directly

This changes the uterm-input infrastructure to use XKB directly instead of
using a modularized infrastructure. There is no need to use something else
anymore.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-10-09 10:56:00 +02:00
parent fa566972e5
commit fba4b9104b
3 changed files with 105 additions and 377 deletions

View File

@ -53,28 +53,6 @@ enum device_feature {
FEATURE_HAS_LEDS = 0x02, FEATURE_HAS_LEDS = 0x02,
}; };
struct uterm_input_dev {
struct shl_dlist list;
struct uterm_input *input;
unsigned int features;
int rfd;
char *node;
struct ev_fd *fd;
struct kbd_dev *kbd;
};
struct uterm_input {
unsigned long ref;
struct ev_eloop *eloop;
int awake;
struct shl_hook *hook;
struct kbd_desc *desc;
struct shl_dlist devices;
};
static void input_free_dev(struct uterm_input_dev *dev); static void input_free_dev(struct uterm_input_dev *dev);
static void notify_key(struct uterm_input_dev *dev, static void notify_key(struct uterm_input_dev *dev,
@ -89,7 +67,7 @@ static void notify_key(struct uterm_input_dev *dev,
return; return;
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
ret = kbd_dev_process(dev->kbd, value, code, &ev); ret = uxkb_dev_process(dev, value, code, &ev);
if (ret) if (ret)
return; return;
@ -156,7 +134,7 @@ static int input_wake_up_dev(struct uterm_input_dev *dev)
} }
/* rediscover the keyboard state if sth changed during sleep */ /* rediscover the keyboard state if sth changed during sleep */
kbd_dev_reset(dev->kbd, ledbits); uxkb_dev_reset(dev, ledbits);
ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd, ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd,
dev->rfd, EV_READABLE, dev->rfd, EV_READABLE,
@ -201,7 +179,7 @@ static void input_new_dev(struct uterm_input *input,
if (!dev->node) if (!dev->node)
goto err_free; goto err_free;
ret = kbd_desc_alloc(input->desc, &dev->kbd); ret = uxkb_dev_init(dev);
if (ret) if (ret)
goto err_node; goto err_node;
@ -216,7 +194,7 @@ static void input_new_dev(struct uterm_input *input,
return; return;
err_kbd: err_kbd:
kbd_dev_unref(dev->kbd); uxkb_dev_destroy(dev);
err_node: err_node:
free(dev->node); free(dev->node);
err_free: err_free:
@ -228,7 +206,7 @@ static void input_free_dev(struct uterm_input_dev *dev)
log_debug("free device %s", dev->node); log_debug("free device %s", dev->node);
input_sleep_dev(dev); input_sleep_dev(dev);
shl_dlist_unlink(&dev->list); shl_dlist_unlink(&dev->list);
kbd_dev_unref(dev->kbd); uxkb_dev_destroy(dev);
free(dev->node); free(dev->node);
free(dev); free(dev);
} }
@ -257,11 +235,7 @@ int uterm_input_new(struct uterm_input **out,
if (ret) if (ret)
goto err_free; goto err_free;
ret = kbd_desc_new(&input->desc, ret = uxkb_desc_init(input, layout, variant, options);
layout,
variant,
options,
KBD_UXKB);
if (ret) if (ret)
goto err_hook; goto err_hook;
@ -301,7 +275,7 @@ void uterm_input_unref(struct uterm_input *input)
input_free_dev(dev); input_free_dev(dev);
} }
kbd_desc_unref(input->desc); uxkb_desc_destroy(input);
shl_hook_free(input->hook); shl_hook_free(input->hook);
ev_eloop_unref(input->eloop); ev_eloop_unref(input->eloop);
free(input); free(input);
@ -467,28 +441,3 @@ bool uterm_input_is_awake(struct uterm_input *input)
return input->awake > 0; return input->awake > 0;
} }
void uterm_input_keysym_to_string(struct uterm_input *input,
uint32_t keysym, char *str, size_t size)
{
if (!str || !size)
return;
if (!input) {
*str = 0;
return;
}
kbd_desc_keysym_to_string(input->desc, keysym, str, size);
}
int uterm_input_string_to_keysym(struct uterm_input *input, const char *n,
uint32_t *out)
{
if (!n || !out)
return -EINVAL;
if (input)
return kbd_desc_string_to_keysym(input->desc, n, out);
return uxkb_string_to_keysym(n, out);
}

View File

@ -34,172 +34,49 @@
#include <stdlib.h> #include <stdlib.h>
#include <xkbcommon/xkbcommon-keysyms.h> #include <xkbcommon/xkbcommon-keysyms.h>
#include "eloop.h" #include "eloop.h"
#include "shl_dlist.h"
#include "uterm.h" #include "uterm.h"
struct kbd_desc; struct uterm_input_dev {
struct kbd_dev; struct shl_dlist list;
struct uterm_input *input;
struct kbd_desc_ops { unsigned int features;
int (*init) (struct kbd_desc **out, const char *layout, int rfd;
const char *variant, const char *options); char *node;
void (*ref) (struct kbd_desc *desc); struct ev_fd *fd;
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 (*string_to_keysym) (const char *n, uint32_t *out);
};
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);
};
struct uxkb_desc {
struct xkb_context *ctx;
struct xkb_keymap *keymap;
};
struct uxkb_dev {
struct xkb_state *state; struct xkb_state *state;
}; };
static const bool uxkb_available = true; struct uterm_input {
extern const struct kbd_desc_ops uxkb_desc_ops;
extern const struct kbd_dev_ops uxkb_dev_ops;
extern int uxkb_string_to_keysym(const char *n, uint32_t *out);
struct kbd_desc {
unsigned long ref; unsigned long ref;
const struct kbd_desc_ops *ops; struct ev_eloop *eloop;
int awake;
union { struct shl_hook *hook;
struct uxkb_desc uxkb; struct xkb_context *ctx;
}; struct xkb_keymap *keymap;
struct shl_dlist devices;
}; };
struct kbd_dev {
unsigned long ref;
struct kbd_desc *desc;
const struct kbd_dev_ops *ops;
union {
struct uxkb_dev uxkb;
};
};
enum kbd_mode {
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;
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 int kbd_desc_string_to_keysym(struct kbd_desc *desc,
const char *n,
uint32_t *out)
{
if (!desc)
return -EINVAL;
return desc->ops->string_to_keysym(n, out);
}
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);
}
static inline bool input_bit_is_set(const unsigned long *array, int bit) static inline bool input_bit_is_set(const unsigned long *array, int bit)
{ {
return !!(array[bit / LONG_BIT] & (1LL << (bit % LONG_BIT))); return !!(array[bit / LONG_BIT] & (1LL << (bit % LONG_BIT)));
} }
int uxkb_desc_init(struct uterm_input *input,
const char *layout,
const char *variant,
const char *options);
void uxkb_desc_destroy(struct uterm_input *input);
int uxkb_dev_init(struct uterm_input_dev *dev);
void uxkb_dev_destroy(struct uterm_input_dev *dev);
int uxkb_dev_process(struct uterm_input_dev *dev,
uint16_t key_state,
uint16_t code,
struct uterm_input_event *out);
void uxkb_dev_reset(struct uterm_input_dev *dev, const unsigned long *ledbits);
#endif /* UTERM_INPUT_H */ #endif /* UTERM_INPUT_H */

View File

@ -38,22 +38,71 @@
#define LOG_SUBSYSTEM "input_uxkb" #define LOG_SUBSYSTEM "input_uxkb"
static void uxkb_dev_ref(struct kbd_dev *kbd) int uxkb_desc_init(struct uterm_input *input,
const char *layout,
const char *variant,
const char *options)
{ {
if (!kbd || !kbd->ref) int ret;
return; struct xkb_rule_names rmlvo = {
.rules = "evdev",
.model = "evdev",
.layout = layout,
.variant = variant,
.options = options,
};
++kbd->ref; input->ctx = xkb_context_new(0);
if (!input->ctx) {
log_error("cannot create XKB context");
return -ENOMEM;
}
input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
if (!input->keymap) {
log_warn("failed to create keymap (%s, %s, %s), "
"reverting to default US keymap",
layout, variant, options);
rmlvo.layout = "us";
rmlvo.variant = "";
rmlvo.options = "";
input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
if (!input->keymap) {
log_warn("failed to create XKB keymap");
ret = -EFAULT;
goto err_ctx;
}
}
log_debug("new keyboard description (%s, %s, %s)",
layout, variant, options);
return 0;
err_ctx:
xkb_context_unref(input->ctx);
return ret;
} }
static void uxkb_dev_unref(struct kbd_dev *kbd) void uxkb_desc_destroy(struct uterm_input *input)
{ {
if (!kbd || !kbd->ref || --kbd->ref) xkb_map_unref(input->keymap);
return; xkb_context_unref(input->ctx);
}
xkb_state_unref(kbd->uxkb.state); int uxkb_dev_init(struct uterm_input_dev *dev)
kbd_desc_unref(kbd->desc); {
free(kbd); dev->state = xkb_state_new(dev->input->keymap);
if (!dev->state)
return -ENOMEM;
return 0;
}
void uxkb_dev_destroy(struct uterm_input_dev *dev)
{
xkb_state_unref(dev->state);
} }
#define EVDEV_KEYCODE_OFFSET 8 #define EVDEV_KEYCODE_OFFSET 8
@ -63,10 +112,10 @@ enum {
KEY_REPEATED = 2, KEY_REPEATED = 2,
}; };
static int uxkb_dev_process(struct kbd_dev *kbd, int uxkb_dev_process(struct uterm_input_dev *dev,
uint16_t key_state, uint16_t key_state,
uint16_t code, uint16_t code,
struct uterm_input_event *out) struct uterm_input_event *out)
{ {
struct xkb_state *state; struct xkb_state *state;
struct xkb_keymap *keymap; struct xkb_keymap *keymap;
@ -74,10 +123,7 @@ static int uxkb_dev_process(struct kbd_dev *kbd,
const xkb_keysym_t *keysyms; const xkb_keysym_t *keysyms;
int num_keysyms; int num_keysyms;
if (!kbd) state = dev->state;
return -EINVAL;
state = kbd->uxkb.state;
keymap = xkb_state_get_map(state); keymap = xkb_state_get_map(state);
keycode = code + EVDEV_KEYCODE_OFFSET; keycode = code + EVDEV_KEYCODE_OFFSET;
@ -115,7 +161,7 @@ static int uxkb_dev_process(struct kbd_dev *kbd,
* We don't reset the locked group, this should survive a VT switch, etc. The * We don't reset the locked group, this should survive a VT switch, etc. The
* locked modifiers are reset according to the keyboard LEDs. * locked modifiers are reset according to the keyboard LEDs.
*/ */
static void uxkb_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits) void uxkb_dev_reset(struct uterm_input_dev *dev, const unsigned long *ledbits)
{ {
unsigned int i; unsigned int i;
struct xkb_state *state; struct xkb_state *state;
@ -128,9 +174,6 @@ static void uxkb_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
{ LED_SCROLLL, XKB_LED_NAME_SCROLL }, { LED_SCROLLL, XKB_LED_NAME_SCROLL },
}; };
if (!kbd)
return;
/* TODO: Urghs, while the input device was closed we might have missed /* TODO: Urghs, while the input device was closed we might have missed
* some events that affect internal state. As xkbcommon does not provide * some events that affect internal state. As xkbcommon does not provide
* a way to reset the internal state, we simply recreate the state. This * a way to reset the internal state, we simply recreate the state. This
@ -138,13 +181,13 @@ static void uxkb_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
* It also has a bug that if the CTRL-Release event is skipped, then * It also has a bug that if the CTRL-Release event is skipped, then
* every further release will never perform a _real_ release. Kind of * every further release will never perform a _real_ release. Kind of
* buggy so we should fix it upstream. */ * buggy so we should fix it upstream. */
state = xkb_state_new(kbd->desc->uxkb.keymap); state = xkb_state_new(dev->input->keymap);
if (!state) { if (!state) {
log_warning("cannot recreate xkb-state"); log_warning("cannot recreate xkb-state");
return; return;
} }
xkb_state_unref(kbd->uxkb.state); xkb_state_unref(dev->state);
kbd->uxkb.state = state; dev->state = state;
for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) { for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
if (!input_bit_is_set(ledbits, led_names[i].led)) if (!input_bit_is_set(ledbits, led_names[i].led))
@ -158,144 +201,3 @@ static void uxkb_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
*/ */
} }
} }
static int uxkb_desc_init(struct kbd_desc **out,
const char *layout,
const char *variant,
const char *options)
{
int ret;
struct kbd_desc *desc;
struct xkb_rule_names rmlvo = {
.rules = "evdev",
.model = "evdev",
.layout = layout,
.variant = variant,
.options = options,
};
if (!out)
return -EINVAL;
desc = malloc(sizeof(*desc));
if (!desc)
return -ENOMEM;
memset(desc, 0, sizeof(*desc));
desc->ref = 1;
desc->ops = &uxkb_desc_ops;
desc->uxkb.ctx = xkb_context_new(0);
if (!desc->uxkb.ctx) {
ret = -ENOMEM;
goto err_desc;
}
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);
rmlvo.layout = "us";
rmlvo.variant = "";
rmlvo.options = "";
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;
}
}
log_debug("new keyboard description (%s, %s, %s)",
layout, variant, options);
*out = desc;
return 0;
err_ctx:
xkb_context_unref(desc->uxkb.ctx);
err_desc:
free(desc);
return ret;
}
static void uxkb_desc_ref(struct kbd_desc *desc)
{
if (!desc || !desc->ref)
return;
++desc->ref;
}
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->uxkb.keymap);
xkb_context_unref(desc->uxkb.ctx);
free(desc);
}
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);
}
int uxkb_string_to_keysym(const char *n, uint32_t *out)
{
uint32_t keysym;
/* TODO: fix xkbcommon upstream to be case-insensitive if case-sensitive
* match fails. */
keysym = xkb_keysym_from_name(n);
if (!keysym)
return -EFAULT;
*out = keysym;
return 0;
}
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,
.string_to_keysym = uxkb_string_to_keysym,
};
const struct kbd_dev_ops uxkb_dev_ops = {
.ref = uxkb_dev_ref,
.unref = uxkb_dev_unref,
.reset = uxkb_dev_reset,
.process = uxkb_dev_process,
};