tsm: vte: use ASCII keysyms for ctrl+<XY> shortcuts
[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_misc.h"
36 #include "uterm.h"
37 #include "uterm_input.h"
38
39 #define LOG_SUBSYSTEM "input_uxkb"
40
41 int uxkb_desc_init(struct uterm_input *input,
42                    const char *layout,
43                    const char *variant,
44                    const char *options)
45 {
46         int ret;
47         struct xkb_rule_names rmlvo = {
48                 .rules = "evdev",
49                 .model = "evdev",
50                 .layout = layout,
51                 .variant = variant,
52                 .options = options,
53         };
54
55         input->ctx = xkb_context_new(0);
56         if (!input->ctx) {
57                 log_error("cannot create XKB context");
58                 return -ENOMEM;
59         }
60
61         input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
62         if (!input->keymap) {
63                 log_warn("failed to create keymap (%s, %s, %s), "
64                          "reverting to default US keymap",
65                          layout, variant, options);
66
67                 rmlvo.layout = "us";
68                 rmlvo.variant = "";
69                 rmlvo.options = "";
70
71                 input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
72                 if (!input->keymap) {
73                         log_warn("failed to create XKB keymap");
74                         ret = -EFAULT;
75                         goto err_ctx;
76                 }
77         }
78
79         log_debug("new keyboard description (%s, %s, %s)",
80                   layout, variant, options);
81         return 0;
82
83 err_ctx:
84         xkb_context_unref(input->ctx);
85         return ret;
86 }
87
88 void uxkb_desc_destroy(struct uterm_input *input)
89 {
90         xkb_map_unref(input->keymap);
91         xkb_context_unref(input->ctx);
92 }
93
94 int uxkb_dev_init(struct uterm_input_dev *dev)
95 {
96         dev->state = xkb_state_new(dev->input->keymap);
97         if (!dev->state)
98                 return -ENOMEM;
99
100         return 0;
101 }
102
103 void uxkb_dev_destroy(struct uterm_input_dev *dev)
104 {
105         xkb_state_unref(dev->state);
106 }
107
108 #define EVDEV_KEYCODE_OFFSET 8
109 enum {
110         KEY_RELEASED = 0,
111         KEY_PRESSED = 1,
112         KEY_REPEATED = 2,
113 };
114
115 int uxkb_dev_process(struct uterm_input_dev *dev,
116                      uint16_t key_state, uint16_t code)
117 {
118         struct xkb_state *state;
119         struct xkb_keymap *keymap;
120         xkb_keycode_t keycode;
121         const xkb_keysym_t *keysyms;
122         int num_keysyms, i;
123         uint32_t *tmp;
124
125         state = dev->state;
126         keymap = xkb_state_get_map(state);
127         keycode = code + EVDEV_KEYCODE_OFFSET;
128
129         num_keysyms = xkb_key_get_syms(state, keycode, &keysyms);
130
131         if (key_state == KEY_PRESSED)
132                 xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
133         else if (key_state == KEY_RELEASED)
134                 xkb_state_update_key(state, keycode, XKB_KEY_UP);
135
136         if (key_state == KEY_RELEASED)
137                 return -ENOKEY;
138
139         if (key_state == KEY_REPEATED && !xkb_key_repeats(keymap, keycode))
140                 return -ENOKEY;
141
142         if (num_keysyms <= 0)
143                 return -ENOKEY;
144
145         if (dev->num_syms < num_keysyms) {
146                 tmp = realloc(dev->event.keysyms,
147                               sizeof(uint32_t) * num_keysyms);
148                 if (!tmp) {
149                         log_warning("cannot reallocate keysym buffer");
150                         return -ENOKEY;
151                 }
152                 dev->event.keysyms = tmp;
153
154                 tmp = realloc(dev->event.codepoints,
155                               sizeof(uint32_t) * num_keysyms);
156                 if (!tmp) {
157                         log_warning("cannot reallocate codepoints buffer");
158                         return -ENOKEY;
159                 }
160                 dev->event.codepoints = tmp;
161
162                 dev->num_syms = num_keysyms;
163         }
164
165         dev->event.handled = false;
166         dev->event.keycode = code;
167         dev->event.ascii = shl_get_ascii(state, code, keysyms, num_keysyms);
168         dev->event.mods = shl_get_xkb_mods(state);
169         dev->event.num_syms = num_keysyms;
170         memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms);
171
172         for (i = 0; i < num_keysyms; ++i) {
173                 dev->event.codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
174                 if (!dev->event.codepoints[i])
175                         dev->event.codepoints[i] = UTERM_INPUT_INVALID;
176         }
177
178         return 0;
179 }
180
181 /*
182  * Call this when we regain control of the keyboard after losing it.
183  * We don't reset the locked group, this should survive a VT switch, etc. The
184  * locked modifiers are reset according to the keyboard LEDs.
185  */
186 void uxkb_dev_reset(struct uterm_input_dev *dev, const unsigned long *ledbits)
187 {
188         unsigned int i;
189         struct xkb_state *state;
190         static const struct {
191                 int led;
192                 const char *name;
193         } led_names[] = {
194                 { LED_NUML, XKB_LED_NAME_NUM },
195                 { LED_CAPSL, XKB_LED_NAME_CAPS },
196                 { LED_SCROLLL, XKB_LED_NAME_SCROLL },
197         };
198
199         /* TODO: Urghs, while the input device was closed we might have missed
200          * some events that affect internal state. As xkbcommon does not provide
201          * a way to reset the internal state, we simply recreate the state. This
202          * should have the same effect.
203          * It also has a bug that if the CTRL-Release event is skipped, then
204          * every further release will never perform a _real_ release. Kind of
205          * buggy so we should fix it upstream. */
206         state = xkb_state_new(dev->input->keymap);
207         if (!state) {
208                 log_warning("cannot recreate xkb-state");
209                 return;
210         }
211         xkb_state_unref(dev->state);
212         dev->state = state;
213
214         for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
215                 if (!input_bit_is_set(ledbits, led_names[i].led))
216                         continue;
217
218                 /*
219                  * TODO: Add support in xkbcommon for setting the led state,
220                  * and updating the modifier state accordingly. E.g., something
221                  * like this:
222                  *      xkb_state_led_name_set_active(state, led_names[i].led);
223                  */
224         }
225 }