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
44/* Keyboard repeat rate (characters per second) and delay (ms)
45 * defaults, used if compositor didnt set them.
46 */
47__attribute__((visibility("default")))
48int32_t swc_repeat_rate = 40, swc_repeat_delay = 500;
49
50static void
51enter(struct input_focus_handler *handler,
52 struct wl_list *resources,
53 struct compositor_view *view)
54{
55 struct keyboard *keyboard =
56 wl_container_of(handler, keyboard, focus_handler);
57 struct keyboard_modifier_state *state = &keyboard->modifier_state;
58 struct wl_resource *resource;
59 uint32_t serial;
60
61 serial = wl_display_next_serial(swc.display);
62 wl_resource_for_each(resource, resources)
63 {
64 wl_keyboard_send_modifiers(resource,
65 serial,
66 state->depressed,
67 state->locked,
68 state->latched,
69 state->group);
70 wl_keyboard_send_enter(
71 resource, serial, view->surface->resource, &keyboard->client_keys);
72 }
73}
74
75static void
76leave(struct input_focus_handler *handler,
77 struct wl_list *resources,
78 struct compositor_view *view)
79{
80 struct wl_resource *resource;
81 uint32_t serial;
82
83 serial = wl_display_next_serial(swc.display);
84 wl_resource_for_each(resource, resources)
85 wl_keyboard_send_leave(resource, serial, view->surface->resource);
86}
87
88static bool
89client_handle_key(struct keyboard *keyboard,
90 uint32_t time,
91 struct key *key,
92 uint32_t state)
93{
94 uint32_t *value;
95 struct wl_resource *resource;
96
97 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
98 if (!(value = wl_array_add(&keyboard->client_keys, sizeof(*value)))) {
99 return false;
100 }
101
102 *value = key->press.value;
103 } else {
104 wl_array_for_each(value, &keyboard->client_keys)
105 {
106 if (*value == key->press.value) {
107 array_remove(&keyboard->client_keys, value, sizeof(*value));
108 break;
109 }
110 }
111 }
112
113 wl_resource_for_each(resource, &keyboard->focus.active)
114 wl_keyboard_send_key(
115 resource, key->press.serial, time, key->press.value, state);
116 return true;
117}
118
119static bool
120client_handle_modifiers(struct keyboard *keyboard,
121 const struct keyboard_modifier_state *state)
122{
123 struct wl_resource *resource;
124 uint32_t serial;
125
126 if (wl_list_empty(&keyboard->focus.active)) {
127 return false;
128 }
129
130 serial = wl_display_next_serial(swc.display);
131 wl_resource_for_each(resource, &keyboard->focus.active)
132 wl_keyboard_send_modifiers(resource,
133 serial,
134 state->depressed,
135 state->locked,
136 state->latched,
137 state->group);
138 return true;
139}
140
141static bool
142update_keymap(struct xkb *xkb)
143{
144 char keymap_path[PATH_MAX];
145 const char *keymap_directory;
146 char *keymap_string;
147 int ret;
148
149 if (!(keymap_directory = getenv("XDG_RUNTIME_DIR"))) {
150 keymap_directory = "/tmp";
151 }
152
153 xkb->indices.ctrl =
154 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_CTRL);
155 xkb->indices.alt =
156 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_ALT);
157 xkb->indices.super =
158 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_LOGO);
159 xkb->indices.shift =
160 xkb_keymap_mod_get_index(xkb->keymap.map, XKB_MOD_NAME_SHIFT);
161
162 /* In order to send the keymap to clients, we must first convert it to a
163 * string and then mmap it to a file. */
164 keymap_string =
165 xkb_keymap_get_as_string(xkb->keymap.map, XKB_KEYMAP_FORMAT_TEXT_V1);
166
167 if (!keymap_string) {
168 WARNING("Could not get XKB keymap as a string\n");
169 goto error0;
170 }
171
172 ret = snprintf(keymap_path,
173 sizeof(keymap_path),
174 "%s/swc-xkb-keymap-XXXXXX",
175 keymap_directory);
176 if (ret < 0 || (size_t)ret >= sizeof(keymap_path)) {
177 WARNING("Could not determine XKB keymap path\n");
178 goto error1;
179 }
180
181 xkb->keymap.size = strlen(keymap_string) + 1;
182 xkb->keymap.fd = mkostemp(keymap_path, O_CLOEXEC);
183
184 if (xkb->keymap.fd == -1) {
185 WARNING("Could not create XKB keymap file\n");
186 goto error1;
187 }
188
189 unlink(keymap_path);
190
191#ifdef __linux__
192 /* preallocate if available */
193 if (posix_fallocate(xkb->keymap.fd, 0, xkb->keymap.size) != 0 &&
194 ftruncate(xkb->keymap.fd, xkb->keymap.size) != 0) {
195 WARNING("Could not resize XKB keymap file\n");
196 goto error2;
197 }
198#else
199 /* otherwise, ftruncate() is fine */
200 if (ftruncate(xkb->keymap.fd, xkb->keymap.size) != 0) {
201 WARNING("Could not resize XKB keymap file\n");
202 goto error2;
203 }
204#endif
205
206 xkb->keymap.area = mmap(NULL,
207 xkb->keymap.size,
208 PROT_READ | PROT_WRITE,
209 MAP_SHARED,
210 xkb->keymap.fd,
211 0);
212
213 if (xkb->keymap.area == MAP_FAILED) {
214 WARNING("Could not mmap XKB keymap string\n");
215 goto error2;
216 }
217
218 strcpy(xkb->keymap.area, keymap_string);
219 free(keymap_string);
220
221 return true;
222
223error2:
224 close(xkb->keymap.fd);
225error1:
226 free(keymap_string);
227error0:
228 return false;
229}
230
231struct keyboard *
232keyboard_create(struct xkb_rule_names *names)
233{
234 struct keyboard *keyboard;
235 struct xkb *xkb;
236
237 keyboard = malloc(sizeof(*keyboard));
238 if (!keyboard) {
239 goto error0;
240 }
241
242 xkb = &keyboard->xkb;
243 if (!(xkb->context = xkb_context_new(0))) {
244 ERROR("Could not create XKB context\n");
245 goto error1;
246 }
247
248 if (!(xkb->keymap.map =
249 xkb_keymap_new_from_names(xkb->context, names, 0))) {
250 ERROR("Could not create XKB keymap\n");
251 goto error2;
252 }
253
254 if (!(xkb->state = xkb_state_new(xkb->keymap.map))) {
255 ERROR("Could not create XKB state\n");
256 goto error3;
257 }
258
259 if (!update_keymap(xkb)) {
260 ERROR("Could not update XKB keymap\n");
261 goto error4;
262 }
263
264 if (!input_focus_initialize(&keyboard->focus, &keyboard->focus_handler)) {
265 goto error4;
266 }
267
268 keyboard->modifier_state = (struct keyboard_modifier_state){0};
269 keyboard->modifiers = 0;
270 keyboard->focus_handler.enter = &enter;
271 keyboard->focus_handler.leave = &leave;
272 keyboard->client_handler.key = &client_handle_key;
273 keyboard->client_handler.modifiers = &client_handle_modifiers;
274 wl_array_init(&keyboard->client_keys);
275 wl_array_init(&keyboard->keys);
276 wl_list_init(&keyboard->handlers);
277 wl_list_insert(&keyboard->handlers, &keyboard->client_handler.link);
278
279 return keyboard;
280
281error4:
282 xkb_state_unref(keyboard->xkb.state);
283error3:
284 xkb_keymap_unref(keyboard->xkb.keymap.map);
285error2:
286 xkb_context_unref(keyboard->xkb.context);
287error1:
288 free(keyboard);
289error0:
290 return NULL;
291}
292
293void
294keyboard_destroy(struct keyboard *keyboard)
295{
296 wl_array_release(&keyboard->client_keys);
297 wl_array_release(&keyboard->keys);
298 input_focus_finalize(&keyboard->focus);
299 munmap(keyboard->xkb.keymap.area, keyboard->xkb.keymap.size);
300 close(keyboard->xkb.keymap.fd);
301 xkb_state_unref(keyboard->xkb.state);
302 xkb_keymap_unref(keyboard->xkb.keymap.map);
303 xkb_context_unref(keyboard->xkb.context);
304 free(keyboard);
305}
306
307bool
308keyboard_reset(struct keyboard *keyboard)
309{
310 struct key *key;
311 uint32_t time = get_time();
312 struct xkb_state *state;
313
314 /* Send simulated key release events for all current key handlers. */
315 wl_array_for_each(key, &keyboard->keys)
316 {
317 if (key->handler) {
318 key->press.serial = wl_display_next_serial(swc.display);
319 key->handler->key(
320 keyboard, time, key, WL_KEYBOARD_KEY_STATE_RELEASED);
321 /* Don't bother updating the XKB state because we will be resetting
322 * it later on and it is unlikely that a key handler cares about the
323 * keyboard state for release events. */
324 }
325 }
326
327 /* We should have removed all the client keys by calling the client key
328 * handler. */
329 assert(keyboard->client_keys.size == 0);
330 keyboard->keys.size = 0;
331 keyboard->modifier_state = (struct keyboard_modifier_state){0};
332 keyboard->modifiers = 0;
333
334 if (!(state = xkb_state_new(keyboard->xkb.keymap.map))) {
335 ERROR("Failed to allocate new XKB state\n");
336 return false;
337 }
338
339 xkb_state_unref(keyboard->xkb.state);
340 keyboard->xkb.state = state;
341
342 return true;
343}
344
345/**
346 * Sets the focus of the keyboard to the specified surface.
347 */
348void
349keyboard_set_focus(struct keyboard *keyboard, struct compositor_view *view)
350{
351 input_focus_set(&keyboard->focus, view);
352}
353
354static const struct wl_keyboard_interface keyboard_impl = {
355 .release = destroy_resource,
356};
357
358static void
359unbind(struct wl_resource *resource)
360{
361 struct keyboard *keyboard = wl_resource_get_user_data(resource);
362 input_focus_remove_resource(&keyboard->focus, resource);
363}
364
365struct wl_resource *
366keyboard_bind(struct keyboard *keyboard,
367 struct wl_client *client,
368 uint32_t version,
369 uint32_t id)
370{
371 struct wl_resource *client_resource;
372
373 client_resource =
374 wl_resource_create(client, &wl_keyboard_interface, version, id);
375 if (!client_resource) {
376 return NULL;
377 }
378 wl_resource_set_implementation(
379 client_resource, &keyboard_impl, keyboard, &unbind);
380
381 /* Subtract one to remove terminating NULL character. */
382 wl_keyboard_send_keymap(client_resource,
383 WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
384 keyboard->xkb.keymap.fd,
385 keyboard->xkb.keymap.size - 1);
386
387 input_focus_add_resource(&keyboard->focus, client_resource);
388
389 if (version >= 4) {
390 wl_keyboard_send_repeat_info(
391 client_resource, swc_repeat_rate, swc_repeat_delay);
392 }
393
394 return client_resource;
395}
396
397void
398keyboard_handle_key(struct keyboard *keyboard,
399 uint32_t time,
400 uint32_t value,
401 uint32_t state)
402{
403 struct key *key;
404 struct keyboard_modifier_state modifier_state;
405 enum xkb_key_direction direction;
406 struct xkb *xkb = &keyboard->xkb;
407 struct keyboard_handler *handler;
408 uint32_t serial;
409
410 serial = wl_display_next_serial(swc.display);
411
412 /* First handle key release events associated with a particular handler. */
413 wl_array_for_each(key, &keyboard->keys)
414 {
415 if (key->press.value == value) {
416 /* Ignore repeat events. */
417 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
418 return;
419 }
420
421 if (key->handler) {
422 key->press.serial = serial;
423 key->handler->key(keyboard, time, key, state);
424 }
425
426 array_remove(&keyboard->keys, key, sizeof(*key));
427 goto update_xkb_state;
428 }
429 }
430
431 /* If we get a unpaired release event, just ignore it. */
432 if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
433 return;
434 }
435
436 if (!(key = wl_array_add(&keyboard->keys, sizeof(*key)))) {
437 goto update_xkb_state;
438 }
439
440 key->press.value = value;
441 key->press.serial = serial;
442 key->handler = NULL;
443
444 /* Go through handlers to see if any will accept this key event. */
445 wl_list_for_each(handler, &keyboard->handlers, link)
446 {
447 if (handler->key && handler->key(keyboard, time, key, state)) {
448 key->handler = handler;
449 break;
450 }
451 }
452
453 /* Update XKB state. */
454update_xkb_state:
455 direction =
456 state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP;
457 xkb_state_update_key(xkb->state, XKB_KEY(value), direction);
458
459 modifier_state.depressed =
460 xkb_state_serialize_mods(xkb->state, XKB_STATE_DEPRESSED);
461 modifier_state.latched =
462 xkb_state_serialize_mods(xkb->state, XKB_STATE_LATCHED);
463 modifier_state.locked =
464 xkb_state_serialize_mods(xkb->state, XKB_STATE_LOCKED);
465 modifier_state.group =
466 xkb_state_serialize_layout(xkb->state, XKB_STATE_LAYOUT_EFFECTIVE);
467
468 if (modifier_state.depressed != keyboard->modifier_state.depressed ||
469 modifier_state.latched != keyboard->modifier_state.latched ||
470 modifier_state.locked != keyboard->modifier_state.locked ||
471 modifier_state.group != keyboard->modifier_state.group) {
472 uint32_t mods_active =
473 modifier_state.depressed | modifier_state.latched;
474
475 /* Update keyboard modifier state. */
476 keyboard->modifier_state = modifier_state;
477 keyboard->modifiers = 0;
478 if (mods_active & (1 << keyboard->xkb.indices.ctrl)) {
479 keyboard->modifiers |= SWC_MOD_CTRL;
480 }
481 if (mods_active & (1 << keyboard->xkb.indices.alt)) {
482 keyboard->modifiers |= SWC_MOD_ALT;
483 }
484 if (mods_active & (1 << keyboard->xkb.indices.super)) {
485 keyboard->modifiers |= SWC_MOD_LOGO;
486 }
487 if (mods_active & (1 << keyboard->xkb.indices.shift)) {
488 keyboard->modifiers |= SWC_MOD_SHIFT;
489 }
490
491 /* Run any modifier handlers. */
492 wl_list_for_each(handler, &keyboard->handlers, link)
493 {
494 if (handler->modifiers) {
495 handler->modifiers(keyboard, &modifier_state);
496 }
497 }
498 }
499}