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