chiark / gitweb /
1ee13ffd156bd1831d2dd6a49549ed144fdec449
[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 if (lvl >= XKB_LOG_LEVEL_ERROR)
510                 sd_lvl = LOG_ERR;
511         else if (lvl >= XKB_LOG_LEVEL_CRITICAL)
512                 sd_lvl = LOG_CRIT;
513         else
514                 sd_lvl = LOG_CRIT;
515
516         snprintf(buf, sizeof(buf), "idev-xkb: %s", format);
517         log_internalv(sd_lvl, 0, __FILE__, __LINE__, __func__, buf, args);
518 }
519
520 static kbdctx *kbdctx_ref(kbdctx *kc) {
521         assert_return(kc, NULL);
522         assert_return(kc->ref > 0, NULL);
523
524         ++kc->ref;
525         return kc;
526 }
527
528 static kbdctx *kbdctx_unref(kbdctx *kc) {
529         if (!kc)
530                 return NULL;
531
532         assert_return(kc->ref > 0, NULL);
533
534         if (--kc->ref > 0)
535                 return NULL;
536
537         free(kc->last_x11_options);
538         free(kc->last_x11_variant);
539         free(kc->last_x11_layout);
540         free(kc->last_x11_model);
541         free(kc->locale_x11_options);
542         free(kc->locale_x11_variant);
543         free(kc->locale_x11_layout);
544         free(kc->locale_x11_model);
545         free(kc->locale_lang);
546         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
547         kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
548         kc->kbdtbl = kbdtbl_unref(kc->kbdtbl);
549         kc->kbdmap = kbdmap_unref(kc->kbdmap);
550         xkb_context_unref(kc->xkb_context);
551         hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
552         free(kc);
553
554         return NULL;
555 }
556
557 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
558
559 static int kbdctx_new(kbdctx **out, idev_context *c) {
560         _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
561         int r;
562
563         assert_return(out, -EINVAL);
564         assert_return(c, -EINVAL);
565
566         kc = new0(kbdctx, 1);
567         if (!kc)
568                 return -ENOMEM;
569
570         kc->ref = 1;
571         kc->context = c;
572
573         errno = 0;
574         kc->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
575         if (!kc->xkb_context)
576                 return errno > 0 ? -errno : -EFAULT;
577
578         xkb_context_set_log_fn(kc->xkb_context, kbdctx_log_fn);
579         xkb_context_set_log_level(kc->xkb_context, XKB_LOG_LEVEL_DEBUG);
580
581         r = kbdctx_refresh_keymap(kc);
582         if (r < 0)
583                 return r;
584
585         r = kbdctx_refresh_compose_table(kc, NULL);
586         if (r < 0)
587                 return r;
588
589         if (c->sysbus) {
590                 r = kbdctx_setup_bus(kc);
591                 if (r < 0)
592                         return r;
593         }
594
595         r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
596         if (r < 0)
597                 return r;
598
599         *out = kc;
600         kc = NULL;
601         return 0;
602 }
603
604 static int get_kbdctx(idev_context *c, kbdctx **out) {
605         kbdctx *kc;
606
607         assert_return(c, -EINVAL);
608         assert_return(out, -EINVAL);
609
610         kc = hashmap_get(c->data_map, KBDCTX_KEY);
611         if (kc) {
612                 *out = kbdctx_ref(kc);
613                 return 0;
614         }
615
616         return kbdctx_new(out, c);
617 }
618
619 /*
620  * Keyboard Devices
621  */
622
623 bool idev_is_keyboard(idev_device *d) {
624         return d && d->vtable == &keyboard_vtable;
625 }
626
627 idev_device *idev_find_keyboard(idev_session *s, const char *name) {
628         char *kname;
629
630         assert_return(s, NULL);
631         assert_return(name, NULL);
632
633         kname = strjoina("keyboard/", name);
634         return hashmap_get(s->device_map, kname);
635 }
636
637 static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
638         idev_device *d = &k->device;
639         int r;
640
641         r = idev_session_raise_device_data(d->session, d, data);
642         if (r < 0)
643                 log_debug_errno(r, "idev-keyboard: %s/%s: error while raising data event: %m",
644                                 d->session->name, d->name);
645
646         return r;
647 }
648
649 static int keyboard_resize_bufs(idev_keyboard *k, uint32_t n_syms) {
650         uint32_t *t;
651
652         if (n_syms <= k->n_syms)
653                 return 0;
654
655         t = realloc(k->compose_res, sizeof(*t) * n_syms);
656         if (!t)
657                 return -ENOMEM;
658         k->compose_res = t;
659
660         t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
661         if (!t)
662                 return -ENOMEM;
663         k->evdata.keyboard.keysyms = t;
664
665         t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
666         if (!t)
667                 return -ENOMEM;
668         k->evdata.keyboard.codepoints = t;
669
670         t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
671         if (!t)
672                 return -ENOMEM;
673         k->repdata.keyboard.keysyms = t;
674
675         t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
676         if (!t)
677                 return -ENOMEM;
678         k->repdata.keyboard.codepoints = t;
679
680         k->n_syms = n_syms;
681         return 0;
682 }
683
684 static unsigned int keyboard_read_compose(idev_keyboard *k, const xkb_keysym_t **out) {
685         _cleanup_free_ char *t = NULL;
686         term_utf8 u8 = { };
687         char buf[256], *p;
688         size_t flen = 0;
689         int i, r;
690
691         r = xkb_compose_state_get_utf8(k->xkb_compose, buf, sizeof(buf));
692         if (r >= (int)sizeof(buf)) {
693                 t = malloc(r + 1);
694                 if (!t)
695                         return 0;
696
697                 xkb_compose_state_get_utf8(k->xkb_compose, t, r + 1);
698                 p = t;
699         } else {
700                 p = buf;
701         }
702
703         for (i = 0; i < r; ++i) {
704                 uint32_t *ucs;
705                 size_t len, j;
706
707                 len = term_utf8_decode(&u8, &ucs, p[i]);
708                 if (len > 0) {
709                         r = keyboard_resize_bufs(k, flen + len);
710                         if (r < 0)
711                                 return 0;
712
713                         for (j = 0; j < len; ++j)
714                                 k->compose_res[flen++] = ucs[j];
715                 }
716         }
717
718         *out = k->compose_res;
719         return flen;
720 }
721
722 static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
723         int r;
724
725         if (usecs != 0) {
726                 usecs += now(CLOCK_MONOTONIC);
727                 r = sd_event_source_set_time(k->repeat_timer, usecs);
728                 if (r >= 0)
729                         sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
730         } else {
731                 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
732         }
733 }
734
735 static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
736         idev_keyboard *k = userdata;
737
738         /* never feed REPEAT keys into COMPOSE */
739
740         keyboard_arm(k, k->repeat_rate);
741         return keyboard_raise_data(k, &k->repdata);
742 }
743
744 int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
745         _cleanup_(idev_device_freep) idev_device *d = NULL;
746         idev_keyboard *k;
747         char *kname;
748         int r;
749
750         assert_return(out, -EINVAL);
751         assert_return(s, -EINVAL);
752         assert_return(name, -EINVAL);
753
754         k = new0(idev_keyboard, 1);
755         if (!k)
756                 return -ENOMEM;
757
758         d = &k->device;
759         k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
760         k->repeat_delay = 250 * USEC_PER_MSEC;
761         k->repeat_rate = 30 * USEC_PER_MSEC;
762
763         /* TODO: add key-repeat configuration */
764
765         r = get_kbdctx(s->context, &k->kbdctx);
766         if (r < 0)
767                 return r;
768
769         r = keyboard_update_kbdmap(k);
770         if (r < 0)
771                 return r;
772
773         r = keyboard_update_kbdtbl(k);
774         if (r < 0)
775                 return r;
776
777         r = keyboard_resize_bufs(k, 8);
778         if (r < 0)
779                 return r;
780
781         r = sd_event_add_time(s->context->event,
782                               &k->repeat_timer,
783                               CLOCK_MONOTONIC,
784                               0,
785                               10 * USEC_PER_MSEC,
786                               keyboard_repeat_timer_fn,
787                               k);
788         if (r < 0)
789                 return r;
790
791         r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
792         if (r < 0)
793                 return r;
794
795         kname = strjoina("keyboard/", name);
796         r = idev_device_add(d, kname);
797         if (r < 0)
798                 return r;
799
800         if (out)
801                 *out = d;
802         d = NULL;
803         return 0;
804 }
805
806 static void keyboard_free(idev_device *d) {
807         idev_keyboard *k = keyboard_from_device(d);
808
809         xkb_compose_state_unref(k->xkb_compose);
810         xkb_state_unref(k->xkb_state);
811         free(k->repdata.keyboard.codepoints);
812         free(k->repdata.keyboard.keysyms);
813         free(k->evdata.keyboard.codepoints);
814         free(k->evdata.keyboard.keysyms);
815         free(k->compose_res);
816         k->repeat_timer = sd_event_source_unref(k->repeat_timer);
817         k->kbdtbl = kbdtbl_unref(k->kbdtbl);
818         k->kbdmap = kbdmap_unref(k->kbdmap);
819         k->kbdctx = kbdctx_unref(k->kbdctx);
820         free(k);
821 }
822
823 static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
824         xkb_layout_index_t n_lo, lo;
825         xkb_level_index_t lv;
826         struct xkb_keymap *keymap;
827         const xkb_keysym_t *s;
828         int num;
829
830         if (n_syms == 1 && syms[0] < 128 && syms[0] > 0)
831                 return syms[0];
832
833         keymap = xkb_state_get_keymap(state);
834         n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
835
836         for (lo = 0; lo < n_lo; ++lo) {
837                 lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
838                 num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
839                 if (num == 1 && s[0] < 128 && s[0] > 0)
840                         return s[0];
841         }
842
843         return -1;
844 }
845
846 static int keyboard_fill(idev_keyboard *k,
847                          idev_data *dst,
848                          bool resync,
849                          uint16_t code,
850                          uint32_t value,
851                          uint32_t n_syms,
852                          const uint32_t *keysyms) {
853         idev_data_keyboard *kev;
854         uint32_t i;
855         int r;
856
857         assert(dst == &k->evdata || dst == &k->repdata);
858
859         r = keyboard_resize_bufs(k, n_syms);
860         if (r < 0)
861                 return r;
862
863         dst->type = IDEV_DATA_KEYBOARD;
864         dst->resync = resync;
865         kev = &dst->keyboard;
866         kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
867         kev->value = value;
868         kev->keycode = code;
869         kev->mods = 0;
870         kev->consumed_mods = 0;
871         kev->n_syms = n_syms;
872         memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
873
874         for (i = 0; i < n_syms; ++i) {
875                 kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
876                 if (!kev->codepoints[i])
877                         kev->codepoints[i] = 0xffffffffUL;
878         }
879
880         for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
881                 if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
882                         continue;
883
884                 r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
885                 if (r > 0)
886                         kev->mods |= 1 << i;
887
888                 r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
889                 if (r > 0)
890                         kev->consumed_mods |= 1 << i;
891         }
892
893         return 0;
894 }
895
896 static void keyboard_repeat(idev_keyboard *k) {
897         idev_data *evdata = &k->evdata;
898         idev_data *repdata = &k->repdata;
899         idev_data_keyboard *evkbd = &evdata->keyboard;
900         idev_data_keyboard *repkbd = &repdata->keyboard;
901         const xkb_keysym_t *keysyms;
902         idev_device *d = &k->device;
903         bool repeats;
904         int r, num;
905
906         if (evdata->resync) {
907                 /*
908                  * We received a re-sync event. During re-sync, any number of
909                  * key-events may have been lost and sync-events may be
910                  * re-ordered. Always disable key-repeat for those events. Any
911                  * following event will trigger it again.
912                  */
913
914                 k->repeating = false;
915                 keyboard_arm(k, 0);
916                 return;
917         }
918
919         repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
920
921         if (k->repeating && repkbd->keycode == evkbd->keycode) {
922                 /*
923                  * We received an event for the key we currently repeat. If it
924                  * was released, stop key-repeat. Otherwise, ignore the event.
925                  */
926
927                 if (evkbd->value == KBDKEY_UP) {
928                         k->repeating = false;
929                         keyboard_arm(k, 0);
930                 }
931         } else if (evkbd->value == KBDKEY_DOWN && repeats) {
932                 /*
933                  * We received a key-down event for a key that repeats. The
934                  * previous condition caught keys we already repeat, so we know
935                  * this is a different key or no key-repeat is running. Start
936                  * new key-repeat.
937                  */
938
939                 errno = 0;
940                 num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
941                 if (num < 0)
942                         r = errno > 0 ? errno : -EFAULT;
943                 else
944                         r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
945
946                 if (r < 0) {
947                         log_debug_errno(r, "idev-keyboard: %s/%s: cannot set key-repeat: %m",
948                                         d->session->name, d->name);
949                         k->repeating = false;
950                         keyboard_arm(k, 0);
951                 } else {
952                         k->repeating = true;
953                         keyboard_arm(k, k->repeat_delay);
954                 }
955         } else if (k->repeating && !repeats) {
956                 /*
957                  * We received an event for a key that does not repeat, but we
958                  * currently repeat a previously received key. The new key is
959                  * usually a modifier, but might be any kind of key. In this
960                  * case, we continue repeating the old key, but update the
961                  * symbols according to the new state.
962                  */
963
964                 errno = 0;
965                 num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
966                 if (num < 0)
967                         r = errno > 0 ? errno : -EFAULT;
968                 else
969                         r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
970
971                 if (r < 0) {
972                         log_debug_errno(r, "idev-keyboard: %s/%s: cannot update key-repeat: %m",
973                                         d->session->name, d->name);
974                         k->repeating = false;
975                         keyboard_arm(k, 0);
976                 }
977         }
978 }
979
980 static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
981         struct input_event *ev = &data->evdev.event;
982         enum xkb_state_component compch;
983         enum xkb_compose_status cstatus;
984         const xkb_keysym_t *keysyms;
985         idev_device *d = &k->device;
986         int num, r;
987
988         if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
989                 return 0;
990
991         /* TODO: We should audit xkb-actions, whether they need @resync as
992          * flag. Most actions should just be executed, however, there might
993          * be actions that depend on modifier-orders. Those should be
994          * suppressed. */
995
996         num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
997         compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
998
999         if (compch & XKB_STATE_LEDS) {
1000                 /* TODO: update LEDs */
1001         }
1002
1003         if (num < 0) {
1004                 r = num;
1005                 goto error;
1006         }
1007
1008         if (k->xkb_compose && ev->value == KBDKEY_DOWN) {
1009                 if (num == 1 && !data->resync) {
1010                         xkb_compose_state_feed(k->xkb_compose, keysyms[0]);
1011                         cstatus = xkb_compose_state_get_status(k->xkb_compose);
1012                 } else {
1013                         cstatus = XKB_COMPOSE_CANCELLED;
1014                 }
1015
1016                 switch (cstatus) {
1017                 case XKB_COMPOSE_NOTHING:
1018                         /* keep produced keysyms and forward unchanged */
1019                         break;
1020                 case XKB_COMPOSE_COMPOSING:
1021                         /* consumed by compose-state, drop keysym */
1022                         keysyms = NULL;
1023                         num = 0;
1024                         break;
1025                 case XKB_COMPOSE_COMPOSED:
1026                         /* compose-state produced sth, replace keysym */
1027                         num = keyboard_read_compose(k, &keysyms);
1028                         xkb_compose_state_reset(k->xkb_compose);
1029                         break;
1030                 case XKB_COMPOSE_CANCELLED:
1031                         /* canceled compose, reset, forward cancellation sym */
1032                         xkb_compose_state_reset(k->xkb_compose);
1033                         break;
1034                 }
1035         } else if (k->xkb_compose &&
1036                    num == 1 &&
1037                    keysyms[0] == XKB_KEY_Multi_key &&
1038                    !data->resync &&
1039                    ev->value == KBDKEY_UP) {
1040                 /* Reset compose state on Multi-Key UP events. This effectively
1041                  * requires you to hold the key during the whole sequence. I
1042                  * think it's pretty handy to avoid accidental
1043                  * Compose-sequences, but this may break Compose for disabled
1044                  * people. We really need to make this opional! (TODO) */
1045                 xkb_compose_state_reset(k->xkb_compose);
1046         }
1047
1048         if (ev->value == KBDKEY_UP) {
1049                 /* never produce keysyms for UP */
1050                 keysyms = NULL;
1051                 num = 0;
1052         }
1053
1054         r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
1055         if (r < 0)
1056                 goto error;
1057
1058         keyboard_repeat(k);
1059         return keyboard_raise_data(k, &k->evdata);
1060
1061 error:
1062         log_debug_errno(r, "idev-keyboard: %s/%s: cannot handle event: %m",
1063                         d->session->name, d->name);
1064         k->repeating = false;
1065         keyboard_arm(k, 0);
1066         return 0;
1067 }
1068
1069 static int keyboard_feed(idev_device *d, idev_data *data) {
1070         idev_keyboard *k = keyboard_from_device(d);
1071
1072         switch (data->type) {
1073         case IDEV_DATA_RESYNC:
1074                 /*
1075                  * If the underlying device is re-synced, key-events might be
1076                  * sent re-ordered. Thus, we don't know which key was pressed
1077                  * last. Key-repeat might get confused, hence, disable it
1078                  * during re-syncs. The first following event will enable it
1079                  * again.
1080                  */
1081
1082                 k->repeating = false;
1083                 keyboard_arm(k, 0);
1084                 return 0;
1085         case IDEV_DATA_EVDEV:
1086                 return keyboard_feed_evdev(k, data);
1087         default:
1088                 return 0;
1089         }
1090 }
1091
1092 static int keyboard_update_kbdmap(idev_keyboard *k) {
1093         idev_device *d = &k->device;
1094         struct xkb_state *state;
1095         kbdmap *km;
1096         int r;
1097
1098         assert(k);
1099
1100         km = k->kbdctx->kbdmap;
1101         if (km == k->kbdmap)
1102                 return 0;
1103
1104         errno = 0;
1105         state = xkb_state_new(km->xkb_keymap);
1106         if (!state) {
1107                 r = errno > 0 ? -errno : -EFAULT;
1108                 goto error;
1109         }
1110
1111         kbdmap_unref(k->kbdmap);
1112         k->kbdmap = kbdmap_ref(km);
1113         xkb_state_unref(k->xkb_state);
1114         k->xkb_state = state;
1115
1116         /* TODO: On state-change, we should trigger a resync so the whole
1117          * event-state is flushed into the new xkb-state. libevdev currently
1118          * does not support that, though. */
1119
1120         return 0;
1121
1122 error:
1123         return log_debug_errno(r, "idev-keyboard: %s/%s: cannot adopt new keymap: %m",
1124                                d->session->name, d->name);
1125 }
1126
1127 static int keyboard_update_kbdtbl(idev_keyboard *k) {
1128         idev_device *d = &k->device;
1129         struct xkb_compose_state *compose = NULL;
1130         kbdtbl *kt;
1131         int r;
1132
1133         assert(k);
1134
1135         kt = k->kbdctx->kbdtbl;
1136         if (kt == k->kbdtbl)
1137                 return 0;
1138
1139         if (kt) {
1140                 errno = 0;
1141                 compose = xkb_compose_state_new(kt->xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
1142                 if (!compose) {
1143                         r = errno > 0 ? -errno : -EFAULT;
1144                         goto error;
1145                 }
1146         }
1147
1148         kbdtbl_unref(k->kbdtbl);
1149         k->kbdtbl = kbdtbl_ref(kt);
1150         xkb_compose_state_unref(k->xkb_compose);
1151         k->xkb_compose = compose;
1152
1153         return 0;
1154
1155 error:
1156         return log_debug_errno(r, "idev-keyboard: %s/%s: cannot adopt new compose table: %m",
1157                                d->session->name, d->name);
1158 }
1159
1160 static const idev_device_vtable keyboard_vtable = {
1161         .free                   = keyboard_free,
1162         .feed                   = keyboard_feed,
1163 };