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 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
316 kbdctx *kc = userdata;
319 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
321 r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
323 log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
328 r = kbdctx_query_locale(kc);
333 kbdctx_refresh_keymap(kc);
337 static int kbdctx_setup_bus(kbdctx *kc) {
340 r = sd_bus_add_match(kc->context->sysbus,
341 &kc->slot_locale_props_changed,
343 "sender='org.freedesktop.locale1',"
344 "interface='org.freedesktop.DBus.Properties',"
345 "member='PropertiesChanged',"
346 "path='/org/freedesktop/locale1'",
347 kbdctx_locale_props_changed_fn,
350 log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
354 return kbdctx_query_locale(kc);
357 static kbdctx *kbdctx_ref(kbdctx *kc) {
358 assert_return(kc, NULL);
359 assert_return(kc->ref > 0, NULL);
365 static kbdctx *kbdctx_unref(kbdctx *kc) {
369 assert_return(kc->ref > 0, NULL);
374 free(kc->last_x11_options);
375 free(kc->last_x11_variant);
376 free(kc->last_x11_layout);
377 free(kc->last_x11_model);
378 free(kc->locale_x11_options);
379 free(kc->locale_x11_variant);
380 free(kc->locale_x11_layout);
381 free(kc->locale_x11_model);
382 kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
383 kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
384 kc->kbdmap = kbdmap_unref(kc->kbdmap);
385 xkb_context_unref(kc->xkb_context);
386 hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
392 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
394 static int kbdctx_new(kbdctx **out, idev_context *c) {
395 _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
398 assert_return(out, -EINVAL);
399 assert_return(c, -EINVAL);
401 kc = new0(kbdctx, 1);
409 kc->xkb_context = xkb_context_new(0);
410 if (!kc->xkb_context)
411 return errno > 0 ? -errno : -EFAULT;
413 r = kbdctx_refresh_keymap(kc);
418 r = kbdctx_setup_bus(kc);
423 r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
432 static int get_kbdctx(idev_context *c, kbdctx **out) {
435 assert_return(c, -EINVAL);
436 assert_return(out, -EINVAL);
438 kc = hashmap_get(c->data_map, KBDCTX_KEY);
440 *out = kbdctx_ref(kc);
444 return kbdctx_new(out, c);
451 bool idev_is_keyboard(idev_device *d) {
452 return d && d->vtable == &keyboard_vtable;
455 idev_device *idev_find_keyboard(idev_session *s, const char *name) {
458 assert_return(s, NULL);
459 assert_return(name, NULL);
461 kname = strappenda("keyboard/", name);
462 return hashmap_get(s->device_map, kname);
465 static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
466 idev_device *d = &k->device;
469 r = idev_session_raise_device_data(d->session, d, data);
471 log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
472 d->session->name, d->name, strerror(-r));
477 static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
481 usecs += now(CLOCK_MONOTONIC);
482 r = sd_event_source_set_time(k->repeat_timer, usecs);
484 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
486 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
490 static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
491 idev_keyboard *k = userdata;
493 keyboard_arm(k, k->repeat_rate);
494 return keyboard_raise_data(k, &k->repdata);
497 int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
498 _cleanup_(idev_device_freep) idev_device *d = NULL;
503 assert_return(out, -EINVAL);
504 assert_return(s, -EINVAL);
505 assert_return(name, -EINVAL);
507 k = new0(idev_keyboard, 1);
512 k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
513 k->repeat_delay = 250 * USEC_PER_MSEC;
514 k->repeat_rate = 30 * USEC_PER_MSEC;
516 /* TODO: add key-repeat configuration */
518 r = get_kbdctx(s->context, &k->kbdctx);
522 r = keyboard_update_kbdmap(k);
526 r = sd_event_add_time(s->context->event,
531 keyboard_repeat_timer_fn,
536 r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
540 kname = strappenda("keyboard/", name);
541 r = idev_device_add(d, kname);
551 static void keyboard_free(idev_device *d) {
552 idev_keyboard *k = keyboard_from_device(d);
554 free(k->repdata.keyboard.codepoints);
555 free(k->repdata.keyboard.keysyms);
556 free(k->evdata.keyboard.codepoints);
557 free(k->evdata.keyboard.keysyms);
558 k->repeat_timer = sd_event_source_unref(k->repeat_timer);
559 k->kbdmap = kbdmap_unref(k->kbdmap);
560 k->kbdctx = kbdctx_unref(k->kbdctx);
564 static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
565 xkb_layout_index_t n_lo, lo;
566 xkb_level_index_t lv;
567 struct xkb_keymap *keymap;
568 const xkb_keysym_t *s;
571 if (n_syms == 1 && syms[0] < 128)
574 keymap = xkb_state_get_keymap(state);
575 n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
577 for (lo = 0; lo < n_lo; ++lo) {
578 lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
579 num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
580 if (num == 1 && s[0] < 128)
587 static int keyboard_fill(idev_keyboard *k,
593 const uint32_t *keysyms) {
594 idev_data_keyboard *kev;
597 assert(dst == &k->evdata || dst == &k->repdata);
599 if (n_syms > k->n_syms) {
602 t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
605 k->evdata.keyboard.keysyms = t;
607 t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
610 k->evdata.keyboard.codepoints = t;
612 t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
615 k->repdata.keyboard.keysyms = t;
617 t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
620 k->repdata.keyboard.codepoints = t;
625 dst->type = IDEV_DATA_KEYBOARD;
626 dst->resync = resync;
627 kev = &dst->keyboard;
628 kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
632 kev->consumed_mods = 0;
633 kev->n_syms = n_syms;
634 memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
636 for (i = 0; i < n_syms; ++i) {
637 kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
638 if (!kev->codepoints[i])
639 kev->codepoints[i] = 0xffffffffUL;
642 for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
645 if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
648 r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
652 r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
654 kev->consumed_mods |= 1 << i;
660 static void keyboard_repeat(idev_keyboard *k) {
661 idev_data *evdata = &k->evdata;
662 idev_data *repdata = &k->repdata;
663 idev_data_keyboard *evkbd = &evdata->keyboard;
664 idev_data_keyboard *repkbd = &repdata->keyboard;
665 const xkb_keysym_t *keysyms;
666 idev_device *d = &k->device;
670 if (evdata->resync) {
672 * We received a re-sync event. During re-sync, any number of
673 * key-events may have been lost and sync-events may be
674 * re-ordered. Always disable key-repeat for those events. Any
675 * following event will trigger it again.
678 k->repeating = false;
683 repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
685 if (k->repeating && repkbd->keycode == evkbd->keycode) {
687 * We received an event for the key we currently repeat. If it
688 * was released, stop key-repeat. Otherwise, ignore the event.
691 if (evkbd->value == KBDKEY_UP) {
692 k->repeating = false;
695 } else if (evkbd->value == KBDKEY_DOWN && repeats) {
697 * We received a key-down event for a key that repeats. The
698 * previous condition caught keys we already repeat, so we know
699 * this is a different key or no key-repeat is running. Start
704 num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
706 r = errno > 0 ? errno : -EFAULT;
708 r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
711 log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
712 d->session->name, d->name, strerror(-r));
713 k->repeating = false;
717 keyboard_arm(k, k->repeat_delay);
719 } else if (k->repeating && !repeats) {
721 * We received an event for a key that does not repeat, but we
722 * currently repeat a previously received key. The new key is
723 * usually a modifier, but might be any kind of key. In this
724 * case, we continue repeating the old key, but update the
725 * symbols according to the new state.
729 num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
731 r = errno > 0 ? errno : -EFAULT;
733 r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
736 log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
737 d->session->name, d->name, strerror(-r));
738 k->repeating = false;
744 static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
745 struct input_event *ev = &data->evdev.event;
746 enum xkb_state_component compch;
747 const xkb_keysym_t *keysyms;
748 idev_device *d = &k->device;
751 if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
754 /* TODO: We should audit xkb-actions, whether they need @resync as
755 * flag. Most actions should just be executed, however, there might
756 * be actions that depend on modifier-orders. Those should be
759 num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
760 compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
762 if (compch & XKB_STATE_LEDS) {
763 /* TODO: update LEDs */
769 r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
774 return keyboard_raise_data(k, &k->evdata);
777 log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
778 d->session->name, d->name, strerror(-r));
779 k->repeating = false;
784 static int keyboard_feed(idev_device *d, idev_data *data) {
785 idev_keyboard *k = keyboard_from_device(d);
787 switch (data->type) {
788 case IDEV_DATA_RESYNC:
790 * If the underlying device is re-synced, key-events might be
791 * sent re-ordered. Thus, we don't know which key was pressed
792 * last. Key-repeat might get confused, hence, disable it
793 * during re-syncs. The first following event will enable it
797 k->repeating = false;
800 case IDEV_DATA_EVDEV:
801 return keyboard_feed_evdev(k, data);
807 static int keyboard_update_kbdmap(idev_keyboard *k) {
808 idev_device *d = &k->device;
809 struct xkb_state *state;
815 km = k->kbdctx->kbdmap;
820 state = xkb_state_new(km->xkb_keymap);
822 r = errno > 0 ? -errno : -EFAULT;
826 kbdmap_unref(k->kbdmap);
827 k->kbdmap = kbdmap_ref(km);
828 xkb_state_unref(k->xkb_state);
829 k->xkb_state = state;
831 /* TODO: On state-change, we should trigger a resync so the whole
832 * event-state is flushed into the new xkb-state. libevdev currently
833 * does not support that, though. */
838 log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
839 d->session->name, d->name, strerror(-r));
843 static const idev_device_vtable keyboard_vtable = {
844 .free = keyboard_free,
845 .feed = keyboard_feed,