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