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