1/* swc: libswc/keyboard.c
2 *
3 * Copyright (c) 2013-2020 Michael Forney
4 *
5 * Based in part upon input.c from weston, which is:
6 *
7 * Copyright © 2013 Intel Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28#include "keyboard.h"
29#include "compositor.h"
30#include "internal.h"
31#include "surface.h"
32#include "swc.h"
33#include "util.h"
34
35#include <assert.h>
36#include <fcntl.h>
37#include <limits.h>
38#include <stdio.h>
39#include <string.h>
40#include <sys/mman.h>
41#include <unistd.h>
42#include <xkbcommon/xkbcommon.h>
43
44static const int repeat_delay = 500, repeat_rate = 40;
45
46static void
47enter(struct input_focus_handler *handler,
48 struct wl_list *resources,
49 struct compositor_view *view)
50{
51 struct keyboard *keyboard =
52 wl_container_of(handler, keyboard, focus_handler);
53 struct keyboard_modifier_state *state = &keyboard->modifier_state;
54 struct wl_resource *resource;
55 uint32_t serial;
56
57 serial = wl_display_next_serial(swc.display);
58 wl_resource_for_each(resource, resources)
59 {
60 wl_keyboard_send_modifiers(resource,
61 serial,
62 state->depressed,
63 state->locked,
64 state->latched,
65 state->group);
66 wl_keyboard_send_enter(
67 resource, serial, view->surface->resource, &keyboard->client_keys);
68 }
69}
70
71static void
72leave(struct input_focus_handler *handler,
73 struct wl_list *resources,
74 struct compositor_view *view)
75{
76 struct wl_resource *resource;
77 uint32_t serial;
78
79 serial = wl_display_next_serial(swc.display);
80 wl_resource_for_each(resource, resources)
81 wl_keyboard_send_leave(resource, serial, view->surface->resource);
82}
83
84static bool
85client_handle_key(struct keyboard *keyboard,
86 uint32_t time,
87 struct key *key,
88 uint32_t state)
89{
90 uint32_t *value;
91 struct wl_resource *resource;
92
93 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
94 if (!(value = wl_array_add(&keyboard->client_keys, sizeof(*value)))) {
95 return false;
96 }
97
98 *value = key->press.value;
99 } else {
100 wl_array_for_each(value, &keyboard->client_keys)
101 {
102 if (*value == key->press.value) {
103 array_remove(&keyboard->client_keys, value, sizeof(*value));
104 break;
105 }
106 }
107 }
108
109 wl_resource_for_each(resource, &keyboard->focus.active)
110 wl_keyboard_send_key(
111 resource, key->press.serial, time, key->press.value, state);
112 return true;
113}
114
115static bool
116client_handle_modifiers(struct keyboard *keyboard,
117 const struct keyboard_modifier_state *state)
118{
119 struct wl_resource *resource;
120 uint32_t serial;
121
122 if (wl_list_empty(&keyboard->focus.active)) {
123 return false;
124 }
125
126 serial = wl_display_next_serial(swc.display);
127 wl_resource_for_each(resource, &keyboard->focus.active)
128 wl_keyboard_send_modifiers(resource,
129 serial,
130 state->depressed,
131 state->locked,
132 state->latched,
133 state->group);
134 return true;
135}
136
137static bool
138update_keymap(struct xkb *xkb)
139{
140 char keymap_path[PATH_MAX];
141 const char *keymap_directory;
142 char *keymap_string;
143 int ret;
144
145 if (!(keymap_directory = getenv("XDG_RUNTIME_DIR"))) {
146 keymap_directory = "/tmp";
147 }
148
149 xkb->indices.ctrl =
150 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_CTRL);
151 xkb->indices.alt =
152 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_ALT);
153 xkb->indices.super =
154 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_LOGO);
155 xkb->indices.shift =
156 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_SHIFT);
157
158 /* In order to send the keymap to clients, we must first convert it to a
159 * string and then mmap it to a file. */
160 keymap_string =
161 xkb_keymap_get_as_string(xkb->keymap.map, XKB_KEYMAP_FORMAT_TEXT_V1);
162
163 if (!keymap_string) {
164 WARNING("Could not get XKB keymap as a string\n");
165 goto error0;
166 }
167
168 ret = snprintf(keymap_path,
169 sizeof(keymap_path),
170 "%s/swc-xkb-keymap-XXXXXX",
171 keymap_directory);
172 if (ret < 0 || (size_t)ret >= sizeof(keymap_path)) {
173 WARNING("Could not determine XKB keymap path\n");
174 goto error1;
175 }
176
177 xkb->keymap.size = strlen(keymap_string) + 1;
178 xkb->keymap.fd = mkostemp(keymap_path, O_CLOEXEC);
179
180 if (xkb->keymap.fd == -1) {
181 WARNING("Could not create XKB keymap file\n");
182 goto error1;
183 }
184
185 unlink(keymap_path);
186
187#ifdef __linux__
188 /* preallocate if available */
189 if (posix_fallocate(xkb->keymap.fd, 0, xkb->keymap.size) != 0 &&
190 ftruncate(xkb->keymap.fd, xkb->keymap.size) != 0) {
191 WARNING("Could not resize XKB keymap file\n");
192 goto error2;
193 }
194#else
195 /* otherwise, ftruncate() is fine */
196 if (ftruncate(xkb->keymap.fd, xkb->keymap.size) != 0) {
197 WARNING("Could not resize XKB keymap file\n");
198 goto error2;
199 }
200#endif
201
202 xkb->keymap.area = mmap(NULL,
203 xkb->keymap.size,
204 PROT_READ | PROT_WRITE,
205 MAP_SHARED,
206 xkb->keymap.fd,
207 0);
208
209 if (xkb->keymap.area == MAP_FAILED) {
210 WARNING("Could not mmap XKB keymap string\n");
211 goto error2;
212 }
213
214 strcpy(xkb->keymap.area, keymap_string);
215 free(keymap_string);
216
217 return true;
218
219error2:
220 close(xkb->keymap.fd);
221error1:
222 free(keymap_string);
223error0:
224 return false;
225}
226
227struct keyboard *
228keyboard_create(struct xkb_rule_names *names)
229{
230 struct keyboard *keyboard;
231 struct xkb *xkb;
232
233 keyboard = malloc(sizeof(*keyboard));
234 if (!keyboard) {
235 goto error0;
236 }
237
238 xkb = &keyboard->xkb;
239 if (!(xkb->context = xkb_context_new(0))) {
240 ERROR("Could not create XKB context\n");
241 goto error1;
242 }
243
244 if (!(xkb->keymap.map =
245 xkb_keymap_new_from_names(xkb->context, names, 0))) {
246 ERROR("Could not create XKB keymap\n");
247 goto error2;
248 }
249
250 if (!(xkb->state = xkb_state_new(xkb->keymap.map))) {
251 ERROR("Could not create XKB state\n");
252 goto error3;
253 }
254
255 if (!update_keymap(xkb)) {
256 ERROR("Could not update XKB keymap\n");
257 goto error4;
258 }
259
260 if (!input_focus_initialize(&keyboard->focus, &keyboard->focus_handler)) {
261 goto error4;
262 }
263
264 keyboard->modifier_state = (struct keyboard_modifier_state){0};
265 keyboard->modifiers = 0;
266 keyboard->focus_handler.enter = &enter;
267 keyboard->focus_handler.leave = &leave;
268 keyboard->client_handler.key = &client_handle_key;
269 keyboard->client_handler.modifiers = &client_handle_modifiers;
270 wl_array_init(&keyboard->client_keys);
271 wl_array_init(&keyboard->keys);
272 wl_list_init(&keyboard->handlers);
273 wl_list_insert(&keyboard->handlers, &keyboard->client_handler.link);
274
275 return keyboard;
276
277error4:
278 xkb_state_unref(keyboard->xkb.state);
279error3:
280 xkb_keymap_unref(keyboard->xkb.keymap.map);
281error2:
282 xkb_context_unref(keyboard->xkb.context);
283error1:
284 free(keyboard);
285error0:
286 return false;
287}
288
289void
290keyboard_destroy(struct keyboard *keyboard)
291{
292 wl_array_release(&keyboard->client_keys);
293 wl_array_release(&keyboard->keys);
294 input_focus_finalize(&keyboard->focus);
295 munmap(keyboard->xkb.keymap.area, keyboard->xkb.keymap.size);
296 close(keyboard->xkb.keymap.fd);
297 xkb_state_unref(keyboard->xkb.state);
298 xkb_keymap_unref(keyboard->xkb.keymap.map);
299 xkb_context_unref(keyboard->xkb.context);
300 free(keyboard);
301}
302
303bool
304keyboard_reset(struct keyboard *keyboard)
305{
306 struct key *key;
307 uint32_t time = get_time();
308 struct xkb_state *state;
309
310 /* Send simulated key release events for all current key handlers. */
311 wl_array_for_each(key, &keyboard->keys)
312 {
313 if (key->handler) {
314 key->press.serial = wl_display_next_serial(swc.display);
315 key->handler->key(
316 keyboard, time, key, WL_KEYBOARD_KEY_STATE_RELEASED);
317 /* Don't bother updating the XKB state because we will be resetting
318 * it later on and it is unlikely that a key handler cares about the
319 * keyboard state for release events. */
320 }
321 }
322
323 /* We should have removed all the client keys by calling the client key
324 * handler. */
325 assert(keyboard->client_keys.size == 0);
326 keyboard->keys.size = 0;
327 keyboard->modifier_state = (struct keyboard_modifier_state){0};
328 keyboard->modifiers = 0;
329
330 if (!(state = xkb_state_new(keyboard->xkb.keymap.map))) {
331 ERROR("Failed to allocate new XKB state\n");
332 return false;
333 }
334
335 xkb_state_unref(keyboard->xkb.state);
336 keyboard->xkb.state = state;
337
338 return true;
339}
340
341/**
342 * Sets the focus of the keyboard to the specified surface.
343 */
344void
345keyboard_set_focus(struct keyboard *keyboard, struct compositor_view *view)
346{
347 input_focus_set(&keyboard->focus, view);
348}
349
350static const struct wl_keyboard_interface keyboard_impl = {
351 .release = destroy_resource,
352};
353
354static void
355unbind(struct wl_resource *resource)
356{
357 struct keyboard *keyboard = wl_resource_get_user_data(resource);
358 input_focus_remove_resource(&keyboard->focus, resource);
359}
360
361struct wl_resource *
362keyboard_bind(struct keyboard *keyboard,
363 struct wl_client *client,
364 uint32_t version,
365 uint32_t id)
366{
367 struct wl_resource *client_resource;
368
369 client_resource =
370 wl_resource_create(client, &wl_keyboard_interface, version, id);
371 if (!client_resource) {
372 return NULL;
373 }
374 wl_resource_set_implementation(
375 client_resource, &keyboard_impl, keyboard, &unbind);
376
377 /* Subtract one to remove terminating NULL character. */
378 wl_keyboard_send_keymap(client_resource,
379 WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
380 keyboard->xkb.keymap.fd,
381 keyboard->xkb.keymap.size - 1);
382
383 input_focus_add_resource(&keyboard->focus, client_resource);
384
385 if (version >= 4) {
386 wl_keyboard_send_repeat_info(
387 client_resource, repeat_rate, repeat_delay);
388 }
389
390 return client_resource;
391}
392
393void
394keyboard_handle_key(struct keyboard *keyboard,
395 uint32_t time,
396 uint32_t value,
397 uint32_t state)
398{
399 struct key *key;
400 struct keyboard_modifier_state modifier_state;
401 enum xkb_key_direction direction;
402 struct xkb *xkb = &keyboard->xkb;
403 struct keyboard_handler *handler;
404 uint32_t serial;
405
406 serial = wl_display_next_serial(swc.display);
407
408 /* First handle key release events associated with a particular handler. */
409 wl_array_for_each(key, &keyboard->keys)
410 {
411 if (key->press.value == value) {
412 /* Ignore repeat events. */
413 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
414 return;
415 }
416
417 if (key->handler) {
418 key->press.serial = serial;
419 key->handler->key(keyboard, time, key, state);
420 }
421
422 array_remove(&keyboard->keys, key, sizeof(*key));
423 goto update_xkb_state;
424 }
425 }
426
427 /* If we get a unpaired release event, just ignore it. */
428 if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
429 return;
430 }
431
432 if (!(key = wl_array_add(&keyboard->keys, sizeof(*key)))) {
433 goto update_xkb_state;
434 }
435
436 key->press.value = value;
437 key->press.serial = serial;
438 key->handler = NULL;
439
440 /* Go through handlers to see if any will accept this key event. */
441 wl_list_for_each(handler, &keyboard->handlers, link)
442 {
443 if (handler->key && handler->key(keyboard, time, key, state)) {
444 key->handler = handler;
445 break;
446 }
447 }
448
449 /* Update XKB state. */
450update_xkb_state:
451 direction =
452 state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP;
453 xkb_state_update_key(xkb->state, XKB_KEY(value), direction);
454
455 modifier_state.depressed =
456 xkb_state_serialize_mods(xkb->state, XKB_STATE_DEPRESSED);
457 modifier_state.latched =
458 xkb_state_serialize_mods(xkb->state, XKB_STATE_LATCHED);
459 modifier_state.locked =
460 xkb_state_serialize_mods(xkb->state, XKB_STATE_LOCKED);
461 modifier_state.group =
462 xkb_state_serialize_layout(xkb->state, XKB_STATE_LAYOUT_EFFECTIVE);
463
464 if (modifier_state.depressed != keyboard->modifier_state.depressed ||
465 modifier_state.latched != keyboard->modifier_state.latched ||
466 modifier_state.locked != keyboard->modifier_state.locked ||
467 modifier_state.group != keyboard->modifier_state.group) {
468 uint32_t mods_active =
469 modifier_state.depressed | modifier_state.latched;
470
471 /* Update keyboard modifier state. */
472 keyboard->modifier_state = modifier_state;
473 keyboard->modifiers = 0;
474 if (mods_active & (1 << keyboard->xkb.indices.ctrl)) {
475 keyboard->modifiers |= SWC_MOD_CTRL;
476 }
477 if (mods_active & (1 << keyboard->xkb.indices.alt)) {
478 keyboard->modifiers |= SWC_MOD_ALT;
479 }
480 if (mods_active & (1 << keyboard->xkb.indices.super)) {
481 keyboard->modifiers |= SWC_MOD_LOGO;
482 }
483 if (mods_active & (1 << keyboard->xkb.indices.shift)) {
484 keyboard->modifiers |= SWC_MOD_SHIFT;
485 }
486
487 /* Run any modifier handlers. */
488 wl_list_for_each(handler, &keyboard->handlers, link)
489 {
490 if (handler->modifiers) {
491 handler->modifiers(keyboard, &modifier_state);
492 }
493 }
494 }
495}