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