main neuswc / libswc / keyboard.c
  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}