main shrub/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
 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}