1 /*
2  * Copyright (c) 2019 - 2020 Andri Yngvason
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  *
16  * Acknowledgements: Reading Josef Gajdusek's wvnc code helped me understand
17  * how to use the xkbcommon API to interface with the wayland virtual keyboard
18  * interface.
19  */
20 
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <wayland-client-protocol.h>
27 #include <xkbcommon/xkbcommon-keysyms.h>
28 #include <xkbcommon/xkbcommon.h>
29 #include <wayland-client.h>
30 
31 #include "virtual-keyboard-unstable-v1.h"
32 #include "keyboard.h"
33 #include "shm.h"
34 #include "logging.h"
35 #include "intset.h"
36 
37 #define MAYBE_UNUSED __attribute__((unused))
38 
39 struct table_entry {
40 	xkb_keysym_t symbol;
41 	xkb_keycode_t code;
42 	int level;
43 };
44 
45 struct kb_mods {
46 	xkb_mod_mask_t depressed, latched, locked;
47 };
48 
append_entry(struct keyboard * self,xkb_keysym_t symbol,xkb_keycode_t code,int level)49 static void append_entry(struct keyboard* self, xkb_keysym_t symbol,
50                          xkb_keycode_t code, int level)
51 {
52 	if (self->lookup_table_size <= self->lookup_table_length) {
53 		size_t new_size = self->lookup_table_size * 2;
54 		struct table_entry* table =
55 			realloc(self->lookup_table, new_size * sizeof(*table));
56 		if (!table)
57 			return; // TODO: Report this
58 
59 		self->lookup_table_size = new_size;
60 		self->lookup_table = table;
61 	}
62 
63 	struct table_entry* entry =
64 		&self->lookup_table[self->lookup_table_length++];
65 
66 	entry->symbol = symbol;
67 	entry->code = code;
68 	entry->level = level;
69 }
70 
key_iter(struct xkb_keymap * map,xkb_keycode_t code,void * userdata)71 static void key_iter(struct xkb_keymap* map, xkb_keycode_t code, void* userdata)
72 {
73 	struct keyboard* self = userdata;
74 
75 	size_t n_levels = xkb_keymap_num_levels_for_key(map, code, 0);
76 
77 	for (size_t level = 0; level < n_levels; level++) {
78 		const xkb_keysym_t* symbols;
79 		size_t n_syms = xkb_keymap_key_get_syms_by_level(map, code, 0,
80 				                                 level,
81 				                                 &symbols);
82 
83 		for (size_t sym_idx = 0; sym_idx < n_syms; sym_idx++)
84 			append_entry(self, symbols[sym_idx], code, level);
85 	}
86 }
87 
compare_symbols(const void * a,const void * b)88 static int compare_symbols(const void* a, const void* b)
89 {
90 	const struct table_entry* x = a;
91 	const struct table_entry* y = b;
92 
93 	if (x->symbol == y->symbol)
94 		return x->level < y->level ? -1 : x->level > y->level;
95 
96 	return x->symbol < y->symbol ? -1 : x->symbol > y->symbol;
97 }
98 
compare_symbols2(const void * a,const void * b)99 static int compare_symbols2(const void* a, const void* b)
100 {
101 	const struct table_entry* x = a;
102 	const struct table_entry* y = b;
103 
104 	return x->symbol < y->symbol ? -1 : x->symbol > y->symbol;
105 }
106 
create_lookup_table(struct keyboard * self)107 static int create_lookup_table(struct keyboard* self)
108 {
109 	self->lookup_table_length = 0;
110 	self->lookup_table_size = 128;
111 
112 	self->lookup_table =
113 		malloc(self->lookup_table_size * sizeof(*self->lookup_table));
114 	if (!self->lookup_table)
115 		return -1;
116 
117 	xkb_keymap_key_for_each(self->keymap, key_iter, self);
118 
119 	qsort(self->lookup_table, self->lookup_table_length,
120 	      sizeof(*self->lookup_table), compare_symbols);
121 
122 	return 0;
123 }
124 
get_symbol_name(xkb_keysym_t sym,char * dst,size_t size)125 static char* get_symbol_name(xkb_keysym_t sym, char* dst, size_t size)
126 {
127 	if (xkb_keysym_get_name(sym, dst, size) >= 0)
128 		return dst;
129 
130 	snprintf(dst, size, "UNKNOWN (%x)", sym);
131 	return dst;
132 }
133 
keyboard__dump_entry(const struct keyboard * self,const struct table_entry * entry)134 static void keyboard__dump_entry(const struct keyboard* self,
135                                  const struct table_entry* entry)
136 {
137 	char sym_name[256];
138 	get_symbol_name(entry->symbol, sym_name, sizeof(sym_name));
139 
140 	const char* code_name MAYBE_UNUSED =
141 		xkb_keymap_key_get_name(self->keymap, entry->code);
142 
143 	bool is_pressed MAYBE_UNUSED =
144 		intset_is_set(&self->key_state, entry->code);
145 
146 	log_debug("symbol=%s level=%d code=%s %s\n", sym_name, entry->level,
147 	          code_name, is_pressed ? "pressed" : "released");
148 }
149 
keyboard_dump_lookup_table(const struct keyboard * self)150 void keyboard_dump_lookup_table(const struct keyboard* self)
151 {
152 	for (size_t i = 0; i < self->lookup_table_length; i++)
153 		keyboard__dump_entry(self, &self->lookup_table[i]);
154 }
155 
keyboard_init(struct keyboard * self,const struct xkb_rule_names * rule_names)156 int keyboard_init(struct keyboard* self, const struct xkb_rule_names* rule_names)
157 {
158 	self->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
159 	if (!self->context)
160 		return -1;
161 
162 	if (intset_init(&self->key_state, 0) < 0)
163 		goto key_state_failure;
164 
165 	self->keymap = xkb_keymap_new_from_names(self->context, rule_names, 0);
166 	if (!self->keymap)
167 		goto keymap_failure;
168 
169 	if (xkb_keymap_num_layouts(self->keymap) > 1)
170 		log_warning("Multiple keyboard layouts have been specified, but only one is supported.\n");
171 
172 	self->state = xkb_state_new(self->keymap);
173 	if (!self->state)
174 		goto state_failure;
175 
176 	if (create_lookup_table(self) < 0)
177 		goto table_failure;
178 
179 //	keyboard_dump_lookup_table(self);
180 
181 	char* keymap_string =
182 		xkb_keymap_get_as_string(self->keymap,
183 		                         XKB_KEYMAP_FORMAT_TEXT_V1);
184 	if (!keymap_string)
185 		goto keymap_string_failure;
186 
187 	size_t keymap_size = strlen(keymap_string) + 1;
188 
189 	int keymap_fd = shm_alloc_fd(keymap_size);
190 	if (keymap_fd < 0)
191 		goto fd_failure;
192 
193 	size_t written = 0;
194 	while (written < keymap_size) {
195 		ssize_t ret = write(keymap_fd, keymap_string + written, keymap_size - written);
196 		if (ret == -1 && errno == EINTR)
197 			continue;
198 		if (ret == -1)
199 			goto write_failure;
200 		written += ret;
201 	}
202 
203 	free(keymap_string);
204 
205 	zwp_virtual_keyboard_v1_keymap(self->virtual_keyboard,
206 	                               WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
207 	                               keymap_fd, keymap_size);
208 
209 	close(keymap_fd);
210 
211 	return 0;
212 
213 write_failure:
214 	close(keymap_fd);
215 fd_failure:
216 	free(keymap_string);
217 keymap_string_failure:
218 	free(self->lookup_table);
219 table_failure:
220 	xkb_state_unref(self->state);
221 state_failure:
222 	xkb_keymap_unref(self->keymap);
223 keymap_failure:
224 	intset_destroy(&self->key_state);
225 key_state_failure:
226 	xkb_context_unref(self->context);
227 	return -1;
228 }
229 
keyboard_destroy(struct keyboard * self)230 void keyboard_destroy(struct keyboard* self)
231 {
232 	free(self->lookup_table);
233 	xkb_state_unref(self->state);
234 	xkb_keymap_unref(self->keymap);
235 	intset_destroy(&self->key_state);
236 	xkb_context_unref(self->context);
237 }
238 
keyboard_find_symbol(const struct keyboard * self,xkb_keysym_t symbol)239 struct table_entry* keyboard_find_symbol(const struct keyboard* self,
240                                          xkb_keysym_t symbol)
241 {
242 	struct table_entry cmp = { .symbol = symbol };
243 
244 	struct table_entry* entry =
245 		bsearch(&cmp, self->lookup_table, self->lookup_table_length,
246 		        sizeof(*self->lookup_table), compare_symbols2);
247 
248 	if (!entry)
249 		return NULL;
250 
251 	while (entry != self->lookup_table && (entry - 1)->symbol == symbol)
252 		--entry;
253 
254 	return entry;
255 }
256 
keyboard_send_mods(struct keyboard * self)257 static void keyboard_send_mods(struct keyboard* self)
258 {
259 	xkb_mod_mask_t depressed, latched, locked, group;
260 
261 	depressed = xkb_state_serialize_mods(self->state, XKB_STATE_MODS_DEPRESSED);
262 	latched = xkb_state_serialize_mods(self->state, XKB_STATE_MODS_LATCHED);
263 	locked = xkb_state_serialize_mods(self->state, XKB_STATE_MODS_LOCKED);
264 	group = xkb_state_serialize_mods(self->state, XKB_STATE_MODS_EFFECTIVE);
265 
266 	zwp_virtual_keyboard_v1_modifiers(self->virtual_keyboard, depressed,
267 	                                  latched, locked, group);
268 }
269 
keyboard_apply_mods(struct keyboard * self,xkb_keycode_t code,bool is_pressed)270 static void keyboard_apply_mods(struct keyboard* self, xkb_keycode_t code,
271                                 bool is_pressed)
272 {
273 	enum xkb_state_component comp, compmask;
274 
275 	comp = xkb_state_update_key(self->state, code,
276 	                            is_pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
277 
278 	compmask = XKB_STATE_MODS_DEPRESSED |
279 	           XKB_STATE_MODS_LATCHED |
280 	           XKB_STATE_MODS_LOCKED |
281 	           XKB_STATE_MODS_EFFECTIVE;
282 
283 	if (!(comp & compmask))
284 		return;
285 
286 	keyboard_send_mods(self);
287 }
288 
match_level(struct keyboard * self,struct table_entry * entry)289 static struct table_entry* match_level(struct keyboard* self,
290                                        struct table_entry* entry)
291 {
292 	xkb_keysym_t symbol = entry->symbol;
293 
294 	while (true) {
295 		int level;
296 
297 		level = xkb_state_key_get_level(self->state, entry->code, 0);
298 
299 		if (entry->level == level)
300 			return entry;
301 
302 		if (++entry >= &self->lookup_table[self->lookup_table_length] ||
303 		    entry->symbol != symbol)
304 			break;
305 	}
306 
307 	return NULL;
308 }
309 
keyboard_symbol_is_mod(xkb_keysym_t symbol)310 static bool keyboard_symbol_is_mod(xkb_keysym_t symbol)
311 {
312 	switch (symbol) {
313 	case XKB_KEY_Shift_L:
314 	case XKB_KEY_Shift_R:
315 	case XKB_KEY_Control_L:
316 	case XKB_KEY_Caps_Lock:
317 	case XKB_KEY_Shift_Lock:
318 	case XKB_KEY_Meta_L:
319 	case XKB_KEY_Meta_R:
320 	case XKB_KEY_Alt_L:
321 	case XKB_KEY_Alt_R:
322 	case XKB_KEY_Super_L:
323 	case XKB_KEY_Super_R:
324 	case XKB_KEY_Hyper_L:
325 	case XKB_KEY_Hyper_R:
326 	case XKB_KEY_ISO_Level5_Shift:
327 	case XKB_KEY_ISO_Level5_Lock:
328 		return true;
329 	}
330 
331 	return false;
332 }
333 
send_key(struct keyboard * self,xkb_keycode_t code,bool is_pressed)334 static void send_key(struct keyboard* self, xkb_keycode_t code, bool is_pressed)
335 {
336 	zwp_virtual_keyboard_v1_key(self->virtual_keyboard, 0, code - 8,
337 	                            is_pressed ? WL_KEYBOARD_KEY_STATE_PRESSED
338 	                                       : WL_KEYBOARD_KEY_STATE_RELEASED);
339 }
340 
save_mods(struct keyboard * self,struct kb_mods * mods)341 static void save_mods(struct keyboard* self, struct kb_mods* mods)
342 {
343 	mods->depressed = xkb_state_serialize_mods(self->state,
344 			XKB_STATE_MODS_DEPRESSED);
345 	mods->latched = xkb_state_serialize_mods(self->state,
346 			XKB_STATE_MODS_LATCHED);
347 	mods->locked = xkb_state_serialize_mods(self->state,
348 			XKB_STATE_MODS_LOCKED);
349 }
350 
restore_mods(struct keyboard * self,struct kb_mods * mods)351 static void restore_mods(struct keyboard* self, struct kb_mods* mods)
352 {
353 	xkb_state_update_mask(self->state, mods->depressed, mods->latched,
354 			mods->locked, XKB_STATE_MODS_DEPRESSED,
355 			XKB_STATE_MODS_LATCHED, XKB_STATE_MODS_LOCKED);
356 }
357 
send_key_with_level(struct keyboard * self,xkb_keycode_t code,bool is_pressed,int level)358 static void send_key_with_level(struct keyboard* self, xkb_keycode_t code,
359 		bool is_pressed, int level)
360 {
361 	struct kb_mods save;
362 	save_mods(self, &save);
363 
364 	xkb_mod_mask_t mods = 0;
365 	xkb_keymap_key_get_mods_for_level(self->keymap, code, 0, level,
366 			&mods, 1);
367 	xkb_state_update_mask(self->state, mods, 0, 0, XKB_STATE_MODS_DEPRESSED,
368 			XKB_STATE_MODS_LATCHED, XKB_STATE_MODS_LOCKED);
369 	keyboard_send_mods(self);
370 
371 	log_debug("send key with level: old mods: %x, new mods: %x\n",
372 			save.latched | save.locked | save.depressed, mods);
373 
374 	send_key(self, code, is_pressed);
375 
376 	restore_mods(self, &save);
377 	keyboard_send_mods(self);
378 }
379 
update_key_state(struct keyboard * self,xkb_keycode_t code,bool is_pressed)380 static bool update_key_state(struct keyboard* self, xkb_keycode_t code,
381 		bool is_pressed)
382 {
383 	bool was_pressed = intset_is_set(&self->key_state, code);
384 	if (was_pressed == is_pressed)
385 		return false;
386 
387 	if (is_pressed)
388 		intset_set(&self->key_state, code);
389 	else
390 		intset_clear(&self->key_state, code);
391 
392 	return true;
393 }
394 
keyboard_feed(struct keyboard * self,xkb_keysym_t symbol,bool is_pressed)395 void keyboard_feed(struct keyboard* self, xkb_keysym_t symbol, bool is_pressed)
396 {
397 	struct table_entry* entry = keyboard_find_symbol(self, symbol);
398 	if (!entry) {
399 		char name[256];
400 		log_error("Failed to look up keyboard symbol: %s\n",
401 		          get_symbol_name(symbol, name, sizeof(name)));
402 		return;
403 	}
404 
405 	bool level_is_match = true;
406 
407 	if (!keyboard_symbol_is_mod(symbol)) {
408 		struct table_entry* level_entry = match_level(self, entry);
409 		if (level_entry)
410 			entry = level_entry;
411 		else
412 			level_is_match = false;
413 	}
414 
415 #ifndef NDEBUG
416 	keyboard__dump_entry(self, entry);
417 #endif
418 
419 	if (!update_key_state(self, entry->code, is_pressed))
420 		return;
421 
422 	keyboard_apply_mods(self, entry->code, is_pressed);
423 
424 	if (level_is_match)
425 		send_key(self, entry->code, is_pressed);
426 	else
427 		send_key_with_level(self, entry->code, is_pressed,
428 				entry->level);
429 }
430 
keyboard_feed_code(struct keyboard * self,xkb_keycode_t code,bool is_pressed)431 void keyboard_feed_code(struct keyboard* self, xkb_keycode_t code,
432 		bool is_pressed)
433 {
434 	if (update_key_state(self, code, is_pressed)) {
435 		keyboard_apply_mods(self, code, is_pressed);
436 		send_key(self, code, is_pressed);
437 	}
438 }
439