Zbigniew Jędrzejewski-Szmek 62fe94
From e06cc7b07465369fb7c01c9778b84cf82c82fdcf Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Wed, 27 Aug 2014 18:34:55 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] terminal: add xkb-based keyboard devices to idev
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
The idev-keyboard object provides keyboard devices to the idev interface.
Zbigniew Jędrzejewski-Szmek 62fe94
It uses libxkbcommon to provide proper keymap support.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
So far, the keyboard implementation is pretty straightforward with one
Zbigniew Jędrzejewski-Szmek 62fe94
keyboard device per matching evdev element. We feed everything into the
Zbigniew Jędrzejewski-Szmek 62fe94
system keymap and provide proper high-level keyboard events to the
Zbigniew Jędrzejewski-Szmek 62fe94
application. Compose-features and IM need to be added later.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 Makefile.am                             |   1 +
Zbigniew Jędrzejewski-Szmek 62fe94
 configure.ac                            |   2 +-
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev-internal.h |   9 +
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev-keyboard.c | 846 ++++++++++++++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev.c          |  62 ++-
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/idev.h          |  49 ++
Zbigniew Jędrzejewski-Szmek 62fe94
 6 files changed, 966 insertions(+), 3 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
 create mode 100644 src/libsystemd-terminal/idev-keyboard.c
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/Makefile.am b/Makefile.am
Zbigniew Jędrzejewski-Szmek 62fe94
index b51c522443..35a4c44a9f 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/Makefile.am
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/Makefile.am
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2976,6 +2976,7 @@ libsystemd_terminal_la_SOURCES = \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/idev-internal.h \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/idev.c \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/idev-evdev.c \
Zbigniew Jędrzejewski-Szmek 62fe94
+	src/libsystemd-terminal/idev-keyboard.c \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/sysview.h \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/sysview-internal.h \
Zbigniew Jędrzejewski-Szmek 62fe94
 	src/libsystemd-terminal/sysview.c \
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/configure.ac b/configure.ac
Zbigniew Jędrzejewski-Szmek 62fe94
index 3900c4065b..a25ad3f2e2 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/configure.ac
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/configure.ac
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1066,7 +1066,7 @@ AM_CONDITIONAL(ENABLE_MULTI_SEAT_X, [test "$have_multi_seat_x" = "yes"])
Zbigniew Jędrzejewski-Szmek 62fe94
 have_terminal=no
Zbigniew Jędrzejewski-Szmek 62fe94
 AC_ARG_ENABLE(terminal, AS_HELP_STRING([--enable-terminal], [enable terminal support]))
Zbigniew Jędrzejewski-Szmek 62fe94
 if test "x$enable_terminal" = "xyes"; then
Zbigniew Jędrzejewski-Szmek 62fe94
-        PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 ], [have_terminal=yes])
Zbigniew Jędrzejewski-Szmek 62fe94
+        PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 xkbcommon >= 0.4 ], [have_terminal=yes])
Zbigniew Jędrzejewski-Szmek 62fe94
         AS_IF([test "x$have_terminal" != xyes -a "x$enable_terminal" = xyes],
Zbigniew Jędrzejewski-Szmek 62fe94
               [AC_MSG_ERROR([*** terminal support requested but required dependencies not available])],
Zbigniew Jędrzejewski-Szmek 62fe94
               [test "x$have_terminal" = xyes],
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
index 3301ebf6e4..c416f4fadd 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/idev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -28,6 +28,7 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <xkbcommon/xkbcommon.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "hashmap.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "idev.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "list.h"
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -47,6 +48,14 @@ idev_element *idev_find_evdev(idev_session *s, dev_t devnum);
Zbigniew Jędrzejewski-Szmek 62fe94
 int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 /*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Keyboard Devices
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+bool idev_is_keyboard(idev_device *d);
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_device *idev_find_keyboard(idev_session *s, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_keyboard_new(idev_device **out, idev_session *s, const char *name);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
  * Element Links
Zbigniew Jędrzejewski-Szmek 62fe94
  */
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c
Zbigniew Jędrzejewski-Szmek 62fe94
new file mode 100644
Zbigniew Jędrzejewski-Szmek 62fe94
index 0000000000..647aade932
Zbigniew Jędrzejewski-Szmek 62fe94
--- /dev/null
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev-keyboard.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -0,0 +1,846 @@
Zbigniew Jędrzejewski-Szmek 62fe94
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/***
Zbigniew Jędrzejewski-Szmek 62fe94
+  This file is part of systemd.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is free software; you can redistribute it and/or modify it
Zbigniew Jędrzejewski-Szmek 62fe94
+  under the terms of the GNU Lesser General Public License as published by
Zbigniew Jędrzejewski-Szmek 62fe94
+  the Free Software Foundation; either version 2.1 of the License, or
Zbigniew Jędrzejewski-Szmek 62fe94
+  (at your option) any later version.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  systemd is distributed in the hope that it will be useful, but
Zbigniew Jędrzejewski-Szmek 62fe94
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Zbigniew Jędrzejewski-Szmek 62fe94
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Zbigniew Jędrzejewski-Szmek 62fe94
+  Lesser General Public License for more details.
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+  You should have received a copy of the GNU Lesser General Public License
Zbigniew Jędrzejewski-Szmek 62fe94
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Zbigniew Jędrzejewski-Szmek 62fe94
+***/
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <inttypes.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdbool.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <xkbcommon/xkbcommon.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "bus-util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "hashmap.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "idev.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "idev-internal.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "macro.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+#include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct kbdmap kbdmap;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct kbdctx kbdctx;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_keyboard idev_keyboard;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct kbdmap {
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned long ref;
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_keymap *xkb_keymap;
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_mod_index_t modmap[IDEV_KBDMOD_CNT];
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_led_index_t ledmap[IDEV_KBDLED_CNT];
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct kbdctx {
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned long ref;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_context *context;
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_context *xkb_context;
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct kbdmap *kbdmap;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_bus_slot *slot_locale_props_changed;
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_bus_slot *slot_locale_get_all;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *locale_x11_model;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *locale_x11_layout;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *locale_x11_variant;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *locale_x11_options;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *last_x11_model;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *last_x11_layout;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *last_x11_variant;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *last_x11_options;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_keyboard {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device device;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdctx *kbdctx;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdmap *kbdmap;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_state *xkb_state;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        usec_t repeat_delay;
Zbigniew Jędrzejewski-Szmek 62fe94
+        usec_t repeat_rate;
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_event_source *repeat_timer;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t n_syms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data evdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data repdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool repeating : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#define keyboard_from_device(_d) container_of((_d), idev_keyboard, device)
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+#define KBDCTX_KEY "keyboard.context"           /* hashmap key for global kbdctx */
Zbigniew Jędrzejewski-Szmek 62fe94
+#define KBDXKB_SHIFT (8)                        /* xkb shifts evdev key-codes by 8 */
Zbigniew Jędrzejewski-Szmek 62fe94
+#define KBDKEY_UP (0)                           /* KEY UP event value */
Zbigniew Jędrzejewski-Szmek 62fe94
+#define KBDKEY_DOWN (1)                         /* KEY DOWN event value */
Zbigniew Jędrzejewski-Szmek 62fe94
+#define KBDKEY_REPEAT (2)                       /* KEY REPEAT event value */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static const idev_device_vtable keyboard_vtable;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_update_kbdmap(idev_keyboard *k);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Keyboard Keymaps
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static const char * const kbdmap_modmap[IDEV_KBDMOD_CNT] = {
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDMOD_IDX_SHIFT]                 = XKB_MOD_NAME_SHIFT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDMOD_IDX_CTRL]                  = XKB_MOD_NAME_CTRL,
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDMOD_IDX_ALT]                   = XKB_MOD_NAME_ALT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDMOD_IDX_LINUX]                 = XKB_MOD_NAME_LOGO,
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDMOD_IDX_CAPS]                  = XKB_MOD_NAME_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static const char * const kbdmap_ledmap[IDEV_KBDLED_CNT] = {
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDLED_IDX_NUM]                   = XKB_LED_NAME_NUM,
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDLED_IDX_CAPS]                  = XKB_LED_NAME_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+        [IDEV_KBDLED_IDX_SCROLL]                = XKB_LED_NAME_SCROLL,
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static kbdmap *kbdmap_ref(kbdmap *km) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(km, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(km->ref > 0, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        ++km->ref;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return km;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static kbdmap *kbdmap_unref(kbdmap *km) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!km)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(km->ref > 0, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (--km->ref > 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_keymap_unref(km->xkb_keymap);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(km);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+DEFINE_TRIVIAL_CLEANUP_FUNC(kbdmap*, kbdmap_unref);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdmap_new_from_names(kbdmap **out,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                 kbdctx *kc,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                 const char *model,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                 const char *layout,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                 const char *variant,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                 const char *options) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_(kbdmap_unrefp) kbdmap *km = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_rule_names rmlvo = { };
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned int i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(out, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        km = new0(kbdmap, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!km)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        km->ref = 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        rmlvo.rules = "evdev";
Zbigniew Jędrzejewski-Szmek 62fe94
+        rmlvo.model = model;
Zbigniew Jędrzejewski-Szmek 62fe94
+        rmlvo.layout = layout;
Zbigniew Jędrzejewski-Szmek 62fe94
+        rmlvo.variant = variant;
Zbigniew Jędrzejewski-Szmek 62fe94
+        rmlvo.options = options;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        errno = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        km->xkb_keymap = xkb_keymap_new_from_names(kc->xkb_context, &rmlvo, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!km->xkb_keymap)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return errno > 0 ? -errno : -EFAULT;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                const char *t = kbdmap_modmap[i];
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (t)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        km->modmap[i] = xkb_keymap_mod_get_index(km->xkb_keymap, t);
Zbigniew Jędrzejewski-Szmek 62fe94
+                else
Zbigniew Jędrzejewski-Szmek 62fe94
+                        km->modmap[i] = XKB_MOD_INVALID;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        for (i = 0; i < IDEV_KBDLED_CNT; ++i) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                const char *t = kbdmap_ledmap[i];
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (t)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        km->ledmap[i] = xkb_keymap_led_get_index(km->xkb_keymap, t);
Zbigniew Jędrzejewski-Szmek 62fe94
+                else
Zbigniew Jędrzejewski-Szmek 62fe94
+                        km->ledmap[i] = XKB_LED_INVALID;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        *out = km;
Zbigniew Jędrzejewski-Szmek 62fe94
+        km = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Keyboard Context
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void move_str(char **dest, char **src) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(*dest);
Zbigniew Jędrzejewski-Szmek 62fe94
+        *dest = *src;
Zbigniew Jędrzejewski-Szmek 62fe94
+        *src = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdctx_refresh_keymap(kbdctx *kc) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_session *s;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d;
Zbigniew Jędrzejewski-Szmek 62fe94
+        Iterator i, j;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdmap *km;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (kc->kbdmap &&
Zbigniew Jędrzejewski-Szmek 62fe94
+            streq_ptr(kc->locale_x11_model, kc->last_x11_model) &&
Zbigniew Jędrzejewski-Szmek 62fe94
+            streq_ptr(kc->locale_x11_layout, kc->last_x11_layout) &&
Zbigniew Jędrzejewski-Szmek 62fe94
+            streq_ptr(kc->locale_x11_variant, kc->last_x11_variant) &&
Zbigniew Jędrzejewski-Szmek 62fe94
+            streq_ptr(kc->locale_x11_options, kc->last_x11_options))
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0 ;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        move_str(&kc->last_x11_model, &kc->locale_x11_model);
Zbigniew Jędrzejewski-Szmek 62fe94
+        move_str(&kc->last_x11_layout, &kc->locale_x11_layout);
Zbigniew Jędrzejewski-Szmek 62fe94
+        move_str(&kc->last_x11_variant, &kc->locale_x11_variant);
Zbigniew Jędrzejewski-Szmek 62fe94
+        move_str(&kc->last_x11_options, &kc->locale_x11_options);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev-keyboard: new default keymap: [%s / %s / %s / %s]",
Zbigniew Jędrzejewski-Szmek 62fe94
+                  kc->last_x11_model, kc->last_x11_layout, kc->last_x11_variant, kc->last_x11_options);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* TODO: add a fallback keymap that's compiled-in */
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = kbdmap_new_from_names(&km, kc, kc->last_x11_model, kc->last_x11_layout,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                  kc->last_x11_variant, kc->last_x11_options);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev-keyboard: cannot create keymap from locale1: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                          strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdmap_unref(kc->kbdmap);
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->kbdmap = km;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        HASHMAP_FOREACH(s, kc->context->session_map, i)
Zbigniew Jędrzejewski-Szmek 62fe94
+                HASHMAP_FOREACH(d, s->device_map, j)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        if (idev_is_keyboard(d))
Zbigniew Jędrzejewski-Szmek 62fe94
+                                keyboard_update_kbdmap(keyboard_from_device(d));
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static const struct bus_properties_map kbdctx_locale_map[] = {
Zbigniew Jędrzejewski-Szmek 62fe94
+        { "X11Model",   "s",    NULL, offsetof(kbdctx, locale_x11_model) },
Zbigniew Jędrzejewski-Szmek 62fe94
+        { "X11Layout",  "s",    NULL, offsetof(kbdctx, locale_x11_layout) },
Zbigniew Jędrzejewski-Szmek 62fe94
+        { "X11Variant", "s",    NULL, offsetof(kbdctx, locale_x11_variant) },
Zbigniew Jędrzejewski-Szmek 62fe94
+        { "X11Options", "s",    NULL, offsetof(kbdctx, locale_x11_options) },
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdctx_locale_get_all_fn(sd_bus *bus,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                    sd_bus_message *m,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                    void *userdata,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                    sd_bus_error *ret_err) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdctx *kc = userdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (sd_bus_message_is_method_error(m, NULL)) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                const sd_bus_error *error = sd_bus_message_get_error(m);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev-keyboard: GetAll() on locale1 failed: %s: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                          error->name, error->message);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = bus_message_map_all_properties(bus, m, kbdctx_locale_map, kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev-keyboard: erroneous GetAll() reply from locale1");
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdctx_refresh_keymap(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdctx_query_locale(kbdctx *kc) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_bus_message_new_method_call(kc->context->sysbus,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                           &m,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                           "org.freedesktop.locale1",
Zbigniew Jędrzejewski-Szmek 62fe94
+                                           "/org/freedesktop/locale1",
Zbigniew Jędrzejewski-Szmek 62fe94
+                                           "org.freedesktop.DBus.Properties",
Zbigniew Jędrzejewski-Szmek 62fe94
+                                           "GetAll");
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_bus_message_append(m, "s", "org.freedesktop.locale1");
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_bus_call_async(kc->context->sysbus,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              &kc->slot_locale_get_all,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              m,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              kbdctx_locale_get_all_fn,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              kc,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+error:
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev-keyboard: cannot send GetAll to locale1: %s", strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdctx_locale_props_changed_fn(sd_bus *bus,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                          sd_bus_message *signal,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                          void *userdata,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                          sd_bus_error *ret_err) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdctx *kc = userdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r > 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = kbdctx_query_locale(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdctx_refresh_keymap(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdctx_setup_bus(kbdctx *kc) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_bus_add_match(kc->context->sysbus,
Zbigniew Jędrzejewski-Szmek 62fe94
+                             &kc->slot_locale_props_changed,
Zbigniew Jędrzejewski-Szmek 62fe94
+                             "type='signal',"
Zbigniew Jędrzejewski-Szmek 62fe94
+                             "sender='org.freedesktop.locale1',"
Zbigniew Jędrzejewski-Szmek 62fe94
+                             "interface='org.freedesktop.DBus.Properties',"
Zbigniew Jędrzejewski-Szmek 62fe94
+                             "member='PropertiesChanged',"
Zbigniew Jędrzejewski-Szmek 62fe94
+                             "path='/org/freedesktop/locale1'",
Zbigniew Jędrzejewski-Szmek 62fe94
+                             kbdctx_locale_props_changed_fn,
Zbigniew Jędrzejewski-Szmek 62fe94
+                             kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return kbdctx_query_locale(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static kbdctx *kbdctx_ref(kbdctx *kc) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(kc, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(kc->ref > 0, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        ++kc->ref;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return kc;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static kbdctx *kbdctx_unref(kbdctx *kc) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!kc)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(kc->ref > 0, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (--kc->ref > 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->last_x11_options);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->last_x11_variant);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->last_x11_layout);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->last_x11_model);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->locale_x11_options);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->locale_x11_variant);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->locale_x11_layout);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc->locale_x11_model);
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->kbdmap = kbdmap_unref(kc->kbdmap);
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_context_unref(kc->xkb_context);
Zbigniew Jędrzejewski-Szmek 62fe94
+        hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int kbdctx_new(kbdctx **out, idev_context *c) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(out, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc = new0(kbdctx, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!kc)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->ref = 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->context = c;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        errno = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc->xkb_context = xkb_context_new(0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!kc->xkb_context)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return errno > 0 ? -errno : -EFAULT;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = kbdctx_refresh_keymap(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (c->sysbus) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = kbdctx_setup_bus(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        *out = kc;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int get_kbdctx(idev_context *c, kbdctx **out) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdctx *kc;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(c, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(out, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kc = hashmap_get(c->data_map, KBDCTX_KEY);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (kc) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                *out = kbdctx_ref(kc);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return kbdctx_new(out, c);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Keyboard Devices
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+bool idev_is_keyboard(idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        return d && d->vtable == &keyboard_vtable;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+idev_device *idev_find_keyboard(idev_session *s, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *kname;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(s, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, NULL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kname = strappenda("keyboard/", name);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return hashmap_get(s->device_map, kname);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d = &k->device;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = idev_session_raise_device_data(d->session, d, data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                          d->session->name, d->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (usecs != 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                usecs += now(CLOCK_MONOTONIC);
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = sd_event_source_set_time(k->repeat_timer, usecs);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r >= 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
Zbigniew Jędrzejewski-Szmek 62fe94
+        } else {
Zbigniew Jędrzejewski-Szmek 62fe94
+                sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_keyboard *k = userdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        keyboard_arm(k, k->repeat_rate);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return keyboard_raise_data(k, &k->repdata);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_(idev_device_freep) idev_device *d = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_keyboard *k;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char *kname;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(out, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(s, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(name, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        k = new0(idev_keyboard, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!k)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        d = &k->device;
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->repeat_delay = 250 * USEC_PER_MSEC;
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->repeat_rate = 30 * USEC_PER_MSEC;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* TODO: add key-repeat configuration */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = get_kbdctx(s->context, &k->kbdctx);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = keyboard_update_kbdmap(k);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_add_time(s->context->event,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              &k->repeat_timer,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              CLOCK_MONOTONIC,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              0,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              10 * USEC_PER_MSEC,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              keyboard_repeat_timer_fn,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              k);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kname = strappenda("keyboard/", name);
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = idev_device_add(d, kname);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (out)
Zbigniew Jędrzejewski-Szmek 62fe94
+                *out = d;
Zbigniew Jędrzejewski-Szmek 62fe94
+        d = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void keyboard_free(idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_keyboard *k = keyboard_from_device(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(k->repdata.keyboard.codepoints);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(k->repdata.keyboard.keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(k->evdata.keyboard.codepoints);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(k->evdata.keyboard.keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->repeat_timer = sd_event_source_unref(k->repeat_timer);
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->kbdmap = kbdmap_unref(k->kbdmap);
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->kbdctx = kbdctx_unref(k->kbdctx);
Zbigniew Jędrzejewski-Szmek 62fe94
+        free(k);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_layout_index_t n_lo, lo;
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_level_index_t lv;
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_keymap *keymap;
Zbigniew Jędrzejewski-Szmek 62fe94
+        const xkb_keysym_t *s;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int num;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (n_syms == 1 && syms[0] < 128)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return syms[0];
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        keymap = xkb_state_get_keymap(state);
Zbigniew Jędrzejewski-Szmek 62fe94
+        n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        for (lo = 0; lo < n_lo; ++lo) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
Zbigniew Jędrzejewski-Szmek 62fe94
+                num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (num == 1 && s[0] < 128)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return s[0];
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return -1;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_fill(idev_keyboard *k,
Zbigniew Jędrzejewski-Szmek 62fe94
+                         idev_data *dst,
Zbigniew Jędrzejewski-Szmek 62fe94
+                         bool resync,
Zbigniew Jędrzejewski-Szmek 62fe94
+                         uint16_t code,
Zbigniew Jędrzejewski-Szmek 62fe94
+                         uint32_t value,
Zbigniew Jędrzejewski-Szmek 62fe94
+                         uint32_t n_syms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                         const uint32_t *keysyms) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data_keyboard *kev;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(dst == &k->evdata || dst == &k->repdata);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (n_syms > k->n_syms) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                uint32_t *t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!t)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->evdata.keyboard.keysyms = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!t)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->evdata.keyboard.codepoints = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!t)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->repdata.keyboard.keysyms = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!t)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->repdata.keyboard.codepoints = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->n_syms = n_syms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        dst->type = IDEV_DATA_KEYBOARD;
Zbigniew Jędrzejewski-Szmek 62fe94
+        dst->resync = resync;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev = &dst->keyboard;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev->value = value;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev->keycode = code;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev->mods = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev->consumed_mods = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kev->n_syms = n_syms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        for (i = 0; i < n_syms; ++i) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!kev->codepoints[i])
Zbigniew Jędrzejewski-Szmek 62fe94
+                        kev->codepoints[i] = 0xffffffffUL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        continue;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r > 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        kev->mods |= 1 << i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r > 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        kev->consumed_mods |= 1 << i;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static void keyboard_repeat(idev_keyboard *k) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data *evdata = &k->evdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data *repdata = &k->repdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data_keyboard *evkbd = &evdata->keyboard;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_data_keyboard *repkbd = &repdata->keyboard;
Zbigniew Jędrzejewski-Szmek 62fe94
+        const xkb_keysym_t *keysyms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d = &k->device;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool repeats;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r, num;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (evdata->resync) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                /*
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * We received a re-sync event. During re-sync, any number of
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * key-events may have been lost and sync-events may be
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * re-ordered. Always disable key-repeat for those events. Any
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * following event will trigger it again.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->repeating = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                keyboard_arm(k, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (k->repeating && repkbd->keycode == evkbd->keycode) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                /*
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * We received an event for the key we currently repeat. If it
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * was released, stop key-repeat. Otherwise, ignore the event.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (evkbd->value == KBDKEY_UP) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        k->repeating = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        keyboard_arm(k, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+        } else if (evkbd->value == KBDKEY_DOWN && repeats) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                /*
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * We received a key-down event for a key that repeats. The
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * previous condition caught keys we already repeat, so we know
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * this is a different key or no key-repeat is running. Start
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * new key-repeat.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                errno = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+                num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (num < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = errno > 0 ? errno : -EFAULT;
Zbigniew Jędrzejewski-Szmek 62fe94
+                else
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                                  d->session->name, d->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+                        k->repeating = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        keyboard_arm(k, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+                } else {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        k->repeating = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        keyboard_arm(k, k->repeat_delay);
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+        } else if (k->repeating && !repeats) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                /*
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * We received an event for a key that does not repeat, but we
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * currently repeat a previously received key. The new key is
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * usually a modifier, but might be any kind of key. In this
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * case, we continue repeating the old key, but update the
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * symbols according to the new state.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                errno = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+                num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (num < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = errno > 0 ? errno : -EFAULT;
Zbigniew Jędrzejewski-Szmek 62fe94
+                else
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                                  d->session->name, d->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+                        k->repeating = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        keyboard_arm(k, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct input_event *ev = &data->evdev.event;
Zbigniew Jędrzejewski-Szmek 62fe94
+        enum xkb_state_component compch;
Zbigniew Jędrzejewski-Szmek 62fe94
+        const xkb_keysym_t *keysyms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d = &k->device;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int num, r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* TODO: We should audit xkb-actions, whether they need @resync as
Zbigniew Jędrzejewski-Szmek 62fe94
+         * flag. Most actions should just be executed, however, there might
Zbigniew Jędrzejewski-Szmek 62fe94
+         * be actions that depend on modifier-orders. Those should be
Zbigniew Jędrzejewski-Szmek 62fe94
+         * suppressed. */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+        compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (compch & XKB_STATE_LEDS) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* TODO: update LEDs */
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (num < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        keyboard_repeat(k);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return keyboard_raise_data(k, &k->evdata);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+error:
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                  d->session->name, d->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->repeating = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+        keyboard_arm(k, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_feed(idev_device *d, idev_data *data) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_keyboard *k = keyboard_from_device(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (data->type) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case IDEV_DATA_RESYNC:
Zbigniew Jędrzejewski-Szmek 62fe94
+                /*
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * If the underlying device is re-synced, key-events might be
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * sent re-ordered. Thus, we don't know which key was pressed
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * last. Key-repeat might get confused, hence, disable it
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * during re-syncs. The first following event will enable it
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * again.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                k->repeating = false;
Zbigniew Jędrzejewski-Szmek 62fe94
+                keyboard_arm(k, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case IDEV_DATA_EVDEV:
Zbigniew Jędrzejewski-Szmek 62fe94
+                return keyboard_feed_evdev(k, data);
Zbigniew Jędrzejewski-Szmek 62fe94
+        default:
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int keyboard_update_kbdmap(idev_keyboard *k) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d = &k->device;
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_state *state;
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdmap *km;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(k);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        km = k->kbdctx->kbdmap;
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (km == k->kbdmap)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        errno = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        state = xkb_state_new(km->xkb_keymap);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!state) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = errno > 0 ? -errno : -EFAULT;
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        kbdmap_unref(k->kbdmap);
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->kbdmap = kbdmap_ref(km);
Zbigniew Jędrzejewski-Szmek 62fe94
+        xkb_state_unref(k->xkb_state);
Zbigniew Jędrzejewski-Szmek 62fe94
+        k->xkb_state = state;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* TODO: On state-change, we should trigger a resync so the whole
Zbigniew Jędrzejewski-Szmek 62fe94
+         * event-state is flushed into the new xkb-state. libevdev currently
Zbigniew Jędrzejewski-Szmek 62fe94
+         * does not support that, though. */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+error:
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                  d->session->name, d->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
+        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static const idev_device_vtable keyboard_vtable = {
Zbigniew Jędrzejewski-Szmek 62fe94
+        .free                   = keyboard_free,
Zbigniew Jędrzejewski-Szmek 62fe94
+        .feed                   = keyboard_feed,
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c
Zbigniew Jędrzejewski-Szmek 62fe94
index 2316a66529..0ed518cded 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/idev.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -27,6 +27,7 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-login.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <xkbcommon/xkbcommon.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "hashmap.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "idev.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "idev-internal.h"
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -525,10 +526,40 @@ void idev_session_disable(idev_session *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+static int add_link(idev_element *e, idev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_link *l;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        l = new0(idev_link, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!l)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        l->element = e;
Zbigniew Jędrzejewski-Szmek 62fe94
+        l->device = d;
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_PREPEND(links_by_element, e->links, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+        LIST_PREPEND(links_by_device, d->links, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+        device_attach(d, l);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static int guess_type(struct udev_device *d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        const char *id_key;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        id_key = udev_device_get_property_value(d, "ID_INPUT_KEY");
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (streq_ptr(id_key, "1"))
Zbigniew Jędrzejewski-Szmek 62fe94
+                return IDEV_DEVICE_KEYBOARD;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return IDEV_DEVICE_CNT;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 int idev_session_add_evdev(idev_session *s, struct udev_device *ud) {
Zbigniew Jędrzejewski-Szmek 62fe94
         idev_element *e;
Zbigniew Jędrzejewski-Szmek 62fe94
+        idev_device *d;
Zbigniew Jędrzejewski-Szmek 62fe94
         dev_t devnum;
Zbigniew Jędrzejewski-Szmek 62fe94
-        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r, type;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(s, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(ud, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -549,7 +580,34 @@ int idev_session_add_evdev(idev_session *s, struct udev_device *ud) {
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r != 0)
Zbigniew Jędrzejewski-Szmek 62fe94
                 return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        type = guess_type(ud);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (type < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return type;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (type) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case IDEV_DEVICE_KEYBOARD:
Zbigniew Jędrzejewski-Szmek 62fe94
+                d = idev_find_keyboard(s, e->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (d) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        log_debug("idev: %s: keyboard for new evdev element '%s' already available",
Zbigniew Jędrzejewski-Szmek 62fe94
+                                  s->name, e->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = idev_keyboard_new(&d, s, e->name);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = add_link(e, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (r < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        idev_device_free(d);
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                return session_add_device(s, d);
Zbigniew Jędrzejewski-Szmek 62fe94
+        default:
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* unknown elements are silently ignored */
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 int idev_session_remove_evdev(idev_session *s, struct udev_device *ud) {
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h
Zbigniew Jędrzejewski-Szmek 62fe94
index c98fb1bfb0..0ae044cfd5 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/idev.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/idev.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -32,10 +32,12 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-bus.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <systemd/sd-event.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <xkbcommon/xkbcommon.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 typedef struct idev_data                idev_data;
Zbigniew Jędrzejewski-Szmek 62fe94
 typedef struct idev_data_evdev          idev_data_evdev;
Zbigniew Jędrzejewski-Szmek 62fe94
+typedef struct idev_data_keyboard       idev_data_keyboard;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 typedef struct idev_event               idev_event;
Zbigniew Jędrzejewski-Szmek 62fe94
 typedef struct idev_device              idev_device;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -52,6 +54,7 @@ enum {
Zbigniew Jędrzejewski-Szmek 62fe94
 };
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_DEVICE_KEYBOARD,
Zbigniew Jędrzejewski-Szmek 62fe94
         IDEV_DEVICE_CNT
Zbigniew Jędrzejewski-Szmek 62fe94
 };
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -64,12 +67,57 @@ struct idev_data_evdev {
Zbigniew Jędrzejewski-Szmek 62fe94
 };
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 /*
Zbigniew Jędrzejewski-Szmek 62fe94
+ * Keyboard Devices
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct xkb_state;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_IDX_SHIFT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_IDX_CTRL,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_IDX_ALT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_IDX_LINUX,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_IDX_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_CNT,
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_SHIFT               = 1 << IDEV_KBDMOD_IDX_SHIFT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_CTRL                = 1 << IDEV_KBDMOD_IDX_CTRL,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_ALT                 = 1 << IDEV_KBDMOD_IDX_ALT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_LINUX               = 1 << IDEV_KBDMOD_IDX_LINUX,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDMOD_CAPS                = 1 << IDEV_KBDMOD_IDX_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_IDX_NUM,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_IDX_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_IDX_SCROLL,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_CNT,
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_NUM                 = 1 << IDEV_KBDLED_IDX_NUM,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_CAPS                = 1 << IDEV_KBDLED_IDX_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_KBDLED_SCROLL              = 1 << IDEV_KBDLED_IDX_SCROLL,
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+struct idev_data_keyboard {
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct xkb_state *xkb_state;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int8_t ascii;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint8_t value;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint16_t keycode;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t consumed_mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t n_syms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t *keysyms;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t *codepoints;
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/*
Zbigniew Jędrzejewski-Szmek 62fe94
  * Data Packets
Zbigniew Jędrzejewski-Szmek 62fe94
  */
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 enum {
Zbigniew Jędrzejewski-Szmek 62fe94
         IDEV_DATA_RESYNC,
Zbigniew Jędrzejewski-Szmek 62fe94
         IDEV_DATA_EVDEV,
Zbigniew Jędrzejewski-Szmek 62fe94
+        IDEV_DATA_KEYBOARD,
Zbigniew Jędrzejewski-Szmek 62fe94
         IDEV_DATA_CNT
Zbigniew Jędrzejewski-Szmek 62fe94
 };
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -79,6 +127,7 @@ struct idev_data {
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         union {
Zbigniew Jędrzejewski-Szmek 62fe94
                 idev_data_evdev evdev;
Zbigniew Jędrzejewski-Szmek 62fe94
+                idev_data_keyboard keyboard;
Zbigniew Jędrzejewski-Szmek 62fe94
         };
Zbigniew Jędrzejewski-Szmek 62fe94
 };
Zbigniew Jędrzejewski-Szmek 62fe94