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 notify_key(struct uterm_input_dev *dev,
return;
memset(&ev, 0, sizeof(ev));
- ret = kbd_dev_process(dev->kbd, value, code, &ev);
+ ret = uxkb_dev_process(dev, value, code, &ev);
if (ret)
return;
}
/* 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,
dev->rfd, EV_READABLE,
if (!dev->node)
goto err_free;
- ret = kbd_desc_alloc(input->desc, &dev->kbd);
+ ret = uxkb_dev_init(dev);
if (ret)
goto err_node;
return;
err_kbd:
- kbd_dev_unref(dev->kbd);
+ uxkb_dev_destroy(dev);
err_node:
free(dev->node);
err_free:
log_debug("free device %s", dev->node);
input_sleep_dev(dev);
shl_dlist_unlink(&dev->list);
- kbd_dev_unref(dev->kbd);
+ uxkb_dev_destroy(dev);
free(dev->node);
free(dev);
}
if (ret)
goto err_free;
- ret = kbd_desc_new(&input->desc,
- layout,
- variant,
- options,
- KBD_UXKB);
+ ret = uxkb_desc_init(input, layout, variant, options);
if (ret)
goto err_hook;
input_free_dev(dev);
}
- kbd_desc_unref(input->desc);
+ uxkb_desc_destroy(input);
shl_hook_free(input->hook);
ev_eloop_unref(input->eloop);
free(input);
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);
-}
#include <stdlib.h>
#include <xkbcommon/xkbcommon-keysyms.h>
#include "eloop.h"
+#include "shl_dlist.h"
#include "uterm.h"
-struct kbd_desc;
-struct kbd_dev;
+struct uterm_input_dev {
+ struct shl_dlist list;
+ struct uterm_input *input;
-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 (*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 {
+ unsigned int features;
+ int rfd;
+ char *node;
+ struct ev_fd *fd;
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;
-
-extern int uxkb_string_to_keysym(const char *n, uint32_t *out);
-
-struct kbd_desc {
+struct uterm_input {
unsigned long ref;
- const struct kbd_desc_ops *ops;
-
- union {
- struct uxkb_desc uxkb;
- };
-};
+ struct ev_eloop *eloop;
+ int awake;
-struct kbd_dev {
- unsigned long ref;
- struct kbd_desc *desc;
- const struct kbd_dev_ops *ops;
-
- union {
- struct uxkb_dev uxkb;
- };
-};
+ struct shl_hook *hook;
+ struct xkb_context *ctx;
+ struct xkb_keymap *keymap;
-enum kbd_mode {
- KBD_UXKB,
+ struct shl_dlist devices;
};
-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)
{
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 */
#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)
- return;
+ int ret;
+ struct xkb_rule_names rmlvo = {
+ .rules = "evdev",
+ .model = "evdev",
+ .layout = layout,
+ .variant = variant,
+ .options = options,
+ };
+
+ 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;
- ++kbd->ref;
+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)
- return;
+ xkb_map_unref(input->keymap);
+ xkb_context_unref(input->ctx);
+}
+
+int uxkb_dev_init(struct uterm_input_dev *dev)
+{
+ dev->state = xkb_state_new(dev->input->keymap);
+ if (!dev->state)
+ return -ENOMEM;
- xkb_state_unref(kbd->uxkb.state);
- kbd_desc_unref(kbd->desc);
- free(kbd);
+ return 0;
+}
+
+void uxkb_dev_destroy(struct uterm_input_dev *dev)
+{
+ xkb_state_unref(dev->state);
}
#define EVDEV_KEYCODE_OFFSET 8
KEY_REPEATED = 2,
};
-static int uxkb_dev_process(struct kbd_dev *kbd,
- uint16_t key_state,
- uint16_t code,
- struct uterm_input_event *out)
+int uxkb_dev_process(struct uterm_input_dev *dev,
+ uint16_t key_state,
+ uint16_t code,
+ struct uterm_input_event *out)
{
struct xkb_state *state;
struct xkb_keymap *keymap;
const xkb_keysym_t *keysyms;
int num_keysyms;
- if (!kbd)
- return -EINVAL;
-
- state = kbd->uxkb.state;
+ state = dev->state;
keymap = xkb_state_get_map(state);
keycode = code + EVDEV_KEYCODE_OFFSET;
* We don't reset the locked group, this should survive a VT switch, etc. The
* 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;
struct xkb_state *state;
{ LED_SCROLLL, XKB_LED_NAME_SCROLL },
};
- if (!kbd)
- return;
-
/* TODO: Urghs, while the input device was closed we might have missed
* some events that affect internal state. As xkbcommon does not provide
* a way to reset the internal state, we simply recreate the state. This
* 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
* buggy so we should fix it upstream. */
- state = xkb_state_new(kbd->desc->uxkb.keymap);
+ state = xkb_state_new(dev->input->keymap);
if (!state) {
log_warning("cannot recreate xkb-state");
return;
}
- xkb_state_unref(kbd->uxkb.state);
- kbd->uxkb.state = state;
+ xkb_state_unref(dev->state);
+ dev->state = state;
for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
if (!input_bit_is_set(ledbits, led_names[i].led))
*/
}
}
-
-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,
-};