chiark / gitweb /
068478978d57dc8917266fd63cbd4f60b8fd2989
[elogind.git] / src / libsystemd-terminal / idev-keyboard.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <inttypes.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <systemd/sd-bus.h>
26 #include <systemd/sd-event.h>
27 #include <xkbcommon/xkbcommon.h>
28 #include <xkbcommon/xkbcommon-compose.h>
29 #include "bus-util.h"
30 #include "hashmap.h"
31 #include "idev.h"
32 #include "idev-internal.h"
33 #include "macro.h"
34 #include "util.h"
35
36 typedef struct kbdtbl kbdtbl;
37 typedef struct kbdmap kbdmap;
38 typedef struct kbdctx kbdctx;
39 typedef struct idev_keyboard idev_keyboard;
40
41 struct kbdtbl {
42         unsigned long ref;
43         struct xkb_compose_table *xkb_compose_table;
44 };
45
46 struct kbdmap {
47         unsigned long ref;
48         struct xkb_keymap *xkb_keymap;
49         xkb_mod_index_t modmap[IDEV_KBDMOD_CNT];
50         xkb_led_index_t ledmap[IDEV_KBDLED_CNT];
51 };
52
53 struct kbdctx {
54         unsigned long ref;
55         idev_context *context;
56         struct xkb_context *xkb_context;
57         struct kbdmap *kbdmap;
58         struct kbdtbl *kbdtbl;
59
60         sd_bus_slot *slot_locale_props_changed;
61         sd_bus_slot *slot_locale_get_all;
62
63         char *locale_lang;
64         char *locale_x11_model;
65         char *locale_x11_layout;
66         char *locale_x11_variant;
67         char *locale_x11_options;
68         char *last_x11_model;
69         char *last_x11_layout;
70         char *last_x11_variant;
71         char *last_x11_options;
72 };
73
74 struct idev_keyboard {
75         idev_device device;
76         kbdctx *kbdctx;
77         kbdmap *kbdmap;
78         kbdtbl *kbdtbl;
79
80         struct xkb_state *xkb_state;
81         struct xkb_compose_state *xkb_compose;
82
83         usec_t repeat_delay;
84         usec_t repeat_rate;
85         sd_event_source *repeat_timer;
86
87         uint32_t n_syms;
88         idev_data evdata;
89         idev_data repdata;
90
91         bool repeating : 1;
92 };
93
94 #define keyboard_from_device(_d) container_of((_d), idev_keyboard, device)
95
96 #define KBDCTX_KEY "keyboard.context"           /* hashmap key for global kbdctx */
97 #define KBDXKB_SHIFT (8)                        /* xkb shifts evdev key-codes by 8 */
98 #define KBDKEY_UP (0)                           /* KEY UP event value */
99 #define KBDKEY_DOWN (1)                         /* KEY DOWN event value */
100 #define KBDKEY_REPEAT (2)                       /* KEY REPEAT event value */
101
102 static const idev_device_vtable keyboard_vtable;
103
104 static int keyboard_update_kbdmap(idev_keyboard *k);
105 static int keyboard_update_kbdtbl(idev_keyboard *k);
106
107 /*
108  * Keyboard Compose Tables
109  */
110
111 static kbdtbl *kbdtbl_ref(kbdtbl *kt) {
112         if (kt) {
113                 assert_return(kt->ref > 0, NULL);
114                 ++kt->ref;
115         }
116
117         return kt;
118 }
119
120 static kbdtbl *kbdtbl_unref(kbdtbl *kt) {
121         if (!kt)
122                 return NULL;
123
124         assert_return(kt->ref > 0, NULL);
125
126         if (--kt->ref > 0)
127                 return NULL;
128
129         xkb_compose_table_unref(kt->xkb_compose_table);
130         free(kt);
131
132         return 0;
133 }
134
135 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdtbl*, kbdtbl_unref);
136
137 static int kbdtbl_new_from_locale(kbdtbl **out, kbdctx *kc, const char *locale) {
138         _cleanup_(kbdtbl_unrefp) kbdtbl *kt = NULL;
139
140         assert_return(out, -EINVAL);
141         assert_return(locale, -EINVAL);
142
143         kt = new0(kbdtbl, 1);
144         if (!kt)
145                 return -ENOMEM;
146
147         kt->ref = 1;
148
149         kt->xkb_compose_table = xkb_compose_table_new_from_locale(kc->xkb_context,
150                                                                   locale,
151                                                                   XKB_COMPOSE_COMPILE_NO_FLAGS);
152         if (!kt->xkb_compose_table)
153                 return errno > 0 ? -errno : -EFAULT;
154
155         *out = kt;
156         kt = NULL;
157         return 0;
158 }
159
160 /*
161  * Keyboard Keymaps
162  */
163
164 static const char * const kbdmap_modmap[IDEV_KBDMOD_CNT] = {
165         [IDEV_KBDMOD_IDX_SHIFT]                 = XKB_MOD_NAME_SHIFT,
166         [IDEV_KBDMOD_IDX_CTRL]                  = XKB_MOD_NAME_CTRL,
167         [IDEV_KBDMOD_IDX_ALT]                   = XKB_MOD_NAME_ALT,
168         [IDEV_KBDMOD_IDX_LINUX]                 = XKB_MOD_NAME_LOGO,
169         [IDEV_KBDMOD_IDX_CAPS]                  = XKB_MOD_NAME_CAPS,
170 };
171
172 static const char * const kbdmap_ledmap[IDEV_KBDLED_CNT] = {
173         [IDEV_KBDLED_IDX_NUM]                   = XKB_LED_NAME_NUM,
174         [IDEV_KBDLED_IDX_CAPS]                  = XKB_LED_NAME_CAPS,
175         [IDEV_KBDLED_IDX_SCROLL]                = XKB_LED_NAME_SCROLL,
176 };
177
178 static kbdmap *kbdmap_ref(kbdmap *km) {
179         assert_return(km, NULL);
180         assert_return(km->ref > 0, NULL);
181
182         ++km->ref;
183         return km;
184 }
185
186 static kbdmap *kbdmap_unref(kbdmap *km) {
187         if (!km)
188                 return NULL;
189
190         assert_return(km->ref > 0, NULL);
191
192         if (--km->ref > 0)
193                 return NULL;
194
195         xkb_keymap_unref(km->xkb_keymap);
196         free(km);
197
198         return 0;
199 }
200
201 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdmap*, kbdmap_unref);
202
203 static int kbdmap_new_from_names(kbdmap **out,
204                                  kbdctx *kc,
205                                  const char *model,
206                                  const char *layout,
207                                  const char *variant,
208                                  const char *options) {
209         _cleanup_(kbdmap_unrefp) kbdmap *km = NULL;
210         struct xkb_rule_names rmlvo = { };
211         unsigned int i;
212
213         assert_return(out, -EINVAL);
214
215         km = new0(kbdmap, 1);
216         if (!km)
217                 return -ENOMEM;
218
219         km->ref = 1;
220
221         rmlvo.rules = "evdev";
222         rmlvo.model = model;
223         rmlvo.layout = layout;
224         rmlvo.variant = variant;
225         rmlvo.options = options;
226
227         errno = 0;
228         km->xkb_keymap = xkb_keymap_new_from_names(kc->xkb_context, &rmlvo, 0);
229         if (!km->xkb_keymap)
230                 return errno > 0 ? -errno : -EFAULT;
231
232         for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
233                 const char *t = kbdmap_modmap[i];
234
235                 if (t)
236                         km->modmap[i] = xkb_keymap_mod_get_index(km->xkb_keymap, t);
237                 else
238                         km->modmap[i] = XKB_MOD_INVALID;
239         }
240
241         for (i = 0; i < IDEV_KBDLED_CNT; ++i) {
242                 const char *t = kbdmap_ledmap[i];
243
244                 if (t)
245                         km->ledmap[i] = xkb_keymap_led_get_index(km->xkb_keymap, t);
246                 else
247                         km->ledmap[i] = XKB_LED_INVALID;
248         }
249
250         *out = km;
251         km = NULL;
252         return 0;
253 }
254
255 /*
256  * Keyboard Context
257  */
258
259 static int kbdctx_refresh_compose_table(kbdctx *kc, const char *lang) {
260         kbdtbl *kt;
261         idev_session *s;
262         idev_device *d;
263         Iterator i, j;
264         int r;
265
266         if (!lang)
267                 lang = "C";
268
269         if (streq_ptr(kc->locale_lang, lang))
270                 return 0;
271
272         r = free_and_strdup(&kc->locale_lang, lang);
273         if (r < 0)
274                 return r;
275
276         log_debug("idev-keyboard: new default compose table: [ %s ]", lang);
277
278         r = kbdtbl_new_from_locale(&kt, kc, lang);
279         if (r < 0) {
280                 /* TODO: We need to catch the case where no compose-file is
281                  * available. xkb doesn't tell us so far.. so we must not treat
282                  * it as a hard-failure but just continue. Preferably, we want
283                  * xkb to tell us exactly whether compilation failed or whether
284                  * there is no compose file available for this locale. */
285                 log_debug("idev-keyboard: cannot load compose-table for '%s': %s",
286                           lang, strerror(-r));
287                 r = 0;
288                 kt = NULL;
289         }
290
291         kbdtbl_unref(kc->kbdtbl);
292         kc->kbdtbl = kt;
293
294         HASHMAP_FOREACH(s, kc->context->session_map, i)
295                 HASHMAP_FOREACH(d, s->device_map, j)
296                         if (idev_is_keyboard(d))
297                                 keyboard_update_kbdtbl(keyboard_from_device(d));
298
299         return 0;
300 }
301
302 static void move_str(char **dest, char **src) {
303         free(*dest);
304         *dest = *src;
305         *src = NULL;
306 }
307
308 static int kbdctx_refresh_keymap(kbdctx *kc) {
309         idev_session *s;
310         idev_device *d;
311         Iterator i, j;
312         kbdmap *km;
313         int r;
314
315         if (kc->kbdmap &&
316             streq_ptr(kc->locale_x11_model, kc->last_x11_model) &&
317             streq_ptr(kc->locale_x11_layout, kc->last_x11_layout) &&
318             streq_ptr(kc->locale_x11_variant, kc->last_x11_variant) &&
319             streq_ptr(kc->locale_x11_options, kc->last_x11_options))
320                 return 0 ;
321
322         move_str(&kc->last_x11_model, &kc->locale_x11_model);
323         move_str(&kc->last_x11_layout, &kc->locale_x11_layout);
324         move_str(&kc->last_x11_variant, &kc->locale_x11_variant);
325         move_str(&kc->last_x11_options, &kc->locale_x11_options);
326
327         log_debug("idev-keyboard: new default keymap: [%s / %s / %s / %s]",
328                   kc->last_x11_model, kc->last_x11_layout, kc->last_x11_variant, kc->last_x11_options);
329
330         /* TODO: add a fallback keymap that's compiled-in */
331         r = kbdmap_new_from_names(&km, kc, kc->last_x11_model, kc->last_x11_layout,
332                                   kc->last_x11_variant, kc->last_x11_options);
333         if (r < 0) {
334                 log_debug("idev-keyboard: cannot create keymap from locale1: %s",
335                           strerror(-r));
336                 return r;
337         }
338
339         kbdmap_unref(kc->kbdmap);
340         kc->kbdmap = km;
341
342         HASHMAP_FOREACH(s, kc->context->session_map, i)
343                 HASHMAP_FOREACH(d, s->device_map, j)
344                         if (idev_is_keyboard(d))
345                                 keyboard_update_kbdmap(keyboard_from_device(d));
346
347         return 0;
348 }
349
350 static int kbdctx_set_locale(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
351         kbdctx *kc = userdata;
352         const char *s, *ctype = NULL, *lang = NULL;
353         int r;
354
355         r = sd_bus_message_enter_container(m, 'a', "s");
356         if (r < 0)
357                 goto error;
358
359         while ((r = sd_bus_message_read(m, "s", &s)) > 0) {
360                 if (!ctype)
361                         ctype = startswith(s, "LC_CTYPE=");
362                 if (!lang)
363                         lang = startswith(s, "LANG=");
364         }
365
366         if (r < 0)
367                 goto error;
368
369         r = sd_bus_message_exit_container(m);
370         if (r < 0)
371                 goto error;
372
373         kbdctx_refresh_compose_table(kc, ctype ? : lang);
374         r = 0;
375
376 error:
377         if (r < 0)
378                 log_debug("idev-keyboard: cannot parse locale property from locale1: %s", strerror(-r));
379
380         return r;
381 }
382
383 static const struct bus_properties_map kbdctx_locale_map[] = {
384         { "Locale",     "as",   kbdctx_set_locale, 0 },
385         { "X11Model",   "s",    NULL, offsetof(kbdctx, locale_x11_model) },
386         { "X11Layout",  "s",    NULL, offsetof(kbdctx, locale_x11_layout) },
387         { "X11Variant", "s",    NULL, offsetof(kbdctx, locale_x11_variant) },
388         { "X11Options", "s",    NULL, offsetof(kbdctx, locale_x11_options) },
389 };
390
391 static int kbdctx_locale_get_all_fn(sd_bus *bus,
392                                     sd_bus_message *m,
393                                     void *userdata,
394                                     sd_bus_error *ret_err) {
395         kbdctx *kc = userdata;
396         int r;
397
398         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
399
400         if (sd_bus_message_is_method_error(m, NULL)) {
401                 const sd_bus_error *error = sd_bus_message_get_error(m);
402
403                 log_debug("idev-keyboard: GetAll() on locale1 failed: %s: %s",
404                           error->name, error->message);
405                 return 0;
406         }
407
408         r = bus_message_map_all_properties(bus, m, kbdctx_locale_map, kc);
409         if (r < 0) {
410                 log_debug("idev-keyboard: erroneous GetAll() reply from locale1");
411                 return 0;
412         }
413
414         kbdctx_refresh_keymap(kc);
415         return 0;
416 }
417
418 static int kbdctx_query_locale(kbdctx *kc) {
419         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
420         int r;
421
422         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
423
424         r = sd_bus_message_new_method_call(kc->context->sysbus,
425                                            &m,
426                                            "org.freedesktop.locale1",
427                                            "/org/freedesktop/locale1",
428                                            "org.freedesktop.DBus.Properties",
429                                            "GetAll");
430         if (r < 0)
431                 goto error;
432
433         r = sd_bus_message_append(m, "s", "org.freedesktop.locale1");
434         if (r < 0)
435                 goto error;
436
437         r = sd_bus_call_async(kc->context->sysbus,
438                               &kc->slot_locale_get_all,
439                               m,
440                               kbdctx_locale_get_all_fn,
441                               kc,
442                               0);
443         if (r < 0)
444                 goto error;
445
446         return 0;
447
448 error:
449         log_debug("idev-keyboard: cannot send GetAll to locale1: %s", strerror(-r));
450         return r;
451 }
452
453 static int kbdctx_locale_props_changed_fn(sd_bus *bus,
454                                           sd_bus_message *signal,
455                                           void *userdata,
456                                           sd_bus_error *ret_err) {
457         kbdctx *kc = userdata;
458         int r;
459
460         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
461
462         /* skip interface name */
463         r = sd_bus_message_skip(signal, "s");
464         if (r < 0)
465                 goto error;
466
467         r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
468         if (r < 0)
469                 goto error;
470
471         if (r > 0) {
472                 r = kbdctx_query_locale(kc);
473                 if (r < 0)
474                         return r;
475         }
476
477         kbdctx_refresh_keymap(kc);
478         return 0;
479
480 error:
481         log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
482         return r;
483 }
484
485 static int kbdctx_setup_bus(kbdctx *kc) {
486         int r;
487
488         r = sd_bus_add_match(kc->context->sysbus,
489                              &kc->slot_locale_props_changed,
490                              "type='signal',"
491                              "sender='org.freedesktop.locale1',"
492                              "interface='org.freedesktop.DBus.Properties',"
493                              "member='PropertiesChanged',"
494                              "path='/org/freedesktop/locale1'",
495                              kbdctx_locale_props_changed_fn,
496                              kc);
497         if (r < 0) {
498                 log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
499                 return r;
500         }
501
502         return kbdctx_query_locale(kc);
503 }
504
505 static kbdctx *kbdctx_ref(kbdctx *kc) {
506         assert_return(kc, NULL);
507         assert_return(kc->ref > 0, NULL);
508
509         ++kc->ref;
510         return kc;
511 }
512
513 static kbdctx *kbdctx_unref(kbdctx *kc) {
514         if (!kc)
515                 return NULL;
516
517         assert_return(kc->ref > 0, NULL);
518
519         if (--kc->ref > 0)
520                 return NULL;
521
522         free(kc->last_x11_options);
523         free(kc->last_x11_variant);
524         free(kc->last_x11_layout);
525         free(kc->last_x11_model);
526         free(kc->locale_x11_options);
527         free(kc->locale_x11_variant);
528         free(kc->locale_x11_layout);
529         free(kc->locale_x11_model);
530         free(kc->locale_lang);
531         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
532         kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
533         kc->kbdtbl = kbdtbl_unref(kc->kbdtbl);
534         kc->kbdmap = kbdmap_unref(kc->kbdmap);
535         xkb_context_unref(kc->xkb_context);
536         hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
537         free(kc);
538
539         return NULL;
540 }
541
542 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
543
544 static int kbdctx_new(kbdctx **out, idev_context *c) {
545         _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
546         int r;
547
548         assert_return(out, -EINVAL);
549         assert_return(c, -EINVAL);
550
551         kc = new0(kbdctx, 1);
552         if (!kc)
553                 return -ENOMEM;
554
555         kc->ref = 1;
556         kc->context = c;
557
558         errno = 0;
559         kc->xkb_context = xkb_context_new(0);
560         if (!kc->xkb_context)
561                 return errno > 0 ? -errno : -EFAULT;
562
563         r = kbdctx_refresh_keymap(kc);
564         if (r < 0)
565                 return r;
566
567         r = kbdctx_refresh_compose_table(kc, NULL);
568         if (r < 0)
569                 return r;
570
571         if (c->sysbus) {
572                 r = kbdctx_setup_bus(kc);
573                 if (r < 0)
574                         return r;
575         }
576
577         r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
578         if (r < 0)
579                 return r;
580
581         *out = kc;
582         kc = NULL;
583         return 0;
584 }
585
586 static int get_kbdctx(idev_context *c, kbdctx **out) {
587         kbdctx *kc;
588
589         assert_return(c, -EINVAL);
590         assert_return(out, -EINVAL);
591
592         kc = hashmap_get(c->data_map, KBDCTX_KEY);
593         if (kc) {
594                 *out = kbdctx_ref(kc);
595                 return 0;
596         }
597
598         return kbdctx_new(out, c);
599 }
600
601 /*
602  * Keyboard Devices
603  */
604
605 bool idev_is_keyboard(idev_device *d) {
606         return d && d->vtable == &keyboard_vtable;
607 }
608
609 idev_device *idev_find_keyboard(idev_session *s, const char *name) {
610         char *kname;
611
612         assert_return(s, NULL);
613         assert_return(name, NULL);
614
615         kname = strappenda("keyboard/", name);
616         return hashmap_get(s->device_map, kname);
617 }
618
619 static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
620         idev_device *d = &k->device;
621         int r;
622
623         r = idev_session_raise_device_data(d->session, d, data);
624         if (r < 0)
625                 log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
626                           d->session->name, d->name, strerror(-r));
627
628         return r;
629 }
630
631 static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
632         int r;
633
634         if (usecs != 0) {
635                 usecs += now(CLOCK_MONOTONIC);
636                 r = sd_event_source_set_time(k->repeat_timer, usecs);
637                 if (r >= 0)
638                         sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
639         } else {
640                 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
641         }
642 }
643
644 static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
645         idev_keyboard *k = userdata;
646
647         keyboard_arm(k, k->repeat_rate);
648         return keyboard_raise_data(k, &k->repdata);
649 }
650
651 int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
652         _cleanup_(idev_device_freep) idev_device *d = NULL;
653         idev_keyboard *k;
654         char *kname;
655         int r;
656
657         assert_return(out, -EINVAL);
658         assert_return(s, -EINVAL);
659         assert_return(name, -EINVAL);
660
661         k = new0(idev_keyboard, 1);
662         if (!k)
663                 return -ENOMEM;
664
665         d = &k->device;
666         k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
667         k->repeat_delay = 250 * USEC_PER_MSEC;
668         k->repeat_rate = 30 * USEC_PER_MSEC;
669
670         /* TODO: add key-repeat configuration */
671
672         r = get_kbdctx(s->context, &k->kbdctx);
673         if (r < 0)
674                 return r;
675
676         r = keyboard_update_kbdmap(k);
677         if (r < 0)
678                 return r;
679
680         r = keyboard_update_kbdtbl(k);
681         if (r < 0)
682                 return r;
683
684         r = sd_event_add_time(s->context->event,
685                               &k->repeat_timer,
686                               CLOCK_MONOTONIC,
687                               0,
688                               10 * USEC_PER_MSEC,
689                               keyboard_repeat_timer_fn,
690                               k);
691         if (r < 0)
692                 return r;
693
694         r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
695         if (r < 0)
696                 return r;
697
698         kname = strappenda("keyboard/", name);
699         r = idev_device_add(d, kname);
700         if (r < 0)
701                 return r;
702
703         if (out)
704                 *out = d;
705         d = NULL;
706         return 0;
707 }
708
709 static void keyboard_free(idev_device *d) {
710         idev_keyboard *k = keyboard_from_device(d);
711
712         xkb_compose_state_unref(k->xkb_compose);
713         xkb_state_unref(k->xkb_state);
714         free(k->repdata.keyboard.codepoints);
715         free(k->repdata.keyboard.keysyms);
716         free(k->evdata.keyboard.codepoints);
717         free(k->evdata.keyboard.keysyms);
718         k->repeat_timer = sd_event_source_unref(k->repeat_timer);
719         k->kbdtbl = kbdtbl_unref(k->kbdtbl);
720         k->kbdmap = kbdmap_unref(k->kbdmap);
721         k->kbdctx = kbdctx_unref(k->kbdctx);
722         free(k);
723 }
724
725 static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
726         xkb_layout_index_t n_lo, lo;
727         xkb_level_index_t lv;
728         struct xkb_keymap *keymap;
729         const xkb_keysym_t *s;
730         int num;
731
732         if (n_syms == 1 && syms[0] < 128 && syms[0] > 0)
733                 return syms[0];
734
735         keymap = xkb_state_get_keymap(state);
736         n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
737
738         for (lo = 0; lo < n_lo; ++lo) {
739                 lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
740                 num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
741                 if (num == 1 && s[0] < 128 && s[0] > 0)
742                         return s[0];
743         }
744
745         return -1;
746 }
747
748 static int keyboard_fill(idev_keyboard *k,
749                          idev_data *dst,
750                          bool resync,
751                          uint16_t code,
752                          uint32_t value,
753                          uint32_t n_syms,
754                          const uint32_t *keysyms) {
755         idev_data_keyboard *kev;
756         uint32_t i;
757
758         assert(dst == &k->evdata || dst == &k->repdata);
759
760         if (n_syms > k->n_syms) {
761                 uint32_t *t;
762
763                 t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
764                 if (!t)
765                         return -ENOMEM;
766                 k->evdata.keyboard.keysyms = t;
767
768                 t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
769                 if (!t)
770                         return -ENOMEM;
771                 k->evdata.keyboard.codepoints = t;
772
773                 t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
774                 if (!t)
775                         return -ENOMEM;
776                 k->repdata.keyboard.keysyms = t;
777
778                 t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
779                 if (!t)
780                         return -ENOMEM;
781                 k->repdata.keyboard.codepoints = t;
782
783                 k->n_syms = n_syms;
784         }
785
786         dst->type = IDEV_DATA_KEYBOARD;
787         dst->resync = resync;
788         kev = &dst->keyboard;
789         kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
790         kev->value = value;
791         kev->keycode = code;
792         kev->mods = 0;
793         kev->consumed_mods = 0;
794         kev->n_syms = n_syms;
795         memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
796
797         for (i = 0; i < n_syms; ++i) {
798                 kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
799                 if (!kev->codepoints[i])
800                         kev->codepoints[i] = 0xffffffffUL;
801         }
802
803         for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
804                 int r;
805
806                 if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
807                         continue;
808
809                 r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
810                 if (r > 0)
811                         kev->mods |= 1 << i;
812
813                 r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
814                 if (r > 0)
815                         kev->consumed_mods |= 1 << i;
816         }
817
818         return 0;
819 }
820
821 static void keyboard_repeat(idev_keyboard *k) {
822         idev_data *evdata = &k->evdata;
823         idev_data *repdata = &k->repdata;
824         idev_data_keyboard *evkbd = &evdata->keyboard;
825         idev_data_keyboard *repkbd = &repdata->keyboard;
826         const xkb_keysym_t *keysyms;
827         idev_device *d = &k->device;
828         bool repeats;
829         int r, num;
830
831         if (evdata->resync) {
832                 /*
833                  * We received a re-sync event. During re-sync, any number of
834                  * key-events may have been lost and sync-events may be
835                  * re-ordered. Always disable key-repeat for those events. Any
836                  * following event will trigger it again.
837                  */
838
839                 k->repeating = false;
840                 keyboard_arm(k, 0);
841                 return;
842         }
843
844         repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
845
846         if (k->repeating && repkbd->keycode == evkbd->keycode) {
847                 /*
848                  * We received an event for the key we currently repeat. If it
849                  * was released, stop key-repeat. Otherwise, ignore the event.
850                  */
851
852                 if (evkbd->value == KBDKEY_UP) {
853                         k->repeating = false;
854                         keyboard_arm(k, 0);
855                 }
856         } else if (evkbd->value == KBDKEY_DOWN && repeats) {
857                 /*
858                  * We received a key-down event for a key that repeats. The
859                  * previous condition caught keys we already repeat, so we know
860                  * this is a different key or no key-repeat is running. Start
861                  * new key-repeat.
862                  */
863
864                 errno = 0;
865                 num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
866                 if (num < 0)
867                         r = errno > 0 ? errno : -EFAULT;
868                 else
869                         r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
870
871                 if (r < 0) {
872                         log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
873                                   d->session->name, d->name, strerror(-r));
874                         k->repeating = false;
875                         keyboard_arm(k, 0);
876                 } else {
877                         k->repeating = true;
878                         keyboard_arm(k, k->repeat_delay);
879                 }
880         } else if (k->repeating && !repeats) {
881                 /*
882                  * We received an event for a key that does not repeat, but we
883                  * currently repeat a previously received key. The new key is
884                  * usually a modifier, but might be any kind of key. In this
885                  * case, we continue repeating the old key, but update the
886                  * symbols according to the new state.
887                  */
888
889                 errno = 0;
890                 num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
891                 if (num < 0)
892                         r = errno > 0 ? errno : -EFAULT;
893                 else
894                         r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
895
896                 if (r < 0) {
897                         log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
898                                   d->session->name, d->name, strerror(-r));
899                         k->repeating = false;
900                         keyboard_arm(k, 0);
901                 }
902         }
903 }
904
905 static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
906         struct input_event *ev = &data->evdev.event;
907         enum xkb_state_component compch;
908         const xkb_keysym_t *keysyms;
909         idev_device *d = &k->device;
910         int num, r;
911
912         if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
913                 return 0;
914
915         /* TODO: We should audit xkb-actions, whether they need @resync as
916          * flag. Most actions should just be executed, however, there might
917          * be actions that depend on modifier-orders. Those should be
918          * suppressed. */
919
920         num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
921         compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
922
923         if (compch & XKB_STATE_LEDS) {
924                 /* TODO: update LEDs */
925         }
926
927         if (num < 0) {
928                 r = num;
929                 goto error;
930         }
931
932         r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
933         if (r < 0)
934                 goto error;
935
936         keyboard_repeat(k);
937         return keyboard_raise_data(k, &k->evdata);
938
939 error:
940         log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
941                   d->session->name, d->name, strerror(-r));
942         k->repeating = false;
943         keyboard_arm(k, 0);
944         return 0;
945 }
946
947 static int keyboard_feed(idev_device *d, idev_data *data) {
948         idev_keyboard *k = keyboard_from_device(d);
949
950         switch (data->type) {
951         case IDEV_DATA_RESYNC:
952                 /*
953                  * If the underlying device is re-synced, key-events might be
954                  * sent re-ordered. Thus, we don't know which key was pressed
955                  * last. Key-repeat might get confused, hence, disable it
956                  * during re-syncs. The first following event will enable it
957                  * again.
958                  */
959
960                 k->repeating = false;
961                 keyboard_arm(k, 0);
962                 return 0;
963         case IDEV_DATA_EVDEV:
964                 return keyboard_feed_evdev(k, data);
965         default:
966                 return 0;
967         }
968 }
969
970 static int keyboard_update_kbdmap(idev_keyboard *k) {
971         idev_device *d = &k->device;
972         struct xkb_state *state;
973         kbdmap *km;
974         int r;
975
976         assert(k);
977
978         km = k->kbdctx->kbdmap;
979         if (km == k->kbdmap)
980                 return 0;
981
982         errno = 0;
983         state = xkb_state_new(km->xkb_keymap);
984         if (!state) {
985                 r = errno > 0 ? -errno : -EFAULT;
986                 goto error;
987         }
988
989         kbdmap_unref(k->kbdmap);
990         k->kbdmap = kbdmap_ref(km);
991         xkb_state_unref(k->xkb_state);
992         k->xkb_state = state;
993
994         /* TODO: On state-change, we should trigger a resync so the whole
995          * event-state is flushed into the new xkb-state. libevdev currently
996          * does not support that, though. */
997
998         return 0;
999
1000 error:
1001         log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
1002                   d->session->name, d->name, strerror(-r));
1003         return r;
1004 }
1005
1006 static int keyboard_update_kbdtbl(idev_keyboard *k) {
1007         idev_device *d = &k->device;
1008         struct xkb_compose_state *compose = NULL;
1009         kbdtbl *kt;
1010         int r;
1011
1012         assert(k);
1013
1014         kt = k->kbdctx->kbdtbl;
1015         if (kt == k->kbdtbl)
1016                 return 0;
1017
1018         if (kt) {
1019                 errno = 0;
1020                 compose = xkb_compose_state_new(kt->xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
1021                 if (!compose) {
1022                         r = errno > 0 ? -errno : -EFAULT;
1023                         goto error;
1024                 }
1025         }
1026
1027         kbdtbl_unref(k->kbdtbl);
1028         k->kbdtbl = kbdtbl_ref(kt);
1029         xkb_compose_state_unref(k->xkb_compose);
1030         k->xkb_compose = compose;
1031
1032         return 0;
1033
1034 error:
1035         log_debug("idev-keyboard: %s/%s: cannot adopt new compose table: %s",
1036                   d->session->name, d->name, strerror(-r));
1037         return r;
1038 }
1039
1040 static const idev_device_vtable keyboard_vtable = {
1041         .free                   = keyboard_free,
1042         .feed                   = keyboard_feed,
1043 };