2 * uterm - Linux User-Space Terminal
4 * Copyright (c) 2011 Ran Benita <ran234@gmail.com>
5 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
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:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
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.
29 #include <linux/input.h>
33 #include <xkbcommon/xkbcommon.h>
37 #include "uterm_input.h"
39 #define LOG_SUBSYSTEM "input_uxkb"
41 int uxkb_desc_init(struct uterm_input *input,
47 struct xkb_rule_names rmlvo = {
55 input->ctx = xkb_context_new(0);
57 log_error("cannot create XKB context");
61 input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
63 log_warn("failed to create keymap (%s, %s, %s), "
64 "reverting to default US keymap",
65 layout, variant, options);
71 input->keymap = xkb_map_new_from_names(input->ctx, &rmlvo, 0);
73 log_warn("failed to create XKB keymap");
79 log_debug("new keyboard description (%s, %s, %s)",
80 layout, variant, options);
84 xkb_context_unref(input->ctx);
88 void uxkb_desc_destroy(struct uterm_input *input)
90 xkb_map_unref(input->keymap);
91 xkb_context_unref(input->ctx);
94 int uxkb_dev_init(struct uterm_input_dev *dev)
96 dev->state = xkb_state_new(dev->input->keymap);
103 void uxkb_dev_destroy(struct uterm_input_dev *dev)
105 xkb_state_unref(dev->state);
108 #define EVDEV_KEYCODE_OFFSET 8
115 int uxkb_dev_process(struct uterm_input_dev *dev,
116 uint16_t key_state, uint16_t code)
118 struct xkb_state *state;
119 struct xkb_keymap *keymap;
120 xkb_keycode_t keycode;
121 const xkb_keysym_t *keysyms;
126 keymap = xkb_state_get_map(state);
127 keycode = code + EVDEV_KEYCODE_OFFSET;
129 num_keysyms = xkb_key_get_syms(state, keycode, &keysyms);
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);
136 if (key_state == KEY_RELEASED)
139 if (key_state == KEY_REPEATED && !xkb_key_repeats(keymap, keycode))
142 if (num_keysyms <= 0)
145 if (dev->num_syms < num_keysyms) {
146 tmp = realloc(dev->event.keysyms,
147 sizeof(uint32_t) * num_keysyms);
149 log_warning("cannot reallocate keysym buffer");
152 dev->event.keysyms = tmp;
154 tmp = realloc(dev->event.codepoints,
155 sizeof(uint32_t) * num_keysyms);
157 log_warning("cannot reallocate codepoints buffer");
160 dev->event.codepoints = tmp;
162 dev->num_syms = num_keysyms;
165 dev->event.handled = false;
166 dev->event.keycode = code;
167 dev->event.mods = shl_get_xkb_mods(state);
168 dev->event.num_syms = num_keysyms;
169 memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms);
171 for (i = 0; i < num_keysyms; ++i) {
172 dev->event.codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
173 if (!dev->event.codepoints[i])
174 dev->event.codepoints[i] = UTERM_INPUT_INVALID;
181 * Call this when we regain control of the keyboard after losing it.
182 * We don't reset the locked group, this should survive a VT switch, etc. The
183 * locked modifiers are reset according to the keyboard LEDs.
185 void uxkb_dev_reset(struct uterm_input_dev *dev, const unsigned long *ledbits)
188 struct xkb_state *state;
189 static const struct {
193 { LED_NUML, XKB_LED_NAME_NUM },
194 { LED_CAPSL, XKB_LED_NAME_CAPS },
195 { LED_SCROLLL, XKB_LED_NAME_SCROLL },
198 /* TODO: Urghs, while the input device was closed we might have missed
199 * some events that affect internal state. As xkbcommon does not provide
200 * a way to reset the internal state, we simply recreate the state. This
201 * should have the same effect.
202 * It also has a bug that if the CTRL-Release event is skipped, then
203 * every further release will never perform a _real_ release. Kind of
204 * buggy so we should fix it upstream. */
205 state = xkb_state_new(dev->input->keymap);
207 log_warning("cannot recreate xkb-state");
210 xkb_state_unref(dev->state);
213 for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
214 if (!input_bit_is_set(ledbits, led_names[i].led))
218 * TODO: Add support in xkbcommon for setting the led state,
219 * and updating the modifier state accordingly. E.g., something
221 * xkb_state_led_name_set_active(state, led_names[i].led);