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