chiark / gitweb /
647aade9326a990d2d88b0cc0e868f4e7d79cf11
[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         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
316         kbdctx *kc = userdata;
317         int r;
318
319         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
320
321         r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
322         if (r < 0) {
323                 log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
324                 return r;
325         }
326
327         if (r > 0) {
328                 r = kbdctx_query_locale(kc);
329                 if (r < 0)
330                         return r;
331         }
332
333         kbdctx_refresh_keymap(kc);
334         return 0;
335 }
336
337 static int kbdctx_setup_bus(kbdctx *kc) {
338         int r;
339
340         r = sd_bus_add_match(kc->context->sysbus,
341                              &kc->slot_locale_props_changed,
342                              "type='signal',"
343                              "sender='org.freedesktop.locale1',"
344                              "interface='org.freedesktop.DBus.Properties',"
345                              "member='PropertiesChanged',"
346                              "path='/org/freedesktop/locale1'",
347                              kbdctx_locale_props_changed_fn,
348                              kc);
349         if (r < 0) {
350                 log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
351                 return r;
352         }
353
354         return kbdctx_query_locale(kc);
355 }
356
357 static kbdctx *kbdctx_ref(kbdctx *kc) {
358         assert_return(kc, NULL);
359         assert_return(kc->ref > 0, NULL);
360
361         ++kc->ref;
362         return kc;
363 }
364
365 static kbdctx *kbdctx_unref(kbdctx *kc) {
366         if (!kc)
367                 return NULL;
368
369         assert_return(kc->ref > 0, NULL);
370
371         if (--kc->ref > 0)
372                 return NULL;
373
374         free(kc->last_x11_options);
375         free(kc->last_x11_variant);
376         free(kc->last_x11_layout);
377         free(kc->last_x11_model);
378         free(kc->locale_x11_options);
379         free(kc->locale_x11_variant);
380         free(kc->locale_x11_layout);
381         free(kc->locale_x11_model);
382         kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
383         kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
384         kc->kbdmap = kbdmap_unref(kc->kbdmap);
385         xkb_context_unref(kc->xkb_context);
386         hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
387         free(kc);
388
389         return NULL;
390 }
391
392 DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
393
394 static int kbdctx_new(kbdctx **out, idev_context *c) {
395         _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
396         int r;
397
398         assert_return(out, -EINVAL);
399         assert_return(c, -EINVAL);
400
401         kc = new0(kbdctx, 1);
402         if (!kc)
403                 return -ENOMEM;
404
405         kc->ref = 1;
406         kc->context = c;
407
408         errno = 0;
409         kc->xkb_context = xkb_context_new(0);
410         if (!kc->xkb_context)
411                 return errno > 0 ? -errno : -EFAULT;
412
413         r = kbdctx_refresh_keymap(kc);
414         if (r < 0)
415                 return r;
416
417         if (c->sysbus) {
418                 r = kbdctx_setup_bus(kc);
419                 if (r < 0)
420                         return r;
421         }
422
423         r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
424         if (r < 0)
425                 return r;
426
427         *out = kc;
428         kc = NULL;
429         return 0;
430 }
431
432 static int get_kbdctx(idev_context *c, kbdctx **out) {
433         kbdctx *kc;
434
435         assert_return(c, -EINVAL);
436         assert_return(out, -EINVAL);
437
438         kc = hashmap_get(c->data_map, KBDCTX_KEY);
439         if (kc) {
440                 *out = kbdctx_ref(kc);
441                 return 0;
442         }
443
444         return kbdctx_new(out, c);
445 }
446
447 /*
448  * Keyboard Devices
449  */
450
451 bool idev_is_keyboard(idev_device *d) {
452         return d && d->vtable == &keyboard_vtable;
453 }
454
455 idev_device *idev_find_keyboard(idev_session *s, const char *name) {
456         char *kname;
457
458         assert_return(s, NULL);
459         assert_return(name, NULL);
460
461         kname = strappenda("keyboard/", name);
462         return hashmap_get(s->device_map, kname);
463 }
464
465 static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
466         idev_device *d = &k->device;
467         int r;
468
469         r = idev_session_raise_device_data(d->session, d, data);
470         if (r < 0)
471                 log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
472                           d->session->name, d->name, strerror(-r));
473
474         return r;
475 }
476
477 static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
478         int r;
479
480         if (usecs != 0) {
481                 usecs += now(CLOCK_MONOTONIC);
482                 r = sd_event_source_set_time(k->repeat_timer, usecs);
483                 if (r >= 0)
484                         sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
485         } else {
486                 sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
487         }
488 }
489
490 static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
491         idev_keyboard *k = userdata;
492
493         keyboard_arm(k, k->repeat_rate);
494         return keyboard_raise_data(k, &k->repdata);
495 }
496
497 int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
498         _cleanup_(idev_device_freep) idev_device *d = NULL;
499         idev_keyboard *k;
500         char *kname;
501         int r;
502
503         assert_return(out, -EINVAL);
504         assert_return(s, -EINVAL);
505         assert_return(name, -EINVAL);
506
507         k = new0(idev_keyboard, 1);
508         if (!k)
509                 return -ENOMEM;
510
511         d = &k->device;
512         k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
513         k->repeat_delay = 250 * USEC_PER_MSEC;
514         k->repeat_rate = 30 * USEC_PER_MSEC;
515
516         /* TODO: add key-repeat configuration */
517
518         r = get_kbdctx(s->context, &k->kbdctx);
519         if (r < 0)
520                 return r;
521
522         r = keyboard_update_kbdmap(k);
523         if (r < 0)
524                 return r;
525
526         r = sd_event_add_time(s->context->event,
527                               &k->repeat_timer,
528                               CLOCK_MONOTONIC,
529                               0,
530                               10 * USEC_PER_MSEC,
531                               keyboard_repeat_timer_fn,
532                               k);
533         if (r < 0)
534                 return r;
535
536         r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
537         if (r < 0)
538                 return r;
539
540         kname = strappenda("keyboard/", name);
541         r = idev_device_add(d, kname);
542         if (r < 0)
543                 return r;
544
545         if (out)
546                 *out = d;
547         d = NULL;
548         return 0;
549 }
550
551 static void keyboard_free(idev_device *d) {
552         idev_keyboard *k = keyboard_from_device(d);
553
554         free(k->repdata.keyboard.codepoints);
555         free(k->repdata.keyboard.keysyms);
556         free(k->evdata.keyboard.codepoints);
557         free(k->evdata.keyboard.keysyms);
558         k->repeat_timer = sd_event_source_unref(k->repeat_timer);
559         k->kbdmap = kbdmap_unref(k->kbdmap);
560         k->kbdctx = kbdctx_unref(k->kbdctx);
561         free(k);
562 }
563
564 static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
565         xkb_layout_index_t n_lo, lo;
566         xkb_level_index_t lv;
567         struct xkb_keymap *keymap;
568         const xkb_keysym_t *s;
569         int num;
570
571         if (n_syms == 1 && syms[0] < 128)
572                 return syms[0];
573
574         keymap = xkb_state_get_keymap(state);
575         n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
576
577         for (lo = 0; lo < n_lo; ++lo) {
578                 lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
579                 num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
580                 if (num == 1 && s[0] < 128)
581                         return s[0];
582         }
583
584         return -1;
585 }
586
587 static int keyboard_fill(idev_keyboard *k,
588                          idev_data *dst,
589                          bool resync,
590                          uint16_t code,
591                          uint32_t value,
592                          uint32_t n_syms,
593                          const uint32_t *keysyms) {
594         idev_data_keyboard *kev;
595         uint32_t i;
596
597         assert(dst == &k->evdata || dst == &k->repdata);
598
599         if (n_syms > k->n_syms) {
600                 uint32_t *t;
601
602                 t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
603                 if (!t)
604                         return -ENOMEM;
605                 k->evdata.keyboard.keysyms = t;
606
607                 t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
608                 if (!t)
609                         return -ENOMEM;
610                 k->evdata.keyboard.codepoints = t;
611
612                 t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
613                 if (!t)
614                         return -ENOMEM;
615                 k->repdata.keyboard.keysyms = t;
616
617                 t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
618                 if (!t)
619                         return -ENOMEM;
620                 k->repdata.keyboard.codepoints = t;
621
622                 k->n_syms = n_syms;
623         }
624
625         dst->type = IDEV_DATA_KEYBOARD;
626         dst->resync = resync;
627         kev = &dst->keyboard;
628         kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
629         kev->value = value;
630         kev->keycode = code;
631         kev->mods = 0;
632         kev->consumed_mods = 0;
633         kev->n_syms = n_syms;
634         memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
635
636         for (i = 0; i < n_syms; ++i) {
637                 kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
638                 if (!kev->codepoints[i])
639                         kev->codepoints[i] = 0xffffffffUL;
640         }
641
642         for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
643                 int r;
644
645                 if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
646                         continue;
647
648                 r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
649                 if (r > 0)
650                         kev->mods |= 1 << i;
651
652                 r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
653                 if (r > 0)
654                         kev->consumed_mods |= 1 << i;
655         }
656
657         return 0;
658 }
659
660 static void keyboard_repeat(idev_keyboard *k) {
661         idev_data *evdata = &k->evdata;
662         idev_data *repdata = &k->repdata;
663         idev_data_keyboard *evkbd = &evdata->keyboard;
664         idev_data_keyboard *repkbd = &repdata->keyboard;
665         const xkb_keysym_t *keysyms;
666         idev_device *d = &k->device;
667         bool repeats;
668         int r, num;
669
670         if (evdata->resync) {
671                 /*
672                  * We received a re-sync event. During re-sync, any number of
673                  * key-events may have been lost and sync-events may be
674                  * re-ordered. Always disable key-repeat for those events. Any
675                  * following event will trigger it again.
676                  */
677
678                 k->repeating = false;
679                 keyboard_arm(k, 0);
680                 return;
681         }
682
683         repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
684
685         if (k->repeating && repkbd->keycode == evkbd->keycode) {
686                 /*
687                  * We received an event for the key we currently repeat. If it
688                  * was released, stop key-repeat. Otherwise, ignore the event.
689                  */
690
691                 if (evkbd->value == KBDKEY_UP) {
692                         k->repeating = false;
693                         keyboard_arm(k, 0);
694                 }
695         } else if (evkbd->value == KBDKEY_DOWN && repeats) {
696                 /*
697                  * We received a key-down event for a key that repeats. The
698                  * previous condition caught keys we already repeat, so we know
699                  * this is a different key or no key-repeat is running. Start
700                  * new key-repeat.
701                  */
702
703                 errno = 0;
704                 num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
705                 if (num < 0)
706                         r = errno > 0 ? errno : -EFAULT;
707                 else
708                         r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
709
710                 if (r < 0) {
711                         log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
712                                   d->session->name, d->name, strerror(-r));
713                         k->repeating = false;
714                         keyboard_arm(k, 0);
715                 } else {
716                         k->repeating = true;
717                         keyboard_arm(k, k->repeat_delay);
718                 }
719         } else if (k->repeating && !repeats) {
720                 /*
721                  * We received an event for a key that does not repeat, but we
722                  * currently repeat a previously received key. The new key is
723                  * usually a modifier, but might be any kind of key. In this
724                  * case, we continue repeating the old key, but update the
725                  * symbols according to the new state.
726                  */
727
728                 errno = 0;
729                 num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
730                 if (num < 0)
731                         r = errno > 0 ? errno : -EFAULT;
732                 else
733                         r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
734
735                 if (r < 0) {
736                         log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
737                                   d->session->name, d->name, strerror(-r));
738                         k->repeating = false;
739                         keyboard_arm(k, 0);
740                 }
741         }
742 }
743
744 static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
745         struct input_event *ev = &data->evdev.event;
746         enum xkb_state_component compch;
747         const xkb_keysym_t *keysyms;
748         idev_device *d = &k->device;
749         int num, r;
750
751         if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
752                 return 0;
753
754         /* TODO: We should audit xkb-actions, whether they need @resync as
755          * flag. Most actions should just be executed, however, there might
756          * be actions that depend on modifier-orders. Those should be
757          * suppressed. */
758
759         num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
760         compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
761
762         if (compch & XKB_STATE_LEDS) {
763                 /* TODO: update LEDs */
764         }
765
766         if (num < 0)
767                 goto error;
768
769         r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
770         if (r < 0)
771                 goto error;
772
773         keyboard_repeat(k);
774         return keyboard_raise_data(k, &k->evdata);
775
776 error:
777         log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
778                   d->session->name, d->name, strerror(-r));
779         k->repeating = false;
780         keyboard_arm(k, 0);
781         return 0;
782 }
783
784 static int keyboard_feed(idev_device *d, idev_data *data) {
785         idev_keyboard *k = keyboard_from_device(d);
786
787         switch (data->type) {
788         case IDEV_DATA_RESYNC:
789                 /*
790                  * If the underlying device is re-synced, key-events might be
791                  * sent re-ordered. Thus, we don't know which key was pressed
792                  * last. Key-repeat might get confused, hence, disable it
793                  * during re-syncs. The first following event will enable it
794                  * again.
795                  */
796
797                 k->repeating = false;
798                 keyboard_arm(k, 0);
799                 return 0;
800         case IDEV_DATA_EVDEV:
801                 return keyboard_feed_evdev(k, data);
802         default:
803                 return 0;
804         }
805 }
806
807 static int keyboard_update_kbdmap(idev_keyboard *k) {
808         idev_device *d = &k->device;
809         struct xkb_state *state;
810         kbdmap *km;
811         int r;
812
813         assert(k);
814
815         km = k->kbdctx->kbdmap;
816         if (km == k->kbdmap)
817                 return 0;
818
819         errno = 0;
820         state = xkb_state_new(km->xkb_keymap);
821         if (!state) {
822                 r = errno > 0 ? -errno : -EFAULT;
823                 goto error;
824         }
825
826         kbdmap_unref(k->kbdmap);
827         k->kbdmap = kbdmap_ref(km);
828         xkb_state_unref(k->xkb_state);
829         k->xkb_state = state;
830
831         /* TODO: On state-change, we should trigger a resync so the whole
832          * event-state is flushed into the new xkb-state. libevdev currently
833          * does not support that, though. */
834
835         return 0;
836
837 error:
838         log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
839                   d->session->name, d->name, strerror(-r));
840         return r;
841 }
842
843 static const idev_device_vtable keyboard_vtable = {
844         .free                   = keyboard_free,
845         .feed                   = keyboard_feed,
846 };