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:
parent
fa566972e5
commit
fba4b9104b
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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,
|
|
||||||
};
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user