1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <systemd/sd-bus.h>
26 #include <systemd/sd-event.h>
27 #include <xkbcommon/xkbcommon.h>
31 #include "idev-internal.h"
35 typedef struct kbdmap kbdmap;
36 typedef struct kbdctx kbdctx;
37 typedef struct idev_keyboard idev_keyboard;
41 struct xkb_keymap *xkb_keymap;
42 xkb_mod_index_t modmap[IDEV_KBDMOD_CNT];
43 xkb_led_index_t ledmap[IDEV_KBDLED_CNT];
48 idev_context *context;
49 struct xkb_context *xkb_context;
50 struct kbdmap *kbdmap;
52 sd_bus_slot *slot_locale_props_changed;
53 sd_bus_slot *slot_locale_get_all;
55 char *locale_x11_model;
56 char *locale_x11_layout;
57 char *locale_x11_variant;
58 char *locale_x11_options;
60 char *last_x11_layout;
61 char *last_x11_variant;
62 char *last_x11_options;
65 struct idev_keyboard {
70 struct xkb_state *xkb_state;
74 sd_event_source *repeat_timer;
83 #define keyboard_from_device(_d) container_of((_d), idev_keyboard, device)
85 #define KBDCTX_KEY "keyboard.context" /* hashmap key for global kbdctx */
86 #define KBDXKB_SHIFT (8) /* xkb shifts evdev key-codes by 8 */
87 #define KBDKEY_UP (0) /* KEY UP event value */
88 #define KBDKEY_DOWN (1) /* KEY DOWN event value */
89 #define KBDKEY_REPEAT (2) /* KEY REPEAT event value */
91 static const idev_device_vtable keyboard_vtable;
93 static int keyboard_update_kbdmap(idev_keyboard *k);
99 static const char * const kbdmap_modmap[IDEV_KBDMOD_CNT] = {
100 [IDEV_KBDMOD_IDX_SHIFT] = XKB_MOD_NAME_SHIFT,
101 [IDEV_KBDMOD_IDX_CTRL] = XKB_MOD_NAME_CTRL,
102 [IDEV_KBDMOD_IDX_ALT] = XKB_MOD_NAME_ALT,
103 [IDEV_KBDMOD_IDX_LINUX] = XKB_MOD_NAME_LOGO,
104 [IDEV_KBDMOD_IDX_CAPS] = XKB_MOD_NAME_CAPS,
107 static const char * const kbdmap_ledmap[IDEV_KBDLED_CNT] = {
108 [IDEV_KBDLED_IDX_NUM] = XKB_LED_NAME_NUM,
109 [IDEV_KBDLED_IDX_CAPS] = XKB_LED_NAME_CAPS,
110 [IDEV_KBDLED_IDX_SCROLL] = XKB_LED_NAME_SCROLL,
113 static kbdmap *kbdmap_ref(kbdmap *km) {
114 assert_return(km, NULL);
115 assert_return(km->ref > 0, NULL);
121 static kbdmap *kbdmap_unref(kbdmap *km) {
125 assert_return(km->ref > 0, NULL);
130 xkb_keymap_unref(km->xkb_keymap);
136 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdmap*, kbdmap_unref);
138 static int kbdmap_new_from_names(kbdmap **out,
143 const char *options) {
144 _cleanup_(kbdmap_unrefp) kbdmap *km = NULL;
145 struct xkb_rule_names rmlvo = { };
148 assert_return(out, -EINVAL);
150 km = new0(kbdmap, 1);
156 rmlvo.rules = "evdev";
158 rmlvo.layout = layout;
159 rmlvo.variant = variant;
160 rmlvo.options = options;
163 km->xkb_keymap = xkb_keymap_new_from_names(kc->xkb_context, &rmlvo, 0);
165 return errno > 0 ? -errno : -EFAULT;
167 for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
168 const char *t = kbdmap_modmap[i];
171 km->modmap[i] = xkb_keymap_mod_get_index(km->xkb_keymap, t);
173 km->modmap[i] = XKB_MOD_INVALID;
176 for (i = 0; i < IDEV_KBDLED_CNT; ++i) {
177 const char *t = kbdmap_ledmap[i];
180 km->ledmap[i] = xkb_keymap_led_get_index(km->xkb_keymap, t);
182 km->ledmap[i] = XKB_LED_INVALID;
194 static void move_str(char **dest, char **src) {
200 static int kbdctx_refresh_keymap(kbdctx *kc) {
208 streq_ptr(kc->locale_x11_model, kc->last_x11_model) &&
209 streq_ptr(kc->locale_x11_layout, kc->last_x11_layout) &&
210 streq_ptr(kc->locale_x11_variant, kc->last_x11_variant) &&
211 streq_ptr(kc->locale_x11_options, kc->last_x11_options))
214 move_str(&kc->last_x11_model, &kc->locale_x11_model);
215 move_str(&kc->last_x11_layout, &kc->locale_x11_layout);
216 move_str(&kc->last_x11_variant, &kc->locale_x11_variant);
217 move_str(&kc->last_x11_options, &kc->locale_x11_options);
219 log_debug("idev-keyboard: new default keymap: [%s / %s / %s / %s]",
220 kc->last_x11_model, kc->last_x11_layout, kc->last_x11_variant, kc->last_x11_options);
222 /* TODO: add a fallback keymap that's compiled-in */
223 r = kbdmap_new_from_names(&km, kc, kc->last_x11_model, kc->last_x11_layout,
224 kc->last_x11_variant, kc->last_x11_options);
226 log_debug("idev-keyboard: cannot create keymap from locale1: %s",
231 kbdmap_unref(kc->kbdmap);
234 HASHMAP_FOREACH(s, kc->context->session_map, i)
235 HASHMAP_FOREACH(d, s->device_map, j)
236 if (idev_is_keyboard(d))
237 keyboard_update_kbdmap(keyboard_from_device(d));
242 static const struct bus_properties_map kbdctx_locale_map[] = {
243 { "X11Model", "s", NULL, offsetof(kbdctx, locale_x11_model) },
244 { "X11Layout", "s", NULL, offsetof(kbdctx, locale_x11_layout) },
245 { "X11Variant", "s", NULL, offsetof(kbdctx, locale_x11_variant) },
246 { "X11Options", "s", NULL, offsetof(kbdctx, locale_x11_options) },
249 static int kbdctx_locale_get_all_fn(sd_bus *bus,
252 sd_bus_error *ret_err) {
253 kbdctx *kc = userdata;
256 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
258 if (sd_bus_message_is_method_error(m, NULL)) {
259 const sd_bus_error *error = sd_bus_message_get_error(m);
261 log_debug("idev-keyboard: GetAll() on locale1 failed: %s: %s",
262 error->name, error->message);
266 r = bus_message_map_all_properties(bus, m, kbdctx_locale_map, kc);
268 log_debug("idev-keyboard: erroneous GetAll() reply from locale1");
272 kbdctx_refresh_keymap(kc);
276 static int kbdctx_query_locale(kbdctx *kc) {
277 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
280 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
282 r = sd_bus_message_new_method_call(kc->context->sysbus,
284 "org.freedesktop.locale1",
285 "/org/freedesktop/locale1",
286 "org.freedesktop.DBus.Properties",
291 r = sd_bus_message_append(m, "s", "org.freedesktop.locale1");
295 r = sd_bus_call_async(kc->context->sysbus,
296 &kc->slot_locale_get_all,
298 kbdctx_locale_get_all_fn,
307 log_debug("idev-keyboard: cannot send GetAll to locale1: %s", strerror(-r));
311 static int kbdctx_locale_props_changed_fn(sd_bus *bus,
312 sd_bus_message *signal,
314 sd_bus_error *ret_err) {
315 kbdctx *kc = userdata;
318 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
320 r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
322 log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
327 r = kbdctx_query_locale(kc);
332 kbdctx_refresh_keymap(kc);
336 static int kbdctx_setup_bus(kbdctx *kc) {
339 r = sd_bus_add_match(kc->context->sysbus,
340 &kc->slot_locale_props_changed,
342 "sender='org.freedesktop.locale1',"
343 "interface='org.freedesktop.DBus.Properties',"
344 "member='PropertiesChanged',"
345 "path='/org/freedesktop/locale1'",
346 kbdctx_locale_props_changed_fn,
349 log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
353 return kbdctx_query_locale(kc);
356 static kbdctx *kbdctx_ref(kbdctx *kc) {
357 assert_return(kc, NULL);
358 assert_return(kc->ref > 0, NULL);
364 static kbdctx *kbdctx_unref(kbdctx *kc) {
368 assert_return(kc->ref > 0, NULL);
373 free(kc->last_x11_options);
374 free(kc->last_x11_variant);
375 free(kc->last_x11_layout);
376 free(kc->last_x11_model);
377 free(kc->locale_x11_options);
378 free(kc->locale_x11_variant);
379 free(kc->locale_x11_layout);
380 free(kc->locale_x11_model);
381 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
382 kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
383 kc->kbdmap = kbdmap_unref(kc->kbdmap);
384 xkb_context_unref(kc->xkb_context);
385 hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
391 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
393 static int kbdctx_new(kbdctx **out, idev_context *c) {
394 _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
397 assert_return(out, -EINVAL);
398 assert_return(c, -EINVAL);
400 kc = new0(kbdctx, 1);
408 kc->xkb_context = xkb_context_new(0);
409 if (!kc->xkb_context)
410 return errno > 0 ? -errno : -EFAULT;
412 r = kbdctx_refresh_keymap(kc);
417 r = kbdctx_setup_bus(kc);
422 r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
431 static int get_kbdctx(idev_context *c, kbdctx **out) {
434 assert_return(c, -EINVAL);
435 assert_return(out, -EINVAL);
437 kc = hashmap_get(c->data_map, KBDCTX_KEY);
439 *out = kbdctx_ref(kc);
443 return kbdctx_new(out, c);
450 bool idev_is_keyboard(idev_device *d) {
451 return d && d->vtable == &keyboard_vtable;
454 idev_device *idev_find_keyboard(idev_session *s, const char *name) {
457 assert_return(s, NULL);
458 assert_return(name, NULL);
460 kname = strappenda("keyboard/", name);
461 return hashmap_get(s->device_map, kname);
464 static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
465 idev_device *d = &k->device;
468 r = idev_session_raise_device_data(d->session, d, data);
470 log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
471 d->session->name, d->name, strerror(-r));
476 static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
480 usecs += now(CLOCK_MONOTONIC);
481 r = sd_event_source_set_time(k->repeat_timer, usecs);
483 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
485 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
489 static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
490 idev_keyboard *k = userdata;
492 keyboard_arm(k, k->repeat_rate);
493 return keyboard_raise_data(k, &k->repdata);
496 int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
497 _cleanup_(idev_device_freep) idev_device *d = NULL;
502 assert_return(out, -EINVAL);
503 assert_return(s, -EINVAL);
504 assert_return(name, -EINVAL);
506 k = new0(idev_keyboard, 1);
511 k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
512 k->repeat_delay = 250 * USEC_PER_MSEC;
513 k->repeat_rate = 30 * USEC_PER_MSEC;
515 /* TODO: add key-repeat configuration */
517 r = get_kbdctx(s->context, &k->kbdctx);
521 r = keyboard_update_kbdmap(k);
525 r = sd_event_add_time(s->context->event,
530 keyboard_repeat_timer_fn,
535 r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
539 kname = strappenda("keyboard/", name);
540 r = idev_device_add(d, kname);
550 static void keyboard_free(idev_device *d) {
551 idev_keyboard *k = keyboard_from_device(d);
553 free(k->repdata.keyboard.codepoints);
554 free(k->repdata.keyboard.keysyms);
555 free(k->evdata.keyboard.codepoints);
556 free(k->evdata.keyboard.keysyms);
557 k->repeat_timer = sd_event_source_unref(k->repeat_timer);
558 k->kbdmap = kbdmap_unref(k->kbdmap);
559 k->kbdctx = kbdctx_unref(k->kbdctx);
563 static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
564 xkb_layout_index_t n_lo, lo;
565 xkb_level_index_t lv;
566 struct xkb_keymap *keymap;
567 const xkb_keysym_t *s;
570 if (n_syms == 1 && syms[0] < 128)
573 keymap = xkb_state_get_keymap(state);
574 n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
576 for (lo = 0; lo < n_lo; ++lo) {
577 lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
578 num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
579 if (num == 1 && s[0] < 128)
586 static int keyboard_fill(idev_keyboard *k,
592 const uint32_t *keysyms) {
593 idev_data_keyboard *kev;
596 assert(dst == &k->evdata || dst == &k->repdata);
598 if (n_syms > k->n_syms) {
601 t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
604 k->evdata.keyboard.keysyms = t;
606 t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
609 k->evdata.keyboard.codepoints = t;
611 t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
614 k->repdata.keyboard.keysyms = t;
616 t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
619 k->repdata.keyboard.codepoints = t;
624 dst->type = IDEV_DATA_KEYBOARD;
625 dst->resync = resync;
626 kev = &dst->keyboard;
627 kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
631 kev->consumed_mods = 0;
632 kev->n_syms = n_syms;
633 memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
635 for (i = 0; i < n_syms; ++i) {
636 kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
637 if (!kev->codepoints[i])
638 kev->codepoints[i] = 0xffffffffUL;
641 for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
644 if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
647 r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
651 r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
653 kev->consumed_mods |= 1 << i;
659 static void keyboard_repeat(idev_keyboard *k) {
660 idev_data *evdata = &k->evdata;
661 idev_data *repdata = &k->repdata;
662 idev_data_keyboard *evkbd = &evdata->keyboard;
663 idev_data_keyboard *repkbd = &repdata->keyboard;
664 const xkb_keysym_t *keysyms;
665 idev_device *d = &k->device;
669 if (evdata->resync) {
671 * We received a re-sync event. During re-sync, any number of
672 * key-events may have been lost and sync-events may be
673 * re-ordered. Always disable key-repeat for those events. Any
674 * following event will trigger it again.
677 k->repeating = false;
682 repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
684 if (k->repeating && repkbd->keycode == evkbd->keycode) {
686 * We received an event for the key we currently repeat. If it
687 * was released, stop key-repeat. Otherwise, ignore the event.
690 if (evkbd->value == KBDKEY_UP) {
691 k->repeating = false;
694 } else if (evkbd->value == KBDKEY_DOWN && repeats) {
696 * We received a key-down event for a key that repeats. The
697 * previous condition caught keys we already repeat, so we know
698 * this is a different key or no key-repeat is running. Start
703 num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
705 r = errno > 0 ? errno : -EFAULT;
707 r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
710 log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
711 d->session->name, d->name, strerror(-r));
712 k->repeating = false;
716 keyboard_arm(k, k->repeat_delay);
718 } else if (k->repeating && !repeats) {
720 * We received an event for a key that does not repeat, but we
721 * currently repeat a previously received key. The new key is
722 * usually a modifier, but might be any kind of key. In this
723 * case, we continue repeating the old key, but update the
724 * symbols according to the new state.
728 num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
730 r = errno > 0 ? errno : -EFAULT;
732 r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
735 log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
736 d->session->name, d->name, strerror(-r));
737 k->repeating = false;
743 static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
744 struct input_event *ev = &data->evdev.event;
745 enum xkb_state_component compch;
746 const xkb_keysym_t *keysyms;
747 idev_device *d = &k->device;
750 if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
753 /* TODO: We should audit xkb-actions, whether they need @resync as
754 * flag. Most actions should just be executed, however, there might
755 * be actions that depend on modifier-orders. Those should be
758 num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
759 compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
761 if (compch & XKB_STATE_LEDS) {
762 /* TODO: update LEDs */
768 r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
773 return keyboard_raise_data(k, &k->evdata);
776 log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
777 d->session->name, d->name, strerror(-r));
778 k->repeating = false;
783 static int keyboard_feed(idev_device *d, idev_data *data) {
784 idev_keyboard *k = keyboard_from_device(d);
786 switch (data->type) {
787 case IDEV_DATA_RESYNC:
789 * If the underlying device is re-synced, key-events might be
790 * sent re-ordered. Thus, we don't know which key was pressed
791 * last. Key-repeat might get confused, hence, disable it
792 * during re-syncs. The first following event will enable it
796 k->repeating = false;
799 case IDEV_DATA_EVDEV:
800 return keyboard_feed_evdev(k, data);
806 static int keyboard_update_kbdmap(idev_keyboard *k) {
807 idev_device *d = &k->device;
808 struct xkb_state *state;
814 km = k->kbdctx->kbdmap;
819 state = xkb_state_new(km->xkb_keymap);
821 r = errno > 0 ? -errno : -EFAULT;
825 kbdmap_unref(k->kbdmap);
826 k->kbdmap = kbdmap_ref(km);
827 xkb_state_unref(k->xkb_state);
828 k->xkb_state = state;
830 /* TODO: On state-change, we should trigger a resync so the whole
831 * event-state is flushed into the new xkb-state. libevdev currently
832 * does not support that, though. */
837 log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
838 d->session->name, d->name, strerror(-r));
842 static const idev_device_vtable keyboard_vtable = {
843 .free = keyboard_free,
844 .feed = keyboard_feed,