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 /* skip interface name */
321 r = sd_bus_message_skip(signal, "s");
325 r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
330 r = kbdctx_query_locale(kc);
335 kbdctx_refresh_keymap(kc);
339 log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
343 static int kbdctx_setup_bus(kbdctx *kc) {
346 r = sd_bus_add_match(kc->context->sysbus,
347 &kc->slot_locale_props_changed,
349 "sender='org.freedesktop.locale1',"
350 "interface='org.freedesktop.DBus.Properties',"
351 "member='PropertiesChanged',"
352 "path='/org/freedesktop/locale1'",
353 kbdctx_locale_props_changed_fn,
356 log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
360 return kbdctx_query_locale(kc);
363 static kbdctx *kbdctx_ref(kbdctx *kc) {
364 assert_return(kc, NULL);
365 assert_return(kc->ref > 0, NULL);
371 static kbdctx *kbdctx_unref(kbdctx *kc) {
375 assert_return(kc->ref > 0, NULL);
380 free(kc->last_x11_options);
381 free(kc->last_x11_variant);
382 free(kc->last_x11_layout);
383 free(kc->last_x11_model);
384 free(kc->locale_x11_options);
385 free(kc->locale_x11_variant);
386 free(kc->locale_x11_layout);
387 free(kc->locale_x11_model);
388 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
389 kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
390 kc->kbdmap = kbdmap_unref(kc->kbdmap);
391 xkb_context_unref(kc->xkb_context);
392 hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
398 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
400 static int kbdctx_new(kbdctx **out, idev_context *c) {
401 _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
404 assert_return(out, -EINVAL);
405 assert_return(c, -EINVAL);
407 kc = new0(kbdctx, 1);
415 kc->xkb_context = xkb_context_new(0);
416 if (!kc->xkb_context)
417 return errno > 0 ? -errno : -EFAULT;
419 r = kbdctx_refresh_keymap(kc);
424 r = kbdctx_setup_bus(kc);
429 r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
438 static int get_kbdctx(idev_context *c, kbdctx **out) {
441 assert_return(c, -EINVAL);
442 assert_return(out, -EINVAL);
444 kc = hashmap_get(c->data_map, KBDCTX_KEY);
446 *out = kbdctx_ref(kc);
450 return kbdctx_new(out, c);
457 bool idev_is_keyboard(idev_device *d) {
458 return d && d->vtable == &keyboard_vtable;
461 idev_device *idev_find_keyboard(idev_session *s, const char *name) {
464 assert_return(s, NULL);
465 assert_return(name, NULL);
467 kname = strappenda("keyboard/", name);
468 return hashmap_get(s->device_map, kname);
471 static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
472 idev_device *d = &k->device;
475 r = idev_session_raise_device_data(d->session, d, data);
477 log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
478 d->session->name, d->name, strerror(-r));
483 static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
487 usecs += now(CLOCK_MONOTONIC);
488 r = sd_event_source_set_time(k->repeat_timer, usecs);
490 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
492 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
496 static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
497 idev_keyboard *k = userdata;
499 keyboard_arm(k, k->repeat_rate);
500 return keyboard_raise_data(k, &k->repdata);
503 int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
504 _cleanup_(idev_device_freep) idev_device *d = NULL;
509 assert_return(out, -EINVAL);
510 assert_return(s, -EINVAL);
511 assert_return(name, -EINVAL);
513 k = new0(idev_keyboard, 1);
518 k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
519 k->repeat_delay = 250 * USEC_PER_MSEC;
520 k->repeat_rate = 30 * USEC_PER_MSEC;
522 /* TODO: add key-repeat configuration */
524 r = get_kbdctx(s->context, &k->kbdctx);
528 r = keyboard_update_kbdmap(k);
532 r = sd_event_add_time(s->context->event,
537 keyboard_repeat_timer_fn,
542 r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
546 kname = strappenda("keyboard/", name);
547 r = idev_device_add(d, kname);
557 static void keyboard_free(idev_device *d) {
558 idev_keyboard *k = keyboard_from_device(d);
560 xkb_state_unref(k->xkb_state);
561 free(k->repdata.keyboard.codepoints);
562 free(k->repdata.keyboard.keysyms);
563 free(k->evdata.keyboard.codepoints);
564 free(k->evdata.keyboard.keysyms);
565 k->repeat_timer = sd_event_source_unref(k->repeat_timer);
566 k->kbdmap = kbdmap_unref(k->kbdmap);
567 k->kbdctx = kbdctx_unref(k->kbdctx);
571 static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
572 xkb_layout_index_t n_lo, lo;
573 xkb_level_index_t lv;
574 struct xkb_keymap *keymap;
575 const xkb_keysym_t *s;
578 if (n_syms == 1 && syms[0] < 128)
581 keymap = xkb_state_get_keymap(state);
582 n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
584 for (lo = 0; lo < n_lo; ++lo) {
585 lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
586 num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
587 if (num == 1 && s[0] < 128)
594 static int keyboard_fill(idev_keyboard *k,
600 const uint32_t *keysyms) {
601 idev_data_keyboard *kev;
604 assert(dst == &k->evdata || dst == &k->repdata);
606 if (n_syms > k->n_syms) {
609 t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
612 k->evdata.keyboard.keysyms = t;
614 t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
617 k->evdata.keyboard.codepoints = t;
619 t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
622 k->repdata.keyboard.keysyms = t;
624 t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
627 k->repdata.keyboard.codepoints = t;
632 dst->type = IDEV_DATA_KEYBOARD;
633 dst->resync = resync;
634 kev = &dst->keyboard;
635 kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
639 kev->consumed_mods = 0;
640 kev->n_syms = n_syms;
641 memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
643 for (i = 0; i < n_syms; ++i) {
644 kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
645 if (!kev->codepoints[i])
646 kev->codepoints[i] = 0xffffffffUL;
649 for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
652 if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
655 r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
659 r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
661 kev->consumed_mods |= 1 << i;
667 static void keyboard_repeat(idev_keyboard *k) {
668 idev_data *evdata = &k->evdata;
669 idev_data *repdata = &k->repdata;
670 idev_data_keyboard *evkbd = &evdata->keyboard;
671 idev_data_keyboard *repkbd = &repdata->keyboard;
672 const xkb_keysym_t *keysyms;
673 idev_device *d = &k->device;
677 if (evdata->resync) {
679 * We received a re-sync event. During re-sync, any number of
680 * key-events may have been lost and sync-events may be
681 * re-ordered. Always disable key-repeat for those events. Any
682 * following event will trigger it again.
685 k->repeating = false;
690 repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
692 if (k->repeating && repkbd->keycode == evkbd->keycode) {
694 * We received an event for the key we currently repeat. If it
695 * was released, stop key-repeat. Otherwise, ignore the event.
698 if (evkbd->value == KBDKEY_UP) {
699 k->repeating = false;
702 } else if (evkbd->value == KBDKEY_DOWN && repeats) {
704 * We received a key-down event for a key that repeats. The
705 * previous condition caught keys we already repeat, so we know
706 * this is a different key or no key-repeat is running. Start
711 num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
713 r = errno > 0 ? errno : -EFAULT;
715 r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
718 log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
719 d->session->name, d->name, strerror(-r));
720 k->repeating = false;
724 keyboard_arm(k, k->repeat_delay);
726 } else if (k->repeating && !repeats) {
728 * We received an event for a key that does not repeat, but we
729 * currently repeat a previously received key. The new key is
730 * usually a modifier, but might be any kind of key. In this
731 * case, we continue repeating the old key, but update the
732 * symbols according to the new state.
736 num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
738 r = errno > 0 ? errno : -EFAULT;
740 r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
743 log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
744 d->session->name, d->name, strerror(-r));
745 k->repeating = false;
751 static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
752 struct input_event *ev = &data->evdev.event;
753 enum xkb_state_component compch;
754 const xkb_keysym_t *keysyms;
755 idev_device *d = &k->device;
758 if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
761 /* TODO: We should audit xkb-actions, whether they need @resync as
762 * flag. Most actions should just be executed, however, there might
763 * be actions that depend on modifier-orders. Those should be
766 num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
767 compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
769 if (compch & XKB_STATE_LEDS) {
770 /* TODO: update LEDs */
778 r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
783 return keyboard_raise_data(k, &k->evdata);
786 log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
787 d->session->name, d->name, strerror(-r));
788 k->repeating = false;
793 static int keyboard_feed(idev_device *d, idev_data *data) {
794 idev_keyboard *k = keyboard_from_device(d);
796 switch (data->type) {
797 case IDEV_DATA_RESYNC:
799 * If the underlying device is re-synced, key-events might be
800 * sent re-ordered. Thus, we don't know which key was pressed
801 * last. Key-repeat might get confused, hence, disable it
802 * during re-syncs. The first following event will enable it
806 k->repeating = false;
809 case IDEV_DATA_EVDEV:
810 return keyboard_feed_evdev(k, data);
816 static int keyboard_update_kbdmap(idev_keyboard *k) {
817 idev_device *d = &k->device;
818 struct xkb_state *state;
824 km = k->kbdctx->kbdmap;
829 state = xkb_state_new(km->xkb_keymap);
831 r = errno > 0 ? -errno : -EFAULT;
835 kbdmap_unref(k->kbdmap);
836 k->kbdmap = kbdmap_ref(km);
837 xkb_state_unref(k->xkb_state);
838 k->xkb_state = state;
840 /* TODO: On state-change, we should trigger a resync so the whole
841 * event-state is flushed into the new xkb-state. libevdev currently
842 * does not support that, though. */
847 log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
848 d->session->name, d->name, strerror(-r));
852 static const idev_device_vtable keyboard_vtable = {
853 .free = keyboard_free,
854 .feed = keyboard_feed,