swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

keyboard.c (12506B)


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