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
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 += \
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=""
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);
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;
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;
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);
#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.
[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;
++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;
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;
*/
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. */
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];
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,
+};
#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;
++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);
}
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;
if (!kbd)
return -EINVAL;
- state = kbd->state;
+ state = kbd->uxkb.state;
keymap = xkb_state_get_map(state);
keycode = code + EVDEV_KEYCODE_OFFSET;
*/
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;
}
* 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;
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))
(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;
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);
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;
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;
++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,
+};
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);
+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);
+};
-/*
- * 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);
+struct plain_desc {
+ int unused;
+};
-/*
- * 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 uterm_input_event *out);
+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 */
-void kbd_dev_keysym_to_string(uint32_t keysym, char *str, size_t size);
+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 */