terminal: add xkb-based keyboard devices to idev

The idev-keyboard object provides keyboard devices to the idev interface.
It uses libxkbcommon to provide proper keymap support.

So far, the keyboard implementation is pretty straightforward with one
keyboard device per matching evdev element. We feed everything into the
system keymap and provide proper high-level keyboard events to the
application. Compose-features and IM need to be added later.
This commit is contained in:
David Herrmann
2014-08-27 18:34:55 +02:00
parent c93e5a62ff
commit e06cc7b074
6 changed files with 966 additions and 3 deletions

View File

@@ -2976,6 +2976,7 @@ libsystemd_terminal_la_SOURCES = \
src/libsystemd-terminal/idev-internal.h \
src/libsystemd-terminal/idev.c \
src/libsystemd-terminal/idev-evdev.c \
src/libsystemd-terminal/idev-keyboard.c \
src/libsystemd-terminal/sysview.h \
src/libsystemd-terminal/sysview-internal.h \
src/libsystemd-terminal/sysview.c \

View File

@@ -1066,7 +1066,7 @@ AM_CONDITIONAL(ENABLE_MULTI_SEAT_X, [test "$have_multi_seat_x" = "yes"])
have_terminal=no
AC_ARG_ENABLE(terminal, AS_HELP_STRING([--enable-terminal], [enable terminal support]))
if test "x$enable_terminal" = "xyes"; then
PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 ], [have_terminal=yes])
PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 xkbcommon >= 0.4 ], [have_terminal=yes])
AS_IF([test "x$have_terminal" != xyes -a "x$enable_terminal" = xyes],
[AC_MSG_ERROR([*** terminal support requested but required dependencies not available])],
[test "x$have_terminal" = xyes],

View File

@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <xkbcommon/xkbcommon.h>
#include "hashmap.h"
#include "idev.h"
#include "list.h"
@@ -46,6 +47,14 @@ bool idev_is_evdev(idev_element *e);
idev_element *idev_find_evdev(idev_session *s, dev_t devnum);
int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud);
/*
* Keyboard Devices
*/
bool idev_is_keyboard(idev_device *d);
idev_device *idev_find_keyboard(idev_session *s, const char *name);
int idev_keyboard_new(idev_device **out, idev_session *s, const char *name);
/*
* Element Links
*/

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <systemd/sd-login.h>
#include <xkbcommon/xkbcommon.h>
#include "hashmap.h"
#include "idev.h"
#include "idev-internal.h"
@@ -525,10 +526,40 @@ void idev_session_disable(idev_session *s) {
}
}
static int add_link(idev_element *e, idev_device *d) {
idev_link *l;
assert(e);
assert(d);
l = new0(idev_link, 1);
if (!l)
return -ENOMEM;
l->element = e;
l->device = d;
LIST_PREPEND(links_by_element, e->links, l);
LIST_PREPEND(links_by_device, d->links, l);
device_attach(d, l);
return 0;
}
static int guess_type(struct udev_device *d) {
const char *id_key;
id_key = udev_device_get_property_value(d, "ID_INPUT_KEY");
if (streq_ptr(id_key, "1"))
return IDEV_DEVICE_KEYBOARD;
return IDEV_DEVICE_CNT;
}
int idev_session_add_evdev(idev_session *s, struct udev_device *ud) {
idev_element *e;
idev_device *d;
dev_t devnum;
int r;
int r, type;
assert_return(s, -EINVAL);
assert_return(ud, -EINVAL);
@@ -549,7 +580,34 @@ int idev_session_add_evdev(idev_session *s, struct udev_device *ud) {
if (r != 0)
return r;
return 0;
type = guess_type(ud);
if (type < 0)
return type;
switch (type) {
case IDEV_DEVICE_KEYBOARD:
d = idev_find_keyboard(s, e->name);
if (d) {
log_debug("idev: %s: keyboard for new evdev element '%s' already available",
s->name, e->name);
return 0;
}
r = idev_keyboard_new(&d, s, e->name);
if (r < 0)
return r;
r = add_link(e, d);
if (r < 0) {
idev_device_free(d);
return r;
}
return session_add_device(s, d);
default:
/* unknown elements are silently ignored */
return 0;
}
}
int idev_session_remove_evdev(idev_session *s, struct udev_device *ud) {

View File

@@ -32,10 +32,12 @@
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <xkbcommon/xkbcommon.h>
#include "util.h"
typedef struct idev_data idev_data;
typedef struct idev_data_evdev idev_data_evdev;
typedef struct idev_data_keyboard idev_data_keyboard;
typedef struct idev_event idev_event;
typedef struct idev_device idev_device;
@@ -52,6 +54,7 @@ enum {
};
enum {
IDEV_DEVICE_KEYBOARD,
IDEV_DEVICE_CNT
};
@@ -63,6 +66,50 @@ struct idev_data_evdev {
struct input_event event;
};
/*
* Keyboard Devices
*/
struct xkb_state;
enum {
IDEV_KBDMOD_IDX_SHIFT,
IDEV_KBDMOD_IDX_CTRL,
IDEV_KBDMOD_IDX_ALT,
IDEV_KBDMOD_IDX_LINUX,
IDEV_KBDMOD_IDX_CAPS,
IDEV_KBDMOD_CNT,
IDEV_KBDMOD_SHIFT = 1 << IDEV_KBDMOD_IDX_SHIFT,
IDEV_KBDMOD_CTRL = 1 << IDEV_KBDMOD_IDX_CTRL,
IDEV_KBDMOD_ALT = 1 << IDEV_KBDMOD_IDX_ALT,
IDEV_KBDMOD_LINUX = 1 << IDEV_KBDMOD_IDX_LINUX,
IDEV_KBDMOD_CAPS = 1 << IDEV_KBDMOD_IDX_CAPS,
};
enum {
IDEV_KBDLED_IDX_NUM,
IDEV_KBDLED_IDX_CAPS,
IDEV_KBDLED_IDX_SCROLL,
IDEV_KBDLED_CNT,
IDEV_KBDLED_NUM = 1 << IDEV_KBDLED_IDX_NUM,
IDEV_KBDLED_CAPS = 1 << IDEV_KBDLED_IDX_CAPS,
IDEV_KBDLED_SCROLL = 1 << IDEV_KBDLED_IDX_SCROLL,
};
struct idev_data_keyboard {
struct xkb_state *xkb_state;
int8_t ascii;
uint8_t value;
uint16_t keycode;
uint32_t mods;
uint32_t consumed_mods;
uint32_t n_syms;
uint32_t *keysyms;
uint32_t *codepoints;
};
/*
* Data Packets
*/
@@ -70,6 +117,7 @@ struct idev_data_evdev {
enum {
IDEV_DATA_RESYNC,
IDEV_DATA_EVDEV,
IDEV_DATA_KEYBOARD,
IDEV_DATA_CNT
};
@@ -79,6 +127,7 @@ struct idev_data {
union {
idev_data_evdev evdev;
idev_data_keyboard keyboard;
};
};