kmscon: add --xkb-repeat-rate/delay command-line arguments
[platform/upstream/kmscon.git] / src / uterm_input_uxkb.c
1 /*
2  * uterm - Linux User-Space Terminal
3  *
4  * Copyright (c) 2011 Ran Benita <ran234@gmail.com>
5  * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files
9  * (the "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 #include <errno.h>
28 #include <inttypes.h>
29 #include <linux/input.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <xkbcommon/xkbcommon.h>
34 #include "log.h"
35 #include "shl_hook.h"
36 #include "shl_misc.h"
37 #include "uterm.h"
38 #include "uterm_input.h"
39
40 #define LOG_SUBSYSTEM "input_uxkb"
41
42 int uxkb_desc_init(struct uterm_input *input,
43                    const char *layout,
44                    const char *variant,
45                    const char *options)
46 {
47         int ret;
48         struct xkb_rule_names rmlvo = {
49                 .rules = "evdev",
50                 .model = "evdev",
51                 .layout = layout,
52                 .variant = variant,
53                 .options = options,
54         };
55
56         input->ctx = xkb_context_new(0);
57         if (!input->ctx) {
58                 log_error("cannot create XKB context");
59                 return -ENOMEM;
60         }
61
62         input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
63         if (!input->keymap) {
64                 log_warn("failed to create keymap (%s, %s, %s), "
65                          "reverting to default US keymap",
66                          layout, variant, options);
67
68                 rmlvo.layout = "us";
69                 rmlvo.variant = "";
70                 rmlvo.options = "";
71
72                 input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
73                 if (!input->keymap) {
74                         log_warn("failed to create XKB keymap");
75                         ret = -EFAULT;
76                         goto err_ctx;
77                 }
78         }
79
80         log_debug("new keyboard description (%s, %s, %s)",
81                   layout, variant, options);
82         return 0;
83
84 err_ctx:
85         xkb_context_unref(input->ctx);
86         return ret;
87 }
88
89 void uxkb_desc_destroy(struct uterm_input *input)
90 {
91         xkb_map_unref(input->keymap);
92         xkb_context_unref(input->ctx);
93 }
94
95 static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
96 {
97         struct uterm_input_dev *dev = data;
98
99         dev->repeat_event.handled = false;
100         shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event);
101 }
102
103 int uxkb_dev_init(struct uterm_input_dev *dev)
104 {
105         int ret;
106
107         ret = ev_eloop_new_timer(dev->input->eloop, &dev->repeat_timer, NULL,
108                                  timer_event, dev);
109         if (ret)
110                 return ret;
111
112         dev->state = xkb_state_new(dev->input->keymap);
113         if (!dev->state) {
114                 log_error("cannot create XKB state");
115                 ret = -ENOMEM;
116                 goto err_timer;
117         }
118
119         return 0;
120
121 err_timer:
122         ev_eloop_rm_timer(dev->repeat_timer);
123         return ret;
124 }
125
126 void uxkb_dev_destroy(struct uterm_input_dev *dev)
127 {
128         xkb_state_unref(dev->state);
129         ev_eloop_rm_timer(dev->repeat_timer);
130 }
131
132 #define EVDEV_KEYCODE_OFFSET 8
133 enum {
134         KEY_RELEASED = 0,
135         KEY_PRESSED = 1,
136         KEY_REPEATED = 2,
137 };
138
139 int uxkb_dev_process(struct uterm_input_dev *dev,
140                      uint16_t key_state, uint16_t code)
141 {
142         struct xkb_state *state;
143         struct xkb_keymap *keymap;
144         xkb_keycode_t keycode;
145         const xkb_keysym_t *keysyms;
146         int num_keysyms, i;
147         uint32_t *tmp;
148         struct itimerspec spec;
149
150         if (key_state == KEY_REPEATED)
151                 return -ENOKEY;
152
153         state = dev->state;
154         keymap = xkb_state_get_map(state);
155         keycode = code + EVDEV_KEYCODE_OFFSET;
156
157         num_keysyms = xkb_key_get_syms(state, keycode, &keysyms);
158
159         if (key_state == KEY_PRESSED)
160                 xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
161         else if (key_state == KEY_RELEASED)
162                 xkb_state_update_key(state, keycode, XKB_KEY_UP);
163
164         if (num_keysyms <= 0)
165                 return -ENOKEY;
166
167         if (dev->num_syms < num_keysyms) {
168                 tmp = realloc(dev->event.keysyms,
169                               sizeof(uint32_t) * num_keysyms);
170                 if (!tmp) {
171                         log_warning("cannot reallocate keysym buffer");
172                         return -ENOKEY;
173                 }
174                 dev->event.keysyms = tmp;
175
176                 tmp = realloc(dev->event.codepoints,
177                               sizeof(uint32_t) * num_keysyms);
178                 if (!tmp) {
179                         log_warning("cannot reallocate codepoints buffer");
180                         return -ENOKEY;
181                 }
182                 dev->event.codepoints = tmp;
183
184                 tmp = realloc(dev->repeat_event.keysyms,
185                               sizeof(uint32_t) * num_keysyms);
186                 if (!tmp) {
187                         log_warning("cannot reallocate keysym buffer");
188                         return -ENOKEY;
189                 }
190                 dev->repeat_event.keysyms = tmp;
191
192                 tmp = realloc(dev->repeat_event.codepoints,
193                               sizeof(uint32_t) * num_keysyms);
194                 if (!tmp) {
195                         log_warning("cannot reallocate codepoints buffer");
196                         return -ENOKEY;
197                 }
198                 dev->repeat_event.codepoints = tmp;
199
200                 dev->num_syms = num_keysyms;
201         }
202
203         dev->event.handled = false;
204         dev->event.keycode = code;
205         dev->event.ascii = shl_get_ascii(state, code, keysyms, num_keysyms);
206         dev->event.mods = shl_get_xkb_mods(state);
207         dev->event.num_syms = num_keysyms;
208         memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms);
209
210         for (i = 0; i < num_keysyms; ++i) {
211                 dev->event.codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
212                 if (!dev->event.codepoints[i])
213                         dev->event.codepoints[i] = UTERM_INPUT_INVALID;
214         }
215
216         if (key_state == KEY_RELEASED &&
217             dev->repeat_event.num_syms == num_keysyms &&
218             !memcmp(dev->repeat_event.keysyms,
219                     keysyms,
220                     sizeof(uint32_t) * num_keysyms)) {
221                 ev_timer_update(dev->repeat_timer, NULL);
222         } else if (key_state == KEY_PRESSED &&
223                    xkb_key_repeats(keymap, keycode)) {
224                 dev->repeat_event.keycode = code;
225                 dev->repeat_event.ascii = dev->event.ascii;
226                 dev->repeat_event.mods = dev->event.mods;
227                 dev->repeat_event.num_syms = num_keysyms;
228
229                 for (i = 0; i < num_keysyms; ++i) {
230                         dev->repeat_event.keysyms[i] = dev->event.keysyms[i];
231                         dev->repeat_event.codepoints[i] =
232                                                 dev->event.codepoints[i];
233                 }
234
235                 spec.it_interval.tv_sec = 0;
236                 spec.it_interval.tv_nsec = dev->input->repeat_rate * 1000000;
237                 spec.it_value.tv_sec = 0;
238                 spec.it_value.tv_nsec = dev->input->repeat_delay * 1000000;
239                 ev_timer_update(dev->repeat_timer, &spec);
240         }
241
242         if (key_state == KEY_RELEASED)
243                 return -ENOKEY;
244
245         shl_hook_call(dev->input->hook, dev->input, &dev->event);
246
247         return 0;
248 }
249
250 /*
251  * Call this when we regain control of the keyboard after losing it.
252  * We don't reset the locked group, this should survive a VT switch, etc. The
253  * locked modifiers are reset according to the keyboard LEDs.
254  */
255 void uxkb_dev_reset(struct uterm_input_dev *dev, const unsigned long *ledbits)
256 {
257         unsigned int i;
258         struct xkb_state *state;
259         static const struct {
260                 int led;
261                 const char *name;
262         } led_names[] = {
263                 { LED_NUML, XKB_LED_NAME_NUM },
264                 { LED_CAPSL, XKB_LED_NAME_CAPS },
265                 { LED_SCROLLL, XKB_LED_NAME_SCROLL },
266         };
267
268         /* TODO: Urghs, while the input device was closed we might have missed
269          * some events that affect internal state. As xkbcommon does not provide
270          * a way to reset the internal state, we simply recreate the state. This
271          * should have the same effect.
272          * It also has a bug that if the CTRL-Release event is skipped, then
273          * every further release will never perform a _real_ release. Kind of
274          * buggy so we should fix it upstream. */
275         state = xkb_state_new(dev->input->keymap);
276         if (!state) {
277                 log_warning("cannot recreate xkb-state");
278                 return;
279         }
280         xkb_state_unref(dev->state);
281         dev->state = state;
282
283         for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
284                 if (!input_bit_is_set(ledbits, led_names[i].led))
285                         continue;
286
287                 /*
288                  * TODO: Add support in xkbcommon for setting the led state,
289                  * and updating the modifier state accordingly. E.g., something
290                  * like this:
291                  *      xkb_state_led_name_set_active(state, led_names[i].led);
292                  */
293         }
294 }