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