1 #include "input.h"
2
3 #include <string.h>
4 #include <unistd.h>
5 #include <signal.h>
6 #include <threads.h>
7 #include <locale.h>
8 #include <errno.h>
9 #include <wctype.h>
10 #include <sys/mman.h>
11 #include <sys/time.h>
12 #include <sys/timerfd.h>
13 #include <sys/epoll.h>
14 #include <fcntl.h>
15
16 #include <linux/input-event-codes.h>
17
18 #include <xkbcommon/xkbcommon.h>
19 #include <xkbcommon/xkbcommon-keysyms.h>
20 #include <xkbcommon/xkbcommon-compose.h>
21
22 #include <xdg-shell.h>
23
24 #define LOG_MODULE "input"
25 #define LOG_ENABLE_DBG 0
26 #include "log.h"
27 #include "config.h"
28 #include "commands.h"
29 #include "keymap.h"
30 #include "macros.h"
31 #include "quirks.h"
32 #include "render.h"
33 #include "search.h"
34 #include "selection.h"
35 #include "spawn.h"
36 #include "terminal.h"
37 #include "tokenize.h"
38 #include "url-mode.h"
39 #include "util.h"
40 #include "vt.h"
41 #include "xmalloc.h"
42 #include "xsnprintf.h"
43
44 struct pipe_context {
45 char *text;
46 size_t idx;
47 size_t left;
48 };
49
50 static bool
fdm_write_pipe(struct fdm * fdm,int fd,int events,void * data)51 fdm_write_pipe(struct fdm *fdm, int fd, int events, void *data)
52 {
53 struct pipe_context *ctx = data;
54
55 if (events & EPOLLHUP)
56 goto pipe_closed;
57
58 xassert(events & EPOLLOUT);
59 ssize_t written = write(fd, &ctx->text[ctx->idx], ctx->left);
60
61 if (written < 0) {
62 LOG_WARN("failed to write to pipe: %s", strerror(errno));
63 goto pipe_closed;
64 }
65
66 xassert(written <= ctx->left);
67 ctx->idx += written;
68 ctx->left -= written;
69
70 if (ctx->left == 0)
71 goto pipe_closed;
72
73 return true;
74
75 pipe_closed:
76 free(ctx->text);
77 free(ctx);
78 fdm_del(fdm, fd);
79 return true;
80 }
81
82 static bool
execute_binding(struct seat * seat,struct terminal * term,enum bind_action_normal action,char * const * pipe_argv,uint32_t serial)83 execute_binding(struct seat *seat, struct terminal *term,
84 enum bind_action_normal action, char *const *pipe_argv,
85 uint32_t serial)
86 {
87 switch (action) {
88 case BIND_ACTION_NONE:
89 return true;
90
91 case BIND_ACTION_NOOP:
92 return true;
93
94 case BIND_ACTION_SCROLLBACK_UP_PAGE:
95 if (term->grid == &term->normal) {
96 cmd_scrollback_up(term, term->rows);
97 return true;
98 }
99 break;
100
101 case BIND_ACTION_SCROLLBACK_UP_HALF_PAGE:
102 if (term->grid == &term->normal) {
103 cmd_scrollback_up(term, max(term->rows / 2, 1));
104 return true;
105 }
106 break;
107
108 case BIND_ACTION_SCROLLBACK_UP_LINE:
109 if (term->grid == &term->normal) {
110 cmd_scrollback_up(term, 1);
111 return true;
112 }
113 break;
114
115 case BIND_ACTION_SCROLLBACK_DOWN_PAGE:
116 if (term->grid == &term->normal) {
117 cmd_scrollback_down(term, term->rows);
118 return true;
119 }
120 break;
121
122 case BIND_ACTION_SCROLLBACK_DOWN_HALF_PAGE:
123 if (term->grid == &term->normal) {
124 cmd_scrollback_down(term, max(term->rows / 2, 1));
125 return true;
126 }
127 break;
128
129 case BIND_ACTION_SCROLLBACK_DOWN_LINE:
130 if (term->grid == &term->normal) {
131 cmd_scrollback_down(term, 1);
132 return true;
133 }
134 break;
135
136 case BIND_ACTION_CLIPBOARD_COPY:
137 selection_to_clipboard(seat, term, serial);
138 return true;
139
140 case BIND_ACTION_CLIPBOARD_PASTE:
141 selection_from_clipboard(seat, term, serial);
142 term_reset_view(term);
143 return true;
144
145 case BIND_ACTION_PRIMARY_PASTE:
146 selection_from_primary(seat, term);
147 return true;
148
149 case BIND_ACTION_SEARCH_START:
150 search_begin(term);
151 return true;
152
153 case BIND_ACTION_FONT_SIZE_UP:
154 term_font_size_increase(term);
155 return true;
156
157 case BIND_ACTION_FONT_SIZE_DOWN:
158 term_font_size_decrease(term);
159 return true;
160
161 case BIND_ACTION_FONT_SIZE_RESET:
162 term_font_size_reset(term);
163 return true;
164
165 case BIND_ACTION_SPAWN_TERMINAL:
166 term_spawn_new(term);
167 return true;
168
169 case BIND_ACTION_MINIMIZE:
170 xdg_toplevel_set_minimized(term->window->xdg_toplevel);
171 return true;
172
173 case BIND_ACTION_MAXIMIZE:
174 if (term->window->is_fullscreen)
175 xdg_toplevel_unset_fullscreen(term->window->xdg_toplevel);
176 if (term->window->is_maximized)
177 xdg_toplevel_unset_maximized(term->window->xdg_toplevel);
178 else
179 xdg_toplevel_set_maximized(term->window->xdg_toplevel);
180 return true;
181
182 case BIND_ACTION_FULLSCREEN:
183 if (term->window->is_fullscreen)
184 xdg_toplevel_unset_fullscreen(term->window->xdg_toplevel);
185 else
186 xdg_toplevel_set_fullscreen(term->window->xdg_toplevel, NULL);
187 return true;
188
189 case BIND_ACTION_PIPE_SCROLLBACK:
190 if (term->grid == &term->alt)
191 break;
192 /* FALLTHROUGH */
193 case BIND_ACTION_PIPE_VIEW:
194 case BIND_ACTION_PIPE_SELECTED: {
195 if (pipe_argv == NULL)
196 return true;
197
198 struct pipe_context *ctx = NULL;
199
200 int pipe_fd[2] = {-1, -1};
201 int stdout_fd = -1;
202 int stderr_fd = -1;
203
204 char *text = NULL;
205 size_t len = 0;
206
207 if (pipe(pipe_fd) < 0) {
208 LOG_ERRNO("failed to create pipe");
209 goto pipe_err;
210 }
211
212 stdout_fd = open("/dev/null", O_WRONLY);
213 stderr_fd = open("/dev/null", O_WRONLY);
214
215 if (stdout_fd < 0 || stderr_fd < 0) {
216 LOG_ERRNO("failed to open /dev/null");
217 goto pipe_err;
218 }
219
220 bool success;
221 switch (action) {
222 case BIND_ACTION_PIPE_SCROLLBACK:
223 success = term_scrollback_to_text(term, &text, &len);
224 break;
225
226 case BIND_ACTION_PIPE_VIEW:
227 success = term_view_to_text(term, &text, &len);
228 break;
229
230 case BIND_ACTION_PIPE_SELECTED:
231 text = selection_to_text(term);
232 success = text != NULL;
233 len = text != NULL ? strlen(text) : 0;
234 break;
235
236 default:
237 BUG("Unhandled action type");
238 success = false;
239 break;
240 }
241
242 if (!success)
243 goto pipe_err;
244
245 /* Make write-end non-blocking; required by the FDM */
246 {
247 int flags = fcntl(pipe_fd[1], F_GETFL);
248 if (flags < 0 ||
249 fcntl(pipe_fd[1], F_SETFL, flags | O_NONBLOCK) < 0)
250 {
251 LOG_ERRNO("failed to make write-end of pipe non-blocking");
252 goto pipe_err;
253 }
254 }
255
256 /* Make sure write-end is closed on exec() - or the spawned
257 * program may not terminate*/
258 {
259 int flags = fcntl(pipe_fd[1], F_GETFD);
260 if (flags < 0 ||
261 fcntl(pipe_fd[1], F_SETFD, flags | FD_CLOEXEC) < 0)
262 {
263 LOG_ERRNO("failed to set FD_CLOEXEC on writeend of pipe");
264 goto pipe_err;
265 }
266 }
267
268 if (!spawn(term->reaper, NULL, pipe_argv, pipe_fd[0], stdout_fd, stderr_fd))
269 goto pipe_err;
270
271 /* Close read end */
272 close(pipe_fd[0]);
273
274 ctx = xmalloc(sizeof(*ctx));
275 *ctx = (struct pipe_context){
276 .text = text,
277 .left = len,
278 };
279
280 /* Asynchronously write the output to the pipe */
281 if (!fdm_add(term->fdm, pipe_fd[1], EPOLLOUT, &fdm_write_pipe, ctx))
282 goto pipe_err;
283
284 return true;
285
286 pipe_err:
287 if (stdout_fd >= 0)
288 close(stdout_fd);
289 if (stderr_fd >= 0)
290 close(stderr_fd);
291 if (pipe_fd[0] >= 0)
292 close(pipe_fd[0]);
293 if (pipe_fd[1] >= 0)
294 close(pipe_fd[1]);
295 free(text);
296 free(ctx);
297 return true;
298 }
299
300 case BIND_ACTION_SHOW_URLS_COPY:
301 case BIND_ACTION_SHOW_URLS_LAUNCH: {
302 xassert(!urls_mode_is_active(term));
303
304 enum url_action url_action = action == BIND_ACTION_SHOW_URLS_COPY
305 ? URL_ACTION_COPY
306 : URL_ACTION_LAUNCH;
307
308 urls_collect(term, url_action, &term->urls);
309 urls_assign_key_combos(term->conf, &term->urls);
310 urls_render(term);
311 return true;
312 }
313
314 case BIND_ACTION_SELECT_BEGIN:
315 selection_start(
316 term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE, false);
317 return true;
318
319 case BIND_ACTION_SELECT_BEGIN_BLOCK:
320 selection_start(
321 term, seat->mouse.col, seat->mouse.row, SELECTION_BLOCK, false);
322 return true;
323
324 case BIND_ACTION_SELECT_EXTEND:
325 selection_extend(
326 seat, term, seat->mouse.col, seat->mouse.row, term->selection.kind);
327 return true;
328
329 case BIND_ACTION_SELECT_EXTEND_CHAR_WISE:
330 if (term->selection.kind != SELECTION_BLOCK) {
331 selection_extend(
332 seat, term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE);
333 return true;
334 }
335 return false;
336
337 case BIND_ACTION_SELECT_WORD:
338 selection_start(
339 term, seat->mouse.col, seat->mouse.row, SELECTION_WORD_WISE, false);
340 return true;
341
342 case BIND_ACTION_SELECT_WORD_WS:
343 selection_start(
344 term, seat->mouse.col, seat->mouse.row, SELECTION_WORD_WISE, true);
345 return true;
346
347 case BIND_ACTION_SELECT_ROW:
348 selection_start(
349 term, seat->mouse.col, seat->mouse.row, SELECTION_LINE_WISE, false);
350 return true;
351
352 case BIND_ACTION_COUNT:
353 BUG("Invalid action type");
354 return false;
355 }
356
357 return false;
358 }
359
360 static xkb_mod_mask_t
conf_modifiers_to_mask(const struct seat * seat,const struct config_key_modifiers * modifiers)361 conf_modifiers_to_mask(const struct seat *seat,
362 const struct config_key_modifiers *modifiers)
363 {
364 xkb_mod_mask_t mods = 0;
365 if (seat->kbd.mod_shift != XKB_MOD_INVALID)
366 mods |= modifiers->shift << seat->kbd.mod_shift;
367 if (seat->kbd.mod_ctrl != XKB_MOD_INVALID)
368 mods |= modifiers->ctrl << seat->kbd.mod_ctrl;
369 if (seat->kbd.mod_alt != XKB_MOD_INVALID)
370 mods |= modifiers->alt << seat->kbd.mod_alt;
371 if (seat->kbd.mod_super != XKB_MOD_INVALID)
372 mods |= modifiers->meta << seat->kbd.mod_super;
373 return mods;
374 }
375
376 static xkb_keycode_list_t
key_codes_for_xkb_sym(struct xkb_keymap * keymap,xkb_keysym_t sym)377 key_codes_for_xkb_sym(struct xkb_keymap *keymap, xkb_keysym_t sym)
378 {
379 xkb_keycode_list_t key_codes = tll_init();
380
381 /*
382 * Find all key codes that map to this symbol.
383 *
384 * This allows us to match bindings in other layouts
385 * too.
386 */
387 struct xkb_state *state = xkb_state_new(keymap);
388
389 for (xkb_keycode_t code = xkb_keymap_min_keycode(keymap);
390 code <= xkb_keymap_max_keycode(keymap);
391 code++)
392 {
393 if (xkb_state_key_get_one_sym(state, code) == sym)
394 tll_push_back(key_codes, code);
395 }
396
397 xkb_state_unref(state);
398 return key_codes;
399 }
400
401 static xkb_keysym_t
maybe_repair_key_combo(const struct seat * seat,xkb_keysym_t sym,xkb_mod_mask_t mods)402 maybe_repair_key_combo(const struct seat *seat,
403 xkb_keysym_t sym, xkb_mod_mask_t mods)
404 {
405 /*
406 * Detect combos containing a shifted symbol and the corresponding
407 * modifier, and replace the shifted symbol with its unshifted
408 * variant.
409 *
410 * For example, the combo is “Control+Shift+U”. In this case,
411 * Shift is the modifier used to “shift” ‘u’ to ‘U’, after which
412 * ‘Shift’ will have been “consumed”. Since we filter out consumed
413 * modifiers when matching key combos, this key combo will never
414 * trigger (we will never be able to match the ‘Shift’ modifier).
415 *
416 * There are two correct variants of the above key combo:
417 * - “Control+U” (upper case ‘U’)
418 * - “Control+Shift+u” (lower case ‘u’)
419 *
420 * What we do here is, for each key *code*, check if there are any
421 * (shifted) levels where it produces ‘sym’. If there are, check
422 * *which* sets of modifiers are needed to produce it, and compare
423 * with ‘mods’.
424 *
425 * If there is at least one common modifier, it means ‘sym’ is a
426 * “shifted” symbol, with the corresponding shifting modifier
427 * explicitly included in the key combo. I.e. the key combo will
428 * never trigger.
429 *
430 * We then proceed and “repair” the key combo by replacing ‘sym’
431 * with the corresponding unshifted symbol.
432 *
433 * To reduce the noise, we ignore all key codes where the shifted
434 * symbol is the same as the unshifted symbol.
435 */
436
437 for (xkb_keycode_t code = xkb_keymap_min_keycode(seat->kbd.xkb_keymap);
438 code <= xkb_keymap_max_keycode(seat->kbd.xkb_keymap);
439 code++)
440 {
441 xkb_layout_index_t layout_idx =
442 xkb_state_key_get_layout(seat->kbd.xkb_state, code);
443
444 /* Get all unshifted symbols for this key */
445 const xkb_keysym_t *base_syms = NULL;
446 size_t base_count = xkb_keymap_key_get_syms_by_level(
447 seat->kbd.xkb_keymap, code, layout_idx, 0, &base_syms);
448
449 if (base_count == 0 || sym == base_syms[0]) {
450 /* No unshifted symbols, or unshifted symbol is same as ‘sym’ */
451 continue;
452 }
453
454 /* Name of the unshifted symbol, for logging */
455 char base_name[100];
456 xkb_keysym_get_name(base_syms[0], base_name, sizeof(base_name));
457
458 /* Iterate all shift levels */
459 for (xkb_level_index_t level_idx = 1;
460 level_idx < xkb_keymap_num_levels_for_key(
461 seat->kbd.xkb_keymap, code, layout_idx);
462 level_idx++) {
463
464 /* Get all symbols for current shift level */
465 const xkb_keysym_t *shifted_syms = NULL;
466 size_t shifted_count = xkb_keymap_key_get_syms_by_level(
467 seat->kbd.xkb_keymap, code,
468 layout_idx, level_idx, &shifted_syms);
469
470 for (size_t i = 0; i < shifted_count; i++) {
471 if (shifted_syms[i] != sym)
472 continue;
473
474 /* Get modifier sets that produces the current shift level */
475 xkb_mod_mask_t mod_masks[16];
476 size_t mod_mask_count = xkb_keymap_key_get_mods_for_level(
477 seat->kbd.xkb_keymap, code, layout_idx, level_idx,
478 mod_masks, ALEN(mod_masks));
479
480 /* Check if key combo’s modifier set intersects */
481 for (size_t j = 0; j < mod_mask_count; j++) {
482 if ((mod_masks[j] & mods) != mod_masks[j])
483 continue;
484
485 char combo[64] = {0};
486
487 for (int k = 0; k < sizeof(xkb_mod_mask_t) * 8; k++) {
488 if (!(mods & (1u << k)))
489 continue;
490
491 const char *mod_name = xkb_keymap_mod_get_name(
492 seat->kbd.xkb_keymap, k);
493 strcat(combo, mod_name);
494 strcat(combo, "+");
495 }
496
497 size_t len = strlen(combo);
498 xkb_keysym_get_name(
499 sym, &combo[len], sizeof(combo) - len);
500
501 LOG_WARN(
502 "%s: combo with both explicit modifier and shifted symbol "
503 "(level=%d, mod-mask=0x%08x), "
504 "replacing with %s",
505 combo, level_idx, mod_masks[j], base_name);
506
507 /* Replace with unshifted symbol */
508 return base_syms[0];
509 }
510 }
511 }
512 }
513
514 return sym;
515 }
516
517 static void
convert_key_binding(const struct seat * seat,const struct config_key_binding * conf_binding,key_binding_list_t * bindings)518 convert_key_binding(const struct seat *seat,
519 const struct config_key_binding *conf_binding,
520 key_binding_list_t *bindings)
521 {
522 xkb_mod_mask_t mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers);
523 xkb_keysym_t sym = maybe_repair_key_combo(seat, conf_binding->sym, mods);
524
525 struct key_binding binding = {
526 .mods = mods,
527 .sym = sym,
528 .key_codes = key_codes_for_xkb_sym(seat->kbd.xkb_keymap, sym),
529 .action = conf_binding->action,
530 .pipe_argv = conf_binding->pipe.argv.args,
531 };
532 tll_push_back(*bindings, binding);
533 }
534
535 static void
convert_key_bindings(const struct config * conf,struct seat * seat)536 convert_key_bindings(const struct config *conf, struct seat *seat)
537 {
538 for (size_t i = 0; i < conf->bindings.key.count; i++) {
539 const struct config_key_binding *binding = &conf->bindings.key.arr[i];
540 convert_key_binding(seat, binding, &seat->kbd.bindings.key);
541 }
542 }
543
544 static void
convert_search_bindings(const struct config * conf,struct seat * seat)545 convert_search_bindings(const struct config *conf, struct seat *seat)
546 {
547 for (size_t i = 0; i < conf->bindings.search.count; i++) {
548 const struct config_key_binding *binding = &conf->bindings.search.arr[i];
549 convert_key_binding(seat, binding, &seat->kbd.bindings.search);
550 }
551 }
552
553 static void
convert_url_bindings(const struct config * conf,struct seat * seat)554 convert_url_bindings(const struct config *conf, struct seat *seat)
555 {
556 for (size_t i = 0; i < conf->bindings.url.count; i++) {
557 const struct config_key_binding *binding = &conf->bindings.url.arr[i];
558 convert_key_binding(seat, binding, &seat->kbd.bindings.url);
559 }
560 }
561
562 static void
convert_mouse_binding(struct seat * seat,const struct config_mouse_binding * conf_binding)563 convert_mouse_binding(struct seat *seat,
564 const struct config_mouse_binding *conf_binding)
565 {
566 struct mouse_binding binding = {
567 .action = conf_binding->action,
568 .mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers),
569 .button = conf_binding->button,
570 .count = conf_binding->count,
571 .pipe_argv = conf_binding->pipe.argv.args,
572 };
573 tll_push_back(seat->mouse.bindings, binding);
574 }
575
576 static void
convert_mouse_bindings(const struct config * conf,struct seat * seat)577 convert_mouse_bindings(const struct config *conf, struct seat *seat)
578 {
579 for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
580 const struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i];
581 if (binding->action == BIND_ACTION_NONE)
582 continue;
583 convert_mouse_binding(seat, binding);
584 }
585 }
586
587 static void
keyboard_keymap(void * data,struct wl_keyboard * wl_keyboard,uint32_t format,int32_t fd,uint32_t size)588 keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
589 uint32_t format, int32_t fd, uint32_t size)
590 {
591 LOG_DBG("keyboard_keymap: keyboard=%p (format=%u, size=%u)",
592 (void *)wl_keyboard, format, size);
593
594 struct seat *seat = data;
595 struct wayland *wayl = seat->wayl;
596
597 /*
598 * Free old keymap state
599 */
600
601 if (seat->kbd.xkb_compose_state != NULL) {
602 xkb_compose_state_unref(seat->kbd.xkb_compose_state);
603 seat->kbd.xkb_compose_state = NULL;
604 }
605 if (seat->kbd.xkb_compose_table != NULL) {
606 xkb_compose_table_unref(seat->kbd.xkb_compose_table);
607 seat->kbd.xkb_compose_table = NULL;
608 }
609 if (seat->kbd.xkb_keymap != NULL) {
610 xkb_keymap_unref(seat->kbd.xkb_keymap);
611 seat->kbd.xkb_keymap = NULL;
612 }
613 if (seat->kbd.xkb_state != NULL) {
614 xkb_state_unref(seat->kbd.xkb_state);
615 seat->kbd.xkb_state = NULL;
616 }
617 if (seat->kbd.xkb != NULL) {
618 xkb_context_unref(seat->kbd.xkb);
619 seat->kbd.xkb = NULL;
620 }
621
622 tll_foreach(seat->kbd.bindings.key, it)
623 tll_free(it->item.key_codes);
624 tll_free(seat->kbd.bindings.key);
625
626 tll_foreach(seat->kbd.bindings.search, it)
627 tll_free(it->item.key_codes);
628 tll_free(seat->kbd.bindings.search);
629
630 tll_free(seat->mouse.bindings);
631
632 /* Verify keymap is in a format we understand */
633 switch ((enum wl_keyboard_keymap_format)format) {
634 case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
635 return;
636
637 case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:
638 break;
639
640 default:
641 LOG_WARN("unrecognized keymap format: %u", format);
642 return;
643 }
644
645 char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
646 if (map_str == MAP_FAILED) {
647 LOG_ERRNO("failed to mmap keyboard keymap");
648 close(fd);
649 return;
650 }
651
652 while (map_str[size - 1] == '\0')
653 size--;
654
655 seat->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
656
657 if (seat->kbd.xkb != NULL) {
658 seat->kbd.xkb_keymap = xkb_keymap_new_from_buffer(
659 seat->kbd.xkb, map_str, size, XKB_KEYMAP_FORMAT_TEXT_V1,
660 XKB_KEYMAP_COMPILE_NO_FLAGS);
661
662 /* Compose (dead keys) */
663 seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
664 seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
665
666 if (seat->kbd.xkb_compose_table == NULL) {
667 LOG_WARN("failed to instantiate compose table; dead keys will not work");
668 } else {
669 seat->kbd.xkb_compose_state = xkb_compose_state_new(
670 seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
671 }
672 }
673
674 if (seat->kbd.xkb_keymap != NULL) {
675 seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
676
677 seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_MOD_NAME_SHIFT);
678 seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_MOD_NAME_ALT) ;
679 seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_MOD_NAME_CTRL);
680 seat->kbd.mod_super = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_MOD_NAME_LOGO);
681 seat->kbd.mod_caps = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_MOD_NAME_CAPS);
682 seat->kbd.mod_num = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_MOD_NAME_NUM);
683
684 seat->kbd.bind_significant = 0;
685 if (seat->kbd.mod_shift != XKB_MOD_INVALID)
686 seat->kbd.bind_significant |= 1 << seat->kbd.mod_shift;
687 if (seat->kbd.mod_alt != XKB_MOD_INVALID)
688 seat->kbd.bind_significant |= 1 << seat->kbd.mod_alt;
689 if (seat->kbd.mod_ctrl != XKB_MOD_INVALID)
690 seat->kbd.bind_significant |= 1 << seat->kbd.mod_ctrl;
691 if (seat->kbd.mod_super != XKB_MOD_INVALID)
692 seat->kbd.bind_significant |= 1 << seat->kbd.mod_super;
693
694 seat->kbd.kitty_significant = seat->kbd.bind_significant;
695 if (seat->kbd.mod_caps != XKB_MOD_INVALID)
696 seat->kbd.kitty_significant |= 1 << seat->kbd.mod_caps;
697 if (seat->kbd.mod_num != XKB_MOD_INVALID)
698 seat->kbd.kitty_significant |= 1 << seat->kbd.mod_num;
699
700 seat->kbd.key_arrow_up = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "UP");
701 seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN");
702 }
703
704 munmap(map_str, size);
705 close(fd);
706
707 convert_key_bindings(wayl->conf, seat);
708 convert_search_bindings(wayl->conf, seat);
709 convert_url_bindings(wayl->conf, seat);
710 convert_mouse_bindings(wayl->conf, seat);
711 }
712
713 static void
keyboard_enter(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)714 keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
715 struct wl_surface *surface, struct wl_array *keys)
716 {
717 xassert(surface != NULL);
718
719 struct seat *seat = data;
720 struct wl_window *win = wl_surface_get_user_data(surface);
721 struct terminal *term = win->term;
722
723 LOG_DBG("%s: keyboard_enter: keyboard=%p, serial=%u, surface=%p",
724 seat->name, (void *)wl_keyboard, serial, (void *)surface);
725
726 if (seat->kbd.xkb == NULL)
727 return;
728
729 term_kbd_focus_in(term);
730 seat->kbd_focus = term;
731 seat->kbd.serial = serial;
732 }
733
734 static bool
start_repeater(struct seat * seat,uint32_t key)735 start_repeater(struct seat *seat, uint32_t key)
736 {
737 if (seat->kbd.repeat.dont_re_repeat)
738 return true;
739
740 if (seat->kbd.repeat.rate == 0)
741 return true;
742
743 struct itimerspec t = {
744 .it_value = {.tv_sec = 0, .tv_nsec = seat->kbd.repeat.delay * 1000000},
745 .it_interval = {.tv_sec = 0, .tv_nsec = 1000000000 / seat->kbd.repeat.rate},
746 };
747
748 if (t.it_value.tv_nsec >= 1000000000) {
749 t.it_value.tv_sec += t.it_value.tv_nsec / 1000000000;
750 t.it_value.tv_nsec %= 1000000000;
751 }
752 if (t.it_interval.tv_nsec >= 1000000000) {
753 t.it_interval.tv_sec += t.it_interval.tv_nsec / 1000000000;
754 t.it_interval.tv_nsec %= 1000000000;
755 }
756 if (timerfd_settime(seat->kbd.repeat.fd, 0, &t, NULL) < 0) {
757 LOG_ERRNO("%s: failed to arm keyboard repeat timer", seat->name);
758 return false;
759 }
760
761 seat->kbd.repeat.key = key;
762 return true;
763 }
764
765 static bool
stop_repeater(struct seat * seat,uint32_t key)766 stop_repeater(struct seat *seat, uint32_t key)
767 {
768 if (key != -1 && key != seat->kbd.repeat.key)
769 return true;
770
771 if (timerfd_settime(seat->kbd.repeat.fd, 0, &(struct itimerspec){{0}}, NULL) < 0) {
772 LOG_ERRNO("%s: failed to disarm keyboard repeat timer", seat->name);
773 return false;
774 }
775
776 return true;
777 }
778
779 static void
keyboard_leave(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface)780 keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
781 struct wl_surface *surface)
782 {
783 struct seat *seat = data;
784
785 LOG_DBG("keyboard_leave: keyboard=%p, serial=%u, surface=%p",
786 (void *)wl_keyboard, serial, (void *)surface);
787
788 if (seat->kbd.xkb == NULL)
789 return;
790
791 xassert(
792 seat->kbd_focus == NULL ||
793 surface == NULL || /* Seen on Sway 1.2 */
794 ((const struct wl_window *)wl_surface_get_user_data(surface))->term == seat->kbd_focus
795 );
796
797 struct terminal *old_focused = seat->kbd_focus;
798 seat->kbd_focus = NULL;
799
800 stop_repeater(seat, -1);
801 seat->kbd.shift = false;
802 seat->kbd.alt = false;
803 seat->kbd.ctrl = false;
804 seat->kbd.super = false;
805 if (seat->kbd.xkb_compose_state != NULL)
806 xkb_compose_state_reset(seat->kbd.xkb_compose_state);
807
808 if (old_focused != NULL) {
809 seat->pointer.hidden = false;
810 term_xcursor_update_for_seat(old_focused, seat);
811 term_kbd_focus_out(old_focused);
812 } else {
813 /*
814 * Sway bug - under certain conditions we get a
815 * keyboard_leave() (and keyboard_key()) without first having
816 * received a keyboard_enter()
817 */
818 LOG_WARN(
819 "compositor sent keyboard_leave event without a keyboard_enter "
820 "event: surface=%p", (void *)surface);
821 }
822 }
823
824 static const struct key_data *
keymap_data_for_sym(xkb_keysym_t sym,size_t * count)825 keymap_data_for_sym(xkb_keysym_t sym, size_t *count)
826 {
827 switch (sym) {
828 case XKB_KEY_Escape: *count = ALEN(key_escape); return key_escape;
829 case XKB_KEY_Return: *count = ALEN(key_return); return key_return;
830 case XKB_KEY_ISO_Left_Tab: *count = ALEN(key_iso_left_tab); return key_iso_left_tab;
831 case XKB_KEY_Tab: *count = ALEN(key_tab); return key_tab;
832 case XKB_KEY_BackSpace: *count = ALEN(key_backspace); return key_backspace;
833 case XKB_KEY_Up: *count = ALEN(key_up); return key_up;
834 case XKB_KEY_Down: *count = ALEN(key_down); return key_down;
835 case XKB_KEY_Right: *count = ALEN(key_right); return key_right;
836 case XKB_KEY_Left: *count = ALEN(key_left); return key_left;
837 case XKB_KEY_Home: *count = ALEN(key_home); return key_home;
838 case XKB_KEY_End: *count = ALEN(key_end); return key_end;
839 case XKB_KEY_Insert: *count = ALEN(key_insert); return key_insert;
840 case XKB_KEY_Delete: *count = ALEN(key_delete); return key_delete;
841 case XKB_KEY_Page_Up: *count = ALEN(key_pageup); return key_pageup;
842 case XKB_KEY_Page_Down: *count = ALEN(key_pagedown); return key_pagedown;
843 case XKB_KEY_F1: *count = ALEN(key_f1); return key_f1;
844 case XKB_KEY_F2: *count = ALEN(key_f2); return key_f2;
845 case XKB_KEY_F3: *count = ALEN(key_f3); return key_f3;
846 case XKB_KEY_F4: *count = ALEN(key_f4); return key_f4;
847 case XKB_KEY_F5: *count = ALEN(key_f5); return key_f5;
848 case XKB_KEY_F6: *count = ALEN(key_f6); return key_f6;
849 case XKB_KEY_F7: *count = ALEN(key_f7); return key_f7;
850 case XKB_KEY_F8: *count = ALEN(key_f8); return key_f8;
851 case XKB_KEY_F9: *count = ALEN(key_f9); return key_f9;
852 case XKB_KEY_F10: *count = ALEN(key_f10); return key_f10;
853 case XKB_KEY_F11: *count = ALEN(key_f11); return key_f11;
854 case XKB_KEY_F12: *count = ALEN(key_f12); return key_f12;
855 case XKB_KEY_F13: *count = ALEN(key_f13); return key_f13;
856 case XKB_KEY_F14: *count = ALEN(key_f14); return key_f14;
857 case XKB_KEY_F15: *count = ALEN(key_f15); return key_f15;
858 case XKB_KEY_F16: *count = ALEN(key_f16); return key_f16;
859 case XKB_KEY_F17: *count = ALEN(key_f17); return key_f17;
860 case XKB_KEY_F18: *count = ALEN(key_f18); return key_f18;
861 case XKB_KEY_F19: *count = ALEN(key_f19); return key_f19;
862 case XKB_KEY_F20: *count = ALEN(key_f20); return key_f20;
863 case XKB_KEY_F21: *count = ALEN(key_f21); return key_f21;
864 case XKB_KEY_F22: *count = ALEN(key_f22); return key_f22;
865 case XKB_KEY_F23: *count = ALEN(key_f23); return key_f23;
866 case XKB_KEY_F24: *count = ALEN(key_f24); return key_f24;
867 case XKB_KEY_F25: *count = ALEN(key_f25); return key_f25;
868 case XKB_KEY_F26: *count = ALEN(key_f26); return key_f26;
869 case XKB_KEY_F27: *count = ALEN(key_f27); return key_f27;
870 case XKB_KEY_F28: *count = ALEN(key_f28); return key_f28;
871 case XKB_KEY_F29: *count = ALEN(key_f29); return key_f29;
872 case XKB_KEY_F30: *count = ALEN(key_f30); return key_f30;
873 case XKB_KEY_F31: *count = ALEN(key_f31); return key_f31;
874 case XKB_KEY_F32: *count = ALEN(key_f32); return key_f32;
875 case XKB_KEY_F33: *count = ALEN(key_f33); return key_f33;
876 case XKB_KEY_F34: *count = ALEN(key_f34); return key_f34;
877 case XKB_KEY_F35: *count = ALEN(key_f35); return key_f35;
878 case XKB_KEY_KP_Up: *count = ALEN(key_kp_up); return key_kp_up;
879 case XKB_KEY_KP_Down: *count = ALEN(key_kp_down); return key_kp_down;
880 case XKB_KEY_KP_Right: *count = ALEN(key_kp_right); return key_kp_right;
881 case XKB_KEY_KP_Left: *count = ALEN(key_kp_left); return key_kp_left;
882 case XKB_KEY_KP_Begin: *count = ALEN(key_kp_begin); return key_kp_begin;
883 case XKB_KEY_KP_Home: *count = ALEN(key_kp_home); return key_kp_home;
884 case XKB_KEY_KP_End: *count = ALEN(key_kp_end); return key_kp_end;
885 case XKB_KEY_KP_Insert: *count = ALEN(key_kp_insert); return key_kp_insert;
886 case XKB_KEY_KP_Delete: *count = ALEN(key_kp_delete); return key_kp_delete;
887 case XKB_KEY_KP_Page_Up: *count = ALEN(key_kp_pageup); return key_kp_pageup;
888 case XKB_KEY_KP_Page_Down: *count = ALEN(key_kp_pagedown); return key_kp_pagedown;
889 case XKB_KEY_KP_Enter: *count = ALEN(key_kp_enter); return key_kp_enter;
890 case XKB_KEY_KP_Divide: *count = ALEN(key_kp_divide); return key_kp_divide;
891 case XKB_KEY_KP_Multiply: *count = ALEN(key_kp_multiply); return key_kp_multiply;
892 case XKB_KEY_KP_Subtract: *count = ALEN(key_kp_subtract); return key_kp_subtract;
893 case XKB_KEY_KP_Add: *count = ALEN(key_kp_add); return key_kp_add;
894 case XKB_KEY_KP_Separator: *count = ALEN(key_kp_separator); return key_kp_separator;
895 case XKB_KEY_KP_Decimal: *count = ALEN(key_kp_decimal); return key_kp_decimal;
896 case XKB_KEY_KP_0: *count = ALEN(key_kp_0); return key_kp_0;
897 case XKB_KEY_KP_1: *count = ALEN(key_kp_1); return key_kp_1;
898 case XKB_KEY_KP_2: *count = ALEN(key_kp_2); return key_kp_2;
899 case XKB_KEY_KP_3: *count = ALEN(key_kp_3); return key_kp_3;
900 case XKB_KEY_KP_4: *count = ALEN(key_kp_4); return key_kp_4;
901 case XKB_KEY_KP_5: *count = ALEN(key_kp_5); return key_kp_5;
902 case XKB_KEY_KP_6: *count = ALEN(key_kp_6); return key_kp_6;
903 case XKB_KEY_KP_7: *count = ALEN(key_kp_7); return key_kp_7;
904 case XKB_KEY_KP_8: *count = ALEN(key_kp_8); return key_kp_8;
905 case XKB_KEY_KP_9: *count = ALEN(key_kp_9); return key_kp_9;
906 }
907
908 return NULL;
909 }
910
911 static const struct key_data *
keymap_lookup(struct terminal * term,xkb_keysym_t sym,enum modifier mods)912 keymap_lookup(struct terminal *term, xkb_keysym_t sym, enum modifier mods)
913 {
914 size_t count;
915 const struct key_data *info = keymap_data_for_sym(sym, &count);
916
917 if (info == NULL)
918 return NULL;
919
920 const enum cursor_keys cursor_keys_mode = term->cursor_keys_mode;
921 const enum keypad_keys keypad_keys_mode
922 = term->num_lock_modifier ? KEYPAD_NUMERICAL : term->keypad_keys_mode;
923
924 LOG_DBG("keypad mode: %d", keypad_keys_mode);
925
926 for (size_t j = 0; j < count; j++) {
927 enum modifier modifiers = info[j].modifiers;
928
929 if (modifiers & MOD_MODIFY_OTHER_KEYS_STATE1) {
930 if (term->modify_other_keys_2)
931 continue;
932 modifiers &= ~MOD_MODIFY_OTHER_KEYS_STATE1;
933 }
934 if (modifiers & MOD_MODIFY_OTHER_KEYS_STATE2) {
935 if (!term->modify_other_keys_2)
936 continue;
937 modifiers &= ~MOD_MODIFY_OTHER_KEYS_STATE2;
938 }
939
940 if (modifiers != MOD_ANY && modifiers != mods)
941 continue;
942
943 if (info[j].cursor_keys_mode != CURSOR_KEYS_DONTCARE &&
944 info[j].cursor_keys_mode != cursor_keys_mode)
945 continue;
946
947 if (info[j].keypad_keys_mode != KEYPAD_DONTCARE &&
948 info[j].keypad_keys_mode != keypad_keys_mode)
949 continue;
950
951 return &info[j];
952 }
953
954 return NULL;
955 }
956
957 UNITTEST
958 {
959 struct terminal term = {
960 .num_lock_modifier = false,
961 .keypad_keys_mode = KEYPAD_NUMERICAL,
962 .cursor_keys_mode = CURSOR_KEYS_NORMAL,
963 };
964
965 const struct key_data *info = keymap_lookup(&term, XKB_KEY_ISO_Left_Tab, MOD_SHIFT | MOD_CTRL);
966 xassert(info != NULL);
967 xassert(strcmp(info->seq, "\033[27;6;9~") == 0);
968 }
969
970 UNITTEST
971 {
972 struct terminal term = {
973 .modify_other_keys_2 = false,
974 };
975
976 const struct key_data *info = keymap_lookup(&term, XKB_KEY_Return, MOD_ALT);
977 xassert(info != NULL);
978 xassert(strcmp(info->seq, "\033\r") == 0);
979
980 term.modify_other_keys_2 = true;
981 info = keymap_lookup(&term, XKB_KEY_Return, MOD_ALT);
982 xassert(info != NULL);
983 xassert(strcmp(info->seq, "\033[27;3;13~") == 0);
984 }
985
986 static void
get_current_modifiers(const struct seat * seat,xkb_mod_mask_t * effective,xkb_mod_mask_t * consumed,uint32_t key)987 get_current_modifiers(const struct seat *seat,
988 xkb_mod_mask_t *effective,
989 xkb_mod_mask_t *consumed, uint32_t key)
990 {
991 if (effective != NULL) {
992 *effective = xkb_state_serialize_mods(
993 seat->kbd.xkb_state, XKB_STATE_MODS_EFFECTIVE);
994 }
995
996 if (consumed != NULL) {
997 *consumed = xkb_state_key_get_consumed_mods2(
998 seat->kbd.xkb_state, key, XKB_CONSUMED_MODE_XKB);
999 }
1000 }
1001
1002 struct kbd_ctx {
1003 xkb_layout_index_t layout;
1004 xkb_keycode_t key;
1005 xkb_keysym_t sym;
1006
1007 struct {
1008 const xkb_keysym_t *syms;
1009 size_t count;
1010 } level0_syms;
1011
1012 xkb_mod_mask_t mods;
1013 xkb_mod_mask_t consumed;
1014
1015 struct {
1016 const uint8_t *buf;
1017 size_t count;
1018 } utf8;
1019 uint32_t utf32;
1020
1021 enum xkb_compose_status compose_status;
1022 enum wl_keyboard_key_state key_state;
1023 };
1024
1025 static bool
legacy_kbd_protocol(struct seat * seat,struct terminal * term,const struct kbd_ctx * ctx)1026 legacy_kbd_protocol(struct seat *seat, struct terminal *term,
1027 const struct kbd_ctx *ctx)
1028 {
1029 if (ctx->key_state != WL_KEYBOARD_KEY_STATE_PRESSED)
1030 return false;
1031 if (ctx->compose_status == XKB_COMPOSE_COMPOSING)
1032 return false;
1033
1034 enum modifier keymap_mods = MOD_NONE;
1035 keymap_mods |= seat->kbd.shift ? MOD_SHIFT : MOD_NONE;
1036 keymap_mods |= seat->kbd.alt ? MOD_ALT : MOD_NONE;
1037 keymap_mods |= seat->kbd.ctrl ? MOD_CTRL : MOD_NONE;
1038 keymap_mods |= seat->kbd.super ? MOD_META : MOD_NONE;
1039
1040 const xkb_keysym_t sym = ctx->sym;
1041 const size_t count = ctx->utf8.count;
1042 const uint8_t *const utf8 = ctx->utf8.buf;
1043
1044 const struct key_data *keymap;
1045 if (sym == XKB_KEY_Escape && keymap_mods == MOD_NONE && term->modify_escape_key) {
1046 static const struct key_data esc = {.seq = "\033[27;1;27~"};
1047 keymap = &esc;
1048 } else
1049 keymap = keymap_lookup(term, sym, keymap_mods);
1050
1051 if (keymap != NULL) {
1052 term_to_slave(term, keymap->seq, strlen(keymap->seq));
1053 return true;
1054 }
1055
1056 if (count == 0)
1057 return false;
1058
1059 #define is_control_key(x) ((x) >= 0x40 && (x) <= 0x7f)
1060 #define IS_CTRL(x) ((x) < 0x20 || ((x) >= 0x7f && (x) <= 0x9f))
1061
1062 LOG_DBG("term->modify_other_keys=%d, count=%zu, is_ctrl=%d (utf8=0x%02x), sym=%d",
1063 term->modify_other_keys_2, count, IS_CTRL(utf8[0]), utf8[0], sym);
1064
1065 bool ctrl_is_in_effect = (keymap_mods & MOD_CTRL) != 0;
1066 bool ctrl_seq = is_control_key(sym) || (count == 1 && IS_CTRL(utf8[0]));
1067
1068 if (keymap_mods != MOD_NONE && (term->modify_other_keys_2 ||
1069 (ctrl_is_in_effect && !ctrl_seq)))
1070 {
1071 static const int mod_param_map[32] = {
1072 [MOD_SHIFT] = 2,
1073 [MOD_ALT] = 3,
1074 [MOD_SHIFT | MOD_ALT] = 4,
1075 [MOD_CTRL] = 5,
1076 [MOD_SHIFT | MOD_CTRL] = 6,
1077 [MOD_ALT | MOD_CTRL] = 7,
1078 [MOD_SHIFT | MOD_ALT | MOD_CTRL] = 8,
1079 [MOD_META] = 9,
1080 [MOD_META | MOD_SHIFT] = 10,
1081 [MOD_META | MOD_ALT] = 11,
1082 [MOD_META | MOD_SHIFT | MOD_ALT] = 12,
1083 [MOD_META | MOD_CTRL] = 13,
1084 [MOD_META | MOD_SHIFT | MOD_CTRL] = 14,
1085 [MOD_META | MOD_ALT | MOD_CTRL] = 15,
1086 [MOD_META | MOD_SHIFT | MOD_ALT | MOD_CTRL] = 16,
1087 };
1088
1089 xassert(keymap_mods < ALEN(mod_param_map));
1090 int modify_param = mod_param_map[keymap_mods];
1091 xassert(modify_param != 0);
1092
1093 char reply[32];
1094 size_t n = xsnprintf(reply, sizeof(reply), "\x1b[27;%d;%d~", modify_param, sym);
1095 term_to_slave(term, reply, n);
1096 }
1097
1098 else if (keymap_mods & MOD_ALT) {
1099 /*
1100 * When the alt modifier is pressed, we do one out of three things:
1101 *
1102 * 1. we prefix the output bytes with ESC
1103 * 2. we set the 8:th bit in the output byte
1104 * 3. we ignore the alt modifier
1105 *
1106 * #1 is configured with \E[?1036, and is on by default
1107 *
1108 * If #1 has been disabled, we use #2, *if* it's a single byte
1109 * we're emitting. Since this is a UTF-8 terminal, we then
1110 * UTF8-encode the 8-bit character. #2 is configured with
1111 * \E[?1034, and is on by default.
1112 *
1113 * Lastly, if both #1 and #2 have been disabled, the alt
1114 * modifier is ignored.
1115 */
1116 if (term->meta.esc_prefix) {
1117 term_to_slave(term, "\x1b", 1);
1118 term_to_slave(term, utf8, count);
1119 }
1120
1121 else if (term->meta.eight_bit && count == 1) {
1122 const wchar_t wc = 0x80 | utf8[0];
1123
1124 char wc_as_utf8[8];
1125 mbstate_t ps = {0};
1126 size_t chars = wcrtomb(wc_as_utf8, wc, &ps);
1127
1128 if (chars != (size_t)-1)
1129 term_to_slave(term, wc_as_utf8, chars);
1130 else
1131 term_to_slave(term, wc_as_utf8, count);
1132 }
1133
1134 else {
1135 /* Alt ignored */
1136 term_to_slave(term, utf8, count);
1137 }
1138 } else
1139 term_to_slave(term, utf8, count);
1140
1141 return true;
1142 }
1143
1144 static bool
kitty_kbd_protocol(struct seat * seat,struct terminal * term,const struct kbd_ctx * ctx)1145 kitty_kbd_protocol(struct seat *seat, struct terminal *term,
1146 const struct kbd_ctx *ctx)
1147 {
1148 const bool repeating = seat->kbd.repeat.dont_re_repeat;
1149 const bool pressed = ctx->key_state == WL_KEYBOARD_KEY_STATE_PRESSED && !repeating;
1150 const bool released = ctx->key_state == WL_KEYBOARD_KEY_STATE_RELEASED;
1151 const bool composing = ctx->compose_status == XKB_COMPOSE_COMPOSING;
1152 const bool composed = ctx->compose_status == XKB_COMPOSE_COMPOSED;
1153
1154 const enum kitty_kbd_flags flags =
1155 term->grid->kitty_kbd.flags[term->grid->kitty_kbd.idx];
1156
1157 const bool disambiguate = flags & KITTY_KBD_DISAMBIGUATE;
1158 const bool report_events = flags & KITTY_KBD_REPORT_EVENT;
1159 const bool report_alternate = flags & KITTY_KBD_REPORT_ALTERNATE;
1160 const bool report_all_as_escapes = flags & KITTY_KBD_REPORT_ALL;
1161
1162 if (!report_events && released)
1163 return false;
1164
1165 if (composed && released)
1166 return false;
1167
1168 /* TODO: should we even bother with this, or just say it’s not supported? */
1169 if (!disambiguate && !report_all_as_escapes && pressed)
1170 return legacy_kbd_protocol(seat, term, ctx);
1171
1172 const xkb_mod_mask_t mods = ctx->mods & seat->kbd.kitty_significant;
1173 const xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
1174 seat->kbd.xkb_state, ctx->key, XKB_CONSUMED_MODE_GTK) & seat->kbd.kitty_significant;
1175 const xkb_mod_mask_t effective = mods & ~consumed;
1176 const xkb_mod_mask_t caps_num =
1177 (seat->kbd.mod_caps != XKB_MOD_INVALID ? 1 << seat->kbd.mod_caps : 0) |
1178 (seat->kbd.mod_num != XKB_MOD_INVALID ? 1 << seat->kbd.mod_num : 0);
1179
1180 const xkb_keysym_t sym = ctx->sym;
1181 const uint32_t utf32 = ctx->utf32;
1182 const uint8_t *const utf8 = ctx->utf8.buf;
1183
1184 const bool is_text = iswprint(utf32) && (effective & ~caps_num) == 0;
1185 const size_t count = ctx->utf8.count;
1186
1187 const bool report_associated_text =
1188 (flags & KITTY_KBD_REPORT_ASSOCIATED) && is_text && !released;
1189
1190 if (composing) {
1191 /* We never emit anything while composing, *except* modifiers
1192 * (and only in report-all-keys-as-escape-codes mode) */
1193 switch (sym) {
1194 case XKB_KEY_Caps_Lock:
1195 case XKB_KEY_Num_Lock:
1196 case XKB_KEY_Shift_L:
1197 case XKB_KEY_Control_L:
1198 case XKB_KEY_Alt_L:
1199 case XKB_KEY_Super_L:
1200 case XKB_KEY_Hyper_L:
1201 case XKB_KEY_Meta_L:
1202 case XKB_KEY_Shift_R:
1203 case XKB_KEY_Control_R:
1204 case XKB_KEY_Alt_R:
1205 case XKB_KEY_Super_R:
1206 case XKB_KEY_Hyper_R:
1207 case XKB_KEY_Meta_R:
1208 case XKB_KEY_ISO_Level3_Shift:
1209 case XKB_KEY_ISO_Level5_Shift:
1210 goto emit_escapes;
1211
1212 default:
1213 return false;
1214 }
1215 }
1216
1217 if (report_all_as_escapes)
1218 goto emit_escapes;
1219
1220 if (effective == 0) {
1221 switch (sym) {
1222 case XKB_KEY_Return: term_to_slave(term, "\r", 1); return true;
1223 case XKB_KEY_BackSpace: term_to_slave(term, "\x7f", 1); return true;
1224 case XKB_KEY_Tab: term_to_slave(term, "\t", 1); return true;
1225 }
1226 }
1227
1228 /* Plain-text without modifiers, or commposed text, is emitted as-is */
1229 if (is_text && !released) {
1230 term_to_slave(term, utf8, count);
1231 return true;
1232 }
1233
1234 emit_escapes:
1235 ;
1236 unsigned int encoded_mods = 0;
1237 if (seat->kbd.mod_shift != XKB_MOD_INVALID)
1238 encoded_mods |= mods & (1 << seat->kbd.mod_shift) ? (1 << 0) : 0;
1239 if (seat->kbd.mod_alt != XKB_MOD_INVALID)
1240 encoded_mods |= mods & (1 << seat->kbd.mod_alt) ? (1 << 1) : 0;
1241 if (seat->kbd.mod_ctrl != XKB_MOD_INVALID)
1242 encoded_mods |= mods & (1 << seat->kbd.mod_ctrl) ? (1 << 2) : 0;
1243 if (seat->kbd.mod_super != XKB_MOD_INVALID)
1244 encoded_mods |= mods & (1 << seat->kbd.mod_super) ? (1 << 3) : 0;
1245 if (seat->kbd.mod_caps != XKB_MOD_INVALID)
1246 encoded_mods |= mods & (1 << seat->kbd.mod_caps) ? (1 << 6) : 0;
1247 if (seat->kbd.mod_num != XKB_MOD_INVALID)
1248 encoded_mods |= mods & (1 << seat->kbd.mod_num) ? (1 << 7) : 0;
1249 encoded_mods++;
1250
1251 int key = -1, alternate = -1, base = -1;
1252 char final;
1253
1254 switch (sym) {
1255 case XKB_KEY_Escape: key = 27; final = 'u'; break;
1256 case XKB_KEY_Return: key = 13; final = 'u'; break;
1257 case XKB_KEY_Tab: key = 9; final = 'u'; break;
1258 case XKB_KEY_ISO_Left_Tab: key = 9; final = 'u'; break;
1259 case XKB_KEY_BackSpace: key = 127; final = 'u'; break;
1260 case XKB_KEY_Insert: key = 2; final = '~'; break;
1261 case XKB_KEY_Delete: key = 3; final = '~'; break;
1262 case XKB_KEY_Left: key = 1; final = 'D'; break;
1263 case XKB_KEY_Right: key = 1; final = 'C'; break;
1264 case XKB_KEY_Up: key = 1; final = 'A'; break;
1265 case XKB_KEY_Down: key = 1; final = 'B'; break;
1266 case XKB_KEY_Page_Up: key = 5; final = '~'; break;
1267 case XKB_KEY_Page_Down: key = 6; final = '~'; break;
1268 case XKB_KEY_Home: key = 1; final = 'H'; break;
1269 case XKB_KEY_End: key = 1; final = 'F'; break;
1270 case XKB_KEY_Scroll_Lock: key = 57359; final = 'u'; break;
1271 case XKB_KEY_Print: key = 57361; final = 'u'; break;
1272 case XKB_KEY_Pause: key = 57362; final = 'u'; break;
1273 case XKB_KEY_Menu: key = 57363; final = 'u'; break;
1274 case XKB_KEY_F1: key = 1; final = 'P'; break;
1275 case XKB_KEY_F2: key = 1; final = 'Q'; break;
1276 case XKB_KEY_F3: key = 1; final = 'R'; break;
1277 case XKB_KEY_F4: key = 1; final = 'S'; break;
1278 case XKB_KEY_F5: key = 15; final = '~'; break;
1279 case XKB_KEY_F6: key = 17; final = '~'; break;
1280 case XKB_KEY_F7: key = 18; final = '~'; break;
1281 case XKB_KEY_F8: key = 19; final = '~'; break;
1282 case XKB_KEY_F9: key = 20; final = '~'; break;
1283 case XKB_KEY_F10: key = 21; final = '~'; break;
1284 case XKB_KEY_F11: key = 23; final = '~'; break;
1285 case XKB_KEY_F12: key = 24; final = '~'; break;
1286 case XKB_KEY_F13: key = 57376; final = 'u'; break;
1287 case XKB_KEY_F14: key = 57377; final = 'u'; break;
1288 case XKB_KEY_F15: key = 57378; final = 'u'; break;
1289 case XKB_KEY_F16: key = 57379; final = 'u'; break;
1290 case XKB_KEY_F17: key = 57380; final = 'u'; break;
1291 case XKB_KEY_F18: key = 57381; final = 'u'; break;
1292 case XKB_KEY_F19: key = 57382; final = 'u'; break;
1293 case XKB_KEY_F20: key = 57383; final = 'u'; break;
1294 case XKB_KEY_F21: key = 57384; final = 'u'; break;
1295 case XKB_KEY_F22: key = 57385; final = 'u'; break;
1296 case XKB_KEY_F23: key = 57386; final = 'u'; break;
1297 case XKB_KEY_F24: key = 57387; final = 'u'; break;
1298 case XKB_KEY_F25: key = 57388; final = 'u'; break;
1299 case XKB_KEY_F26: key = 57389; final = 'u'; break;
1300 case XKB_KEY_F27: key = 57390; final = 'u'; break;
1301 case XKB_KEY_F28: key = 57391; final = 'u'; break;
1302 case XKB_KEY_F29: key = 57392; final = 'u'; break;
1303 case XKB_KEY_F30: key = 57393; final = 'u'; break;
1304 case XKB_KEY_F31: key = 57394; final = 'u'; break;
1305 case XKB_KEY_F32: key = 57395; final = 'u'; break;
1306 case XKB_KEY_F33: key = 57396; final = 'u'; break;
1307 case XKB_KEY_F34: key = 57397; final = 'u'; break;
1308 case XKB_KEY_F35: key = 57398; final = 'u'; break;
1309 case XKB_KEY_KP_0: key = 57399; final = 'u'; break;
1310 case XKB_KEY_KP_1: key = 57400; final = 'u'; break;
1311 case XKB_KEY_KP_2: key = 57401; final = 'u'; break;
1312 case XKB_KEY_KP_3: key = 57402; final = 'u'; break;
1313 case XKB_KEY_KP_4: key = 57403; final = 'u'; break;
1314 case XKB_KEY_KP_5: key = 57404; final = 'u'; break;
1315 case XKB_KEY_KP_6: key = 57405; final = 'u'; break;
1316 case XKB_KEY_KP_7: key = 57406; final = 'u'; break;
1317 case XKB_KEY_KP_8: key = 57407; final = 'u'; break;
1318 case XKB_KEY_KP_9: key = 57408; final = 'u'; break;
1319 case XKB_KEY_KP_Decimal: key = 57409; final = 'u'; break;
1320 case XKB_KEY_KP_Divide: key = 57410; final = 'u'; break;
1321 case XKB_KEY_KP_Multiply: key = 57411; final = 'u'; break;
1322 case XKB_KEY_KP_Subtract: key = 57412; final = 'u'; break;
1323 case XKB_KEY_KP_Add: key = 57413; final = 'u'; break;
1324 case XKB_KEY_KP_Enter: key = 57414; final = 'u'; break;
1325 case XKB_KEY_KP_Equal: key = 57415; final = 'u'; break;
1326 case XKB_KEY_KP_Separator: key = 57416; final = 'u'; break;
1327 case XKB_KEY_KP_Left: key = 57417; final = 'u'; break;
1328 case XKB_KEY_KP_Right: key = 57418; final = 'u'; break;
1329 case XKB_KEY_KP_Up: key = 57419; final = 'u'; break;
1330 case XKB_KEY_KP_Down: key = 57420; final = 'u'; break;
1331 case XKB_KEY_KP_Page_Up: key = 57421; final = 'u'; break;
1332 case XKB_KEY_KP_Page_Down: key = 57422; final = 'u'; break;
1333 case XKB_KEY_KP_Home: key = 57423; final = 'u'; break;
1334 case XKB_KEY_KP_End: key = 57424; final = 'u'; break;
1335 case XKB_KEY_KP_Insert: key = 57425; final = 'u'; break;
1336 case XKB_KEY_KP_Delete: key = 57426; final = 'u'; break;
1337 case XKB_KEY_KP_Begin: key = 1; final = 'E'; break;
1338
1339 case XKB_KEY_XF86AudioPlay: key = 57428; final = 'u'; break;
1340 case XKB_KEY_XF86AudioPause: key = 57429; final = 'u'; break;
1341 //case XKB_KEY_XF86AudioPlayPause: key = 57430; final = 'u'; break;
1342 //case XKB_KEY_XF86AudioReverse: key = 57431; final = 'u'; break;
1343 case XKB_KEY_XF86AudioStop: key = 57432; final = 'u'; break;
1344 case XKB_KEY_XF86AudioForward: key = 57433; final = 'u'; break;
1345 case XKB_KEY_XF86AudioRewind: key = 57434; final = 'u'; break;
1346 case XKB_KEY_XF86AudioNext: key = 57435; final = 'u'; break;
1347 case XKB_KEY_XF86AudioPrev: key = 57436; final = 'u'; break;
1348 case XKB_KEY_XF86AudioRecord: key = 57437; final = 'u'; break;
1349 case XKB_KEY_XF86AudioLowerVolume: key = 57438; final = 'u'; break;
1350 case XKB_KEY_XF86AudioRaiseVolume: key = 57439; final = 'u'; break;
1351 case XKB_KEY_XF86AudioMute: key = 57440; final = 'u'; break;
1352
1353 case XKB_KEY_Caps_Lock: if (report_all_as_escapes) {key = 57358; final = 'u';} break;
1354 case XKB_KEY_Num_Lock: if (report_all_as_escapes) {key = 57360; final = 'u';} break;
1355
1356 case XKB_KEY_Shift_L: if (report_all_as_escapes) {key = 57441; final = 'u';} break;
1357 case XKB_KEY_Control_L: if (report_all_as_escapes) {key = 57442; final = 'u';} break;
1358 case XKB_KEY_Alt_L: if (report_all_as_escapes) {key = 57443; final = 'u';} break;
1359 case XKB_KEY_Super_L: if (report_all_as_escapes) {key = 57444; final = 'u';} break;
1360 case XKB_KEY_Hyper_L: if (report_all_as_escapes) {key = 57445; final = 'u';} break;
1361 case XKB_KEY_Meta_L: if (report_all_as_escapes) {key = 57446; final = 'u';} break;
1362 case XKB_KEY_Shift_R: if (report_all_as_escapes) {key = 57447; final = 'u';} break;
1363 case XKB_KEY_Control_R: if (report_all_as_escapes) {key = 57448; final = 'u';} break;
1364 case XKB_KEY_Alt_R: if (report_all_as_escapes) {key = 57449; final = 'u';} break;
1365 case XKB_KEY_Super_R: if (report_all_as_escapes) {key = 57450; final = 'u';} break;
1366 case XKB_KEY_Hyper_R: if (report_all_as_escapes) {key = 57451; final = 'u';} break;
1367 case XKB_KEY_Meta_R: if (report_all_as_escapes) {key = 57452; final = 'u';} break;
1368 case XKB_KEY_ISO_Level3_Shift: if (report_all_as_escapes) {key = 57453; final = 'u';} break;
1369 case XKB_KEY_ISO_Level5_Shift: if (report_all_as_escapes) {key = 57454; final = 'u';} break;
1370
1371 default: {
1372 /*
1373 * Use keysym (typically its Unicode codepoint value).
1374 *
1375 * If the keysym is shifted, use its unshifted codepoint
1376 * instead. In other words, ctrl+a and ctrl+shift+a should
1377 * both use the same value for ‘key’ (97 - i.a. ‘a’).
1378 *
1379 * However, if a non-significant modifier was used to
1380 * generate the symbol. This is needed since we cannot
1381 * encode non-significant modifiers, and thus the “extra”
1382 * modifier(s) would get lost.
1383 *
1384 * Example:
1385 *
1386 * the Swedish layout has ‘2’, QUOTATION MARK (“double
1387 * quote”), ‘@’, and ‘²’ on the same key. ‘2’ is the base
1388 * symbol.
1389 *
1390 * Shift+2 results in QUOTATION MARK
1391 * AltGr+2 results in ‘@’
1392 * AltGr+Shift+2 results in ‘²’
1393 *
1394 * The kitty kbd protocol can’t encode AltGr. So, if we
1395 * always used the base symbol (‘2’), Alt+Shift+2 would
1396 * result in the same escape sequence as
1397 * AltGr+Alt+Shift+2.
1398 *
1399 * (yes, this matches what kitty does, as of 0.23.1)
1400 */
1401
1402 /* Get the key’s shift level */
1403 xkb_level_index_t lvl = xkb_state_key_get_level(
1404 seat->kbd.xkb_state, ctx->key, ctx->layout);
1405
1406 /* And get all modifier combinations that, combined with
1407 * the pressed key, results in the current shift level */
1408 xkb_mod_mask_t masks[32];
1409 size_t mask_count = xkb_keymap_key_get_mods_for_level(
1410 seat->kbd.xkb_keymap, ctx->key, ctx->layout, lvl,
1411 masks, ALEN(masks));
1412
1413 /* Check modifier combinations - if a combination has
1414 * modifiers not in our set of ‘significant’ modifiers,
1415 * use key sym as-is */
1416 bool use_level0_sym = true;
1417 for (size_t i = 0; i < mask_count; i++) {
1418 if ((masks[i] & ~seat->kbd.kitty_significant) > 0) {
1419 use_level0_sym = false;
1420 break;
1421 }
1422 }
1423
1424 xkb_keysym_t sym_to_use = use_level0_sym && ctx->level0_syms.count > 0
1425 ? ctx->level0_syms.syms[0]
1426 : sym;
1427
1428 if (composed && is_text)
1429 key = utf32;
1430 else {
1431 key = xkb_keysym_to_utf32(sym_to_use);
1432 if (key == 0)
1433 key = sym_to_use;
1434
1435 /* The *shifted* key. May be the same as the unshifted
1436 * key - if so, this is filtered out below, when
1437 * emitting the CSI */
1438 alternate = xkb_keysym_to_utf32(sym);
1439 }
1440
1441 /* Base layout key. I.e the symbol the pressed key produces in
1442 * the base/default layout (layout idx 0) */
1443 const xkb_keysym_t *base_syms;
1444 int base_sym_count = xkb_keymap_key_get_syms_by_level(
1445 seat->kbd.xkb_keymap, ctx->key, 0, 0, &base_syms);
1446
1447 if (base_sym_count > 0)
1448 base = xkb_keysym_to_utf32(base_syms[0]);
1449
1450 final = 'u';
1451 break;
1452 }
1453 }
1454
1455 xassert(encoded_mods >= 1);
1456
1457 char event[4];
1458 if (report_events /*&& !pressed*/) {
1459 /* Note: this deviates slightly from Kitty, which omits the
1460 * “:1” subparameter for key press events */
1461 event[0] = ':';
1462 event[1] = '0' + (pressed ? 1 : repeating ? 2 : 3);
1463 event[2] = '\0';
1464 } else
1465 event[0] = '\0';
1466
1467 char buf[64], *p = buf;
1468 size_t left = sizeof(buf);
1469 size_t bytes;
1470
1471 if (key < 0)
1472 return false;
1473
1474 if (final == 'u' || final == '~') {
1475 bytes = snprintf(p, left, "\x1b[%u", key);
1476 p += bytes; left -= bytes;
1477
1478 if (report_alternate) {
1479 bool emit_alternate = alternate > 0 && alternate != key;
1480 bool emit_base = base > 0 && base != key && base != alternate;
1481
1482 if (emit_alternate) {
1483 bytes = snprintf(p, left, ":%u", alternate);
1484 p += bytes; left -= bytes;
1485 }
1486
1487 if (emit_base) {
1488 bytes = snprintf(
1489 p, left, "%s:%u", !emit_alternate ? ":" : "", base);
1490 p += bytes; left -= bytes;
1491 }
1492 }
1493
1494 bool emit_mods = encoded_mods > 1 || event[0] != '\0';
1495
1496 if (emit_mods) {
1497 bytes = snprintf(p, left, ";%u%s", encoded_mods, event);
1498 p += bytes; left -= bytes;
1499 }
1500
1501 if (report_associated_text) {
1502 bytes = snprintf(p, left, "%s;%u", !emit_mods ? ";" : "", utf32);
1503 p += bytes; left -= bytes;
1504 }
1505
1506 bytes = snprintf(p, left, "%c", final);
1507 p += bytes; left -= bytes;
1508 } else {
1509 if (encoded_mods > 1 || event[0] != '\0') {
1510 bytes = snprintf(p, left, "\x1b[1;%u%s%c", encoded_mods, event, final);
1511 p += bytes; left -= bytes;
1512 } else {
1513 bytes = snprintf(p, left, "\x1b[%c", final);
1514 p += bytes; left -= bytes;
1515 }
1516 }
1517
1518 term_to_slave(term, buf, sizeof(buf) - left);
1519 return true;
1520 }
1521
1522 static void
key_press_release(struct seat * seat,struct terminal * term,uint32_t serial,uint32_t key,uint32_t state)1523 key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
1524 uint32_t key, uint32_t state)
1525 {
1526 seat->kbd.serial = serial;
1527 if (seat->kbd.xkb == NULL ||
1528 seat->kbd.xkb_keymap == NULL ||
1529 seat->kbd.xkb_state == NULL)
1530 {
1531 return;
1532 }
1533
1534 const bool pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED;
1535 //const bool repeated = pressed && seat->kbd.repeat.dont_re_repeat;
1536 const bool released = state == WL_KEYBOARD_KEY_STATE_RELEASED;
1537
1538 if (released)
1539 stop_repeater(seat, key);
1540
1541 bool should_repeat =
1542 pressed && xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key);
1543
1544 xkb_keysym_t sym = xkb_state_key_get_one_sym(seat->kbd.xkb_state, key);
1545
1546 if (pressed && term->conf->mouse.hide_when_typing &&
1547
1548 /* TODO: better way to detect modifiers */
1549 sym != XKB_KEY_Shift_L && sym != XKB_KEY_Shift_R &&
1550 sym != XKB_KEY_Control_L && sym != XKB_KEY_Control_R &&
1551 sym != XKB_KEY_Alt_L && sym != XKB_KEY_Alt_R &&
1552 sym != XKB_KEY_ISO_Level3_Shift &&
1553 sym != XKB_KEY_Super_L && sym != XKB_KEY_Super_R &&
1554 sym != XKB_KEY_Meta_L && sym != XKB_KEY_Meta_R &&
1555 sym != XKB_KEY_Menu)
1556 {
1557 seat->pointer.hidden = true;
1558 term_xcursor_update_for_seat(term, seat);
1559 }
1560
1561 enum xkb_compose_status compose_status = XKB_COMPOSE_NOTHING;
1562
1563 if (seat->kbd.xkb_compose_state != NULL) {
1564 if (pressed)
1565 xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym);
1566 compose_status = xkb_compose_state_get_status(
1567 seat->kbd.xkb_compose_state);
1568 }
1569
1570 const bool composed = compose_status == XKB_COMPOSE_COMPOSED;
1571
1572 xkb_mod_mask_t mods, consumed;
1573 get_current_modifiers(seat, &mods, &consumed, key);
1574
1575 xkb_mod_mask_t bind_mods = mods & seat->kbd.bind_significant;
1576 xkb_mod_mask_t bind_consumed = consumed & seat->kbd.bind_significant;
1577
1578 xkb_layout_index_t layout_idx =
1579 xkb_state_key_get_layout(seat->kbd.xkb_state, key);
1580
1581 const xkb_keysym_t *raw_syms = NULL;
1582 size_t raw_count = xkb_keymap_key_get_syms_by_level(
1583 seat->kbd.xkb_keymap, key, layout_idx, 0, &raw_syms);
1584
1585 if (pressed) {
1586 if (term->is_searching) {
1587 if (should_repeat)
1588 start_repeater(seat, key);
1589
1590 search_input(
1591 seat, term, key, sym, bind_mods, bind_consumed,
1592 raw_syms, raw_count, serial);
1593 return;
1594 }
1595
1596 else if (urls_mode_is_active(term)) {
1597 if (should_repeat)
1598 start_repeater(seat, key);
1599
1600 urls_input(
1601 seat, term, key, sym, bind_mods, bind_consumed,
1602 raw_syms, raw_count, serial);
1603 return;
1604 }
1605 }
1606
1607 #if 0
1608 for (size_t i = 0; i < 32; i++) {
1609 if (mods & (1 << i)) {
1610 LOG_INFO("%s", xkb_keymap_mod_get_name(seat->kbd.xkb_keymap, i));
1611 }
1612 }
1613 #endif
1614
1615 #if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
1616 char sym_name[100];
1617 xkb_keysym_get_name(sym, sym_name, sizeof(sym_name));
1618
1619 LOG_DBG("%s (%u/0x%x): seat=%s, term=%p, serial=%u, "
1620 "mods=0x%08x, consumed=0x%08x, repeats=%d",
1621 sym_name, sym, sym, seat->name, (void *)term, serial,
1622 mods, consumed, should_repeat);
1623 #endif
1624
1625 /*
1626 * User configurable bindings
1627 */
1628 if (pressed) {
1629 tll_foreach(seat->kbd.bindings.key, it) {
1630 const struct key_binding *bind = &it->item;
1631
1632 /* Match translated symbol */
1633 if (bind->sym == sym &&
1634 bind->mods == (bind_mods & ~bind_consumed) &&
1635 execute_binding(
1636 seat, term, bind->action, bind->pipe_argv, serial))
1637 {
1638 goto maybe_repeat;
1639 }
1640
1641 if (bind->mods != bind_mods)
1642 continue;
1643
1644 /* Match untranslated symbols */
1645 for (size_t i = 0; i < raw_count; i++) {
1646 if (bind->sym == raw_syms[i] && execute_binding(
1647 seat, term, bind->action, bind->pipe_argv, serial))
1648 {
1649 goto maybe_repeat;
1650 }
1651 }
1652
1653 /* Match raw key code */
1654 tll_foreach(bind->key_codes, code) {
1655 if (code->item == key && execute_binding(
1656 seat, term, bind->action, bind->pipe_argv, serial))
1657 {
1658 goto maybe_repeat;
1659 }
1660 }
1661 }
1662 }
1663
1664 /*
1665 * Keys generating escape sequences
1666 */
1667
1668
1669 /*
1670 * Compose, and maybe emit "normal" character
1671 */
1672
1673 xassert(seat->kbd.xkb_compose_state != NULL || !composed);
1674
1675 if (compose_status == XKB_COMPOSE_CANCELLED)
1676 goto maybe_repeat;
1677
1678 int count = composed
1679 ? xkb_compose_state_get_utf8(seat->kbd.xkb_compose_state, NULL, 0)
1680 : xkb_state_key_get_utf8(seat->kbd.xkb_state, key, NULL, 0);
1681
1682 /* Buffer for translated key. Use a static buffer in most cases,
1683 * and use a malloc:ed buffer when necessary */
1684 uint8_t buf[32];
1685 uint8_t *utf8 = count < sizeof(buf) ? buf : xmalloc(count + 1);
1686 uint32_t utf32 = (uint32_t)-1;
1687
1688 if (composed) {
1689 xkb_compose_state_get_utf8(
1690 seat->kbd.xkb_compose_state, (char *)utf8, count + 1);
1691
1692 wchar_t wc;
1693 if (mbtowc(&wc, (const char *)utf8, count) == count)
1694 utf32 = wc;
1695 } else {
1696 xkb_state_key_get_utf8(
1697 seat->kbd.xkb_state, key, (char *)utf8, count + 1);
1698 utf32 = xkb_state_key_get_utf32(seat->kbd.xkb_state, key);
1699 }
1700
1701 struct kbd_ctx ctx = {
1702 .layout = layout_idx,
1703 .key = key,
1704 .sym = sym,
1705 .level0_syms = {
1706 .syms = raw_syms,
1707 .count = raw_count,
1708 },
1709 .mods = mods,
1710 .consumed = consumed,
1711 .utf8 = {
1712 .buf = utf8,
1713 .count = count,
1714 },
1715 .utf32 = utf32,
1716 .compose_status = compose_status,
1717 .key_state = state,
1718 };
1719
1720 bool handled = term->grid->kitty_kbd.flags[term->grid->kitty_kbd.idx] != 0
1721 ? kitty_kbd_protocol(seat, term, &ctx)
1722 : legacy_kbd_protocol(seat, term, &ctx);
1723
1724 if (composed && released)
1725 xkb_compose_state_reset(seat->kbd.xkb_compose_state);
1726
1727 if (utf8 != buf)
1728 free(utf8);
1729
1730 if (handled) {
1731 term_reset_view(term);
1732 selection_cancel(term);
1733 }
1734
1735 maybe_repeat:
1736 clock_gettime(
1737 term->wl->presentation_clock_id, &term->render.input_time);
1738
1739 if (should_repeat)
1740 start_repeater(seat, key);
1741 }
1742
1743 static void
keyboard_key(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)1744 keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
1745 uint32_t time, uint32_t key, uint32_t state)
1746 {
1747 struct seat *seat = data;
1748 key_press_release(seat, seat->kbd_focus, serial, key + 8, state);
1749 }
1750
1751 static void
keyboard_modifiers(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)1752 keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
1753 uint32_t mods_depressed, uint32_t mods_latched,
1754 uint32_t mods_locked, uint32_t group)
1755 {
1756 struct seat *seat = data;
1757
1758 LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u",
1759 mods_depressed, mods_latched, mods_locked, group);
1760
1761 if (seat->kbd.xkb_state != NULL) {
1762 xkb_state_update_mask(
1763 seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
1764
1765 /* Update state of modifiers we're interested in for e.g mouse events */
1766 seat->kbd.shift = seat->kbd.mod_shift != XKB_MOD_INVALID
1767 ? xkb_state_mod_index_is_active(
1768 seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_EFFECTIVE)
1769 : false;
1770 seat->kbd.alt = seat->kbd.mod_alt != XKB_MOD_INVALID
1771 ? xkb_state_mod_index_is_active(
1772 seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_EFFECTIVE)
1773 : false;
1774 seat->kbd.ctrl = seat->kbd.mod_ctrl != XKB_MOD_INVALID
1775 ? xkb_state_mod_index_is_active(
1776 seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_EFFECTIVE)
1777 : false;
1778 seat->kbd.super = seat->kbd.mod_super != XKB_MOD_INVALID
1779 ? xkb_state_mod_index_is_active(
1780 seat->kbd.xkb_state, seat->kbd.mod_super, XKB_STATE_MODS_EFFECTIVE)
1781 : false;
1782 }
1783
1784 if (seat->kbd_focus && seat->kbd_focus->active_surface == TERM_SURF_GRID)
1785 term_xcursor_update_for_seat(seat->kbd_focus, seat);
1786 }
1787
1788 static void
keyboard_repeat_info(void * data,struct wl_keyboard * wl_keyboard,int32_t rate,int32_t delay)1789 keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
1790 int32_t rate, int32_t delay)
1791 {
1792 struct seat *seat = data;
1793 LOG_DBG("keyboard repeat: rate=%d, delay=%d", rate, delay);
1794 seat->kbd.repeat.rate = rate;
1795 seat->kbd.repeat.delay = delay;
1796 }
1797
1798 const struct wl_keyboard_listener keyboard_listener = {
1799 .keymap = &keyboard_keymap,
1800 .enter = &keyboard_enter,
1801 .leave = &keyboard_leave,
1802 .key = &keyboard_key,
1803 .modifiers = &keyboard_modifiers,
1804 .repeat_info = &keyboard_repeat_info,
1805 };
1806
1807 void
input_repeat(struct seat * seat,uint32_t key)1808 input_repeat(struct seat *seat, uint32_t key)
1809 {
1810 /* Should be cleared as soon as we loose focus */
1811 xassert(seat->kbd_focus != NULL);
1812 struct terminal *term = seat->kbd_focus;
1813
1814 key_press_release(seat, term, seat->kbd.serial, key, XKB_KEY_DOWN);
1815 }
1816
1817 static bool
is_top_left(const struct terminal * term,int x,int y)1818 is_top_left(const struct terminal *term, int x, int y)
1819 {
1820 int csd_border_size = term->conf->csd.border_width;
1821 return (
1822 (!term->window->is_tiled_top && !term->window->is_tiled_left) &&
1823 ((term->active_surface == TERM_SURF_BORDER_LEFT && y < 10 * term->scale) ||
1824 (term->active_surface == TERM_SURF_BORDER_TOP && x < (10 + csd_border_size) * term->scale)));
1825 }
1826
1827 static bool
is_top_right(const struct terminal * term,int x,int y)1828 is_top_right(const struct terminal *term, int x, int y)
1829 {
1830 int csd_border_size = term->conf->csd.border_width;
1831 return (
1832 (!term->window->is_tiled_top && !term->window->is_tiled_right) &&
1833 ((term->active_surface == TERM_SURF_BORDER_RIGHT && y < 10 * term->scale) ||
1834 (term->active_surface == TERM_SURF_BORDER_TOP && x > term->width + 1 * csd_border_size * term->scale - 10 * term->scale)));
1835 }
1836
1837 static bool
is_bottom_left(const struct terminal * term,int x,int y)1838 is_bottom_left(const struct terminal *term, int x, int y)
1839 {
1840 int csd_title_size = term->conf->csd.title_height;
1841 int csd_border_size = term->conf->csd.border_width;
1842 return (
1843 (!term->window->is_tiled_bottom && !term->window->is_tiled_left) &&
1844 ((term->active_surface == TERM_SURF_BORDER_LEFT && y > csd_title_size * term->scale + term->height) ||
1845 (term->active_surface == TERM_SURF_BORDER_BOTTOM && x < (10 + csd_border_size) * term->scale)));
1846 }
1847
1848 static bool
is_bottom_right(const struct terminal * term,int x,int y)1849 is_bottom_right(const struct terminal *term, int x, int y)
1850 {
1851 int csd_title_size = term->conf->csd.title_height;
1852 int csd_border_size = term->conf->csd.border_width;
1853 return (
1854 (!term->window->is_tiled_bottom && !term->window->is_tiled_right) &&
1855 ((term->active_surface == TERM_SURF_BORDER_RIGHT && y > csd_title_size * term->scale + term->height) ||
1856 (term->active_surface == TERM_SURF_BORDER_BOTTOM && x > term->width + 1 * csd_border_size * term->scale - 10 * term->scale)));
1857 }
1858
1859 const char *
xcursor_for_csd_border(struct terminal * term,int x,int y)1860 xcursor_for_csd_border(struct terminal *term, int x, int y)
1861 {
1862 if (is_top_left(term, x, y)) return XCURSOR_TOP_LEFT_CORNER;
1863 else if (is_top_right(term, x, y)) return XCURSOR_TOP_RIGHT_CORNER;
1864 else if (is_bottom_left(term, x, y)) return XCURSOR_BOTTOM_LEFT_CORNER;
1865 else if (is_bottom_right(term, x, y)) return XCURSOR_BOTTOM_RIGHT_CORNER;
1866 else if (term->active_surface == TERM_SURF_BORDER_LEFT) return XCURSOR_LEFT_SIDE;
1867 else if (term->active_surface == TERM_SURF_BORDER_RIGHT) return XCURSOR_RIGHT_SIDE;
1868 else if (term->active_surface == TERM_SURF_BORDER_TOP) return XCURSOR_TOP_SIDE;
1869 else if (term->active_surface == TERM_SURF_BORDER_BOTTOM) return XCURSOR_BOTTOM_SIDE;
1870 else {
1871 BUG("Unreachable");
1872 return NULL;
1873 }
1874 }
1875
1876 static void
wl_pointer_enter(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface,wl_fixed_t surface_x,wl_fixed_t surface_y)1877 wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
1878 uint32_t serial, struct wl_surface *surface,
1879 wl_fixed_t surface_x, wl_fixed_t surface_y)
1880 {
1881 xassert(surface != NULL);
1882
1883 if (surface == NULL) {
1884 /* Seen on mutter-3.38 */
1885 return;
1886 }
1887
1888 struct seat *seat = data;
1889 struct wl_window *win = wl_surface_get_user_data(surface);
1890 struct terminal *term = win->term;
1891
1892 int x = wl_fixed_to_int(surface_x) * term->scale;
1893 int y = wl_fixed_to_int(surface_y) * term->scale;
1894
1895 seat->pointer.serial = serial;
1896 seat->pointer.hidden = false;
1897 seat->mouse.x = x;
1898 seat->mouse.y = y;
1899
1900 LOG_DBG("pointer-enter: pointer=%p, serial=%u, surface = %p, new-moused = %p, "
1901 "x=%d, y=%d",
1902 (void *)wl_pointer, serial, (void *)surface, (void *)term,
1903 x, y);
1904
1905 xassert(tll_length(seat->mouse.buttons) == 0);
1906
1907 seat->mouse_focus = term;
1908 term->active_surface = term_surface_kind(term, surface);
1909
1910 wayl_reload_xcursor_theme(seat, term->scale); /* Scale may have changed */
1911 term_xcursor_update_for_seat(term, seat);
1912
1913 switch (term->active_surface) {
1914 case TERM_SURF_GRID: {
1915 /*
1916 * Translate x,y pixel coordinate to a cell coordinate, or -1
1917 * if the cursor is outside the grid. I.e. if it is inside the
1918 * margins.
1919 */
1920
1921 if (x < term->margins.left || x >= term->width - term->margins.right)
1922 seat->mouse.col = -1;
1923 else
1924 seat->mouse.col = (x - term->margins.left) / term->cell_width;
1925
1926 if (y < term->margins.top || y >= term->height - term->margins.bottom)
1927 seat->mouse.row = -1;
1928 else
1929 seat->mouse.row = (y - term->margins.top) / term->cell_height;
1930
1931 break;
1932 }
1933
1934 case TERM_SURF_SEARCH:
1935 case TERM_SURF_SCROLLBACK_INDICATOR:
1936 case TERM_SURF_RENDER_TIMER:
1937 case TERM_SURF_JUMP_LABEL:
1938 case TERM_SURF_TITLE:
1939 case TERM_SURF_BORDER_LEFT:
1940 case TERM_SURF_BORDER_RIGHT:
1941 case TERM_SURF_BORDER_TOP:
1942 case TERM_SURF_BORDER_BOTTOM:
1943 break;
1944
1945 case TERM_SURF_BUTTON_MINIMIZE:
1946 case TERM_SURF_BUTTON_MAXIMIZE:
1947 case TERM_SURF_BUTTON_CLOSE:
1948 render_refresh_csd(term);
1949 break;
1950
1951 case TERM_SURF_NONE:
1952 BUG("Invalid surface type");
1953 break;
1954 }
1955 }
1956
1957 static void
wl_pointer_leave(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface)1958 wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
1959 uint32_t serial, struct wl_surface *surface)
1960 {
1961 struct seat *seat = data;
1962 struct terminal *old_moused = seat->mouse_focus;
1963
1964 LOG_DBG(
1965 "%s: pointer-leave: pointer=%p, serial=%u, surface = %p, old-moused = %p",
1966 seat->name, (void *)wl_pointer, serial, (void *)surface,
1967 (void *)old_moused);
1968
1969 seat->pointer.hidden = false;
1970
1971 if (seat->pointer.xcursor_callback != NULL) {
1972 /* A cursor frame callback may never be called if the pointer leaves our surface */
1973 wl_callback_destroy(seat->pointer.xcursor_callback);
1974 seat->pointer.xcursor_callback = NULL;
1975 seat->pointer.xcursor_pending = false;
1976 }
1977
1978 /* Reset last-set-xcursor, to ensure we update it on a pointer-enter event */
1979 seat->pointer.xcursor = NULL;
1980
1981 /* Reset mouse state */
1982 seat->mouse.x = seat->mouse.y = 0;
1983 seat->mouse.col = seat->mouse.row = 0;
1984 tll_free(seat->mouse.buttons);
1985 seat->mouse.count = 0;
1986 seat->mouse.last_released_button = 0;
1987 memset(&seat->mouse.last_time, 0, sizeof(seat->mouse.last_time));
1988 for (size_t i = 0; i < ALEN(seat->mouse.aggregated); i++)
1989 seat->mouse.aggregated[i] = 0.0;
1990 seat->mouse.have_discrete = false;
1991
1992 seat->mouse_focus = NULL;
1993 if (old_moused == NULL) {
1994 LOG_WARN(
1995 "compositor sent pointer_leave event without a pointer_enter "
1996 "event: surface=%p", (void *)surface);
1997 } else {
1998 if (surface != NULL) {
1999 /* Sway 1.4 sends this event with a NULL surface when we destroy the window */
2000 const struct wl_window UNUSED *win = wl_surface_get_user_data(surface);
2001 xassert(old_moused == win->term);
2002 }
2003
2004 enum term_surface active_surface = old_moused->active_surface;
2005
2006 old_moused->active_surface = TERM_SURF_NONE;
2007
2008 switch (active_surface) {
2009 case TERM_SURF_BUTTON_MINIMIZE:
2010 case TERM_SURF_BUTTON_MAXIMIZE:
2011 case TERM_SURF_BUTTON_CLOSE:
2012 if (old_moused->shutdown.in_progress)
2013 break;
2014
2015 render_refresh_csd(old_moused);
2016 break;
2017
2018 case TERM_SURF_GRID:
2019 selection_finalize(seat, old_moused, seat->pointer.serial);
2020 break;
2021
2022 case TERM_SURF_NONE:
2023 case TERM_SURF_SEARCH:
2024 case TERM_SURF_SCROLLBACK_INDICATOR:
2025 case TERM_SURF_RENDER_TIMER:
2026 case TERM_SURF_JUMP_LABEL:
2027 case TERM_SURF_TITLE:
2028 case TERM_SURF_BORDER_LEFT:
2029 case TERM_SURF_BORDER_RIGHT:
2030 case TERM_SURF_BORDER_TOP:
2031 case TERM_SURF_BORDER_BOTTOM:
2032 break;
2033 }
2034
2035 }
2036 }
2037
2038 static void
wl_pointer_motion(void * data,struct wl_pointer * wl_pointer,uint32_t time,wl_fixed_t surface_x,wl_fixed_t surface_y)2039 wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
2040 uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
2041 {
2042 struct seat *seat = data;
2043 struct wayland *wayl = seat->wayl;
2044 struct terminal *term = seat->mouse_focus;
2045 struct wl_window *win = term->window;
2046
2047 LOG_DBG("pointer_motion: pointer=%p, x=%d, y=%d", (void *)wl_pointer,
2048 wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y));
2049
2050 xassert(term != NULL);
2051
2052 int x = wl_fixed_to_int(surface_x) * term->scale;
2053 int y = wl_fixed_to_int(surface_y) * term->scale;
2054
2055 seat->pointer.hidden = false;
2056 seat->mouse.x = x;
2057 seat->mouse.y = y;
2058
2059 term_xcursor_update_for_seat(term, seat);
2060
2061 enum term_surface surf_kind = term->active_surface;
2062 int button = 0;
2063 bool send_to_client = false;
2064
2065 if (tll_length(seat->mouse.buttons) > 0) {
2066 const struct button_tracker *tracker = &tll_front(seat->mouse.buttons);
2067 surf_kind = tracker->surf_kind;
2068 button = tracker->button;
2069 send_to_client = tracker->send_to_client;
2070 }
2071
2072 switch (surf_kind) {
2073 case TERM_SURF_NONE:
2074 case TERM_SURF_SEARCH:
2075 case TERM_SURF_SCROLLBACK_INDICATOR:
2076 case TERM_SURF_RENDER_TIMER:
2077 case TERM_SURF_JUMP_LABEL:
2078 case TERM_SURF_BUTTON_MINIMIZE:
2079 case TERM_SURF_BUTTON_MAXIMIZE:
2080 case TERM_SURF_BUTTON_CLOSE:
2081 break;
2082
2083 case TERM_SURF_TITLE:
2084 /* We've started a 'move' timer, but user started dragging
2085 * right away - abort the timer and initiate the actual move
2086 * right away */
2087 if (button == BTN_LEFT && win->csd.move_timeout_fd != -1) {
2088 fdm_del(wayl->fdm, win->csd.move_timeout_fd);
2089 win->csd.move_timeout_fd = -1;
2090 xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
2091 }
2092 break;
2093
2094 case TERM_SURF_BORDER_LEFT:
2095 case TERM_SURF_BORDER_RIGHT:
2096 case TERM_SURF_BORDER_TOP:
2097 case TERM_SURF_BORDER_BOTTOM:
2098 break;
2099
2100 case TERM_SURF_GRID: {
2101 int old_col = seat->mouse.col;
2102 int old_row = seat->mouse.row;
2103
2104 /*
2105 * While the seat's mouse coordinates must always be on the
2106 * grid, or -1, we allow updating the selection even when the
2107 * mouse is outside the grid (could also be outside the
2108 * terminal window).
2109 */
2110 int selection_col;
2111 int selection_row;
2112
2113 if (x < term->margins.left) {
2114 seat->mouse.col = -1;
2115 selection_col = 0;
2116 } else if (x >= term->width - term->margins.right) {
2117 seat->mouse.col = -1;
2118 selection_col = term->cols - 1;
2119 } else {
2120 seat->mouse.col = (x - term->margins.left) / term->cell_width;
2121 selection_col = seat->mouse.col;
2122 }
2123
2124 if (y < term->margins.top) {
2125 seat->mouse.row = -1;
2126 selection_row = 0;
2127 } else if (y >= term->height - term->margins.bottom) {
2128 seat->mouse.row = -1;
2129 selection_row = term->rows - 1;
2130 } else {
2131 seat->mouse.row = (y - term->margins.top) / term->cell_height;
2132 selection_row = seat->mouse.row;
2133 }
2134
2135 /*
2136 * If client is receiving events (because the button was
2137 * pressed while the cursor was inside the grid area), then
2138 * make sure it receives valid coordinates.
2139 */
2140 if (send_to_client) {
2141 seat->mouse.col = selection_col;
2142 seat->mouse.row = selection_row;
2143 }
2144
2145 xassert(seat->mouse.col == -1 || (seat->mouse.col >= 0 && seat->mouse.col < term->cols));
2146 xassert(seat->mouse.row == -1 || (seat->mouse.row >= 0 && seat->mouse.row < term->rows));
2147
2148 /* Cursor has moved to a different cell since last time */
2149 bool cursor_is_on_new_cell
2150 = old_col != seat->mouse.col || old_row != seat->mouse.row;
2151
2152 /* Cursor is inside the grid, i.e. *not* in the margins */
2153 const bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0;
2154
2155 enum selection_scroll_direction auto_scroll_direction
2156 = y < term->margins.top ? SELECTION_SCROLL_UP
2157 : y > term->height - term->margins.bottom ? SELECTION_SCROLL_DOWN
2158 : SELECTION_SCROLL_NOT;
2159
2160 if (auto_scroll_direction == SELECTION_SCROLL_NOT)
2161 selection_stop_scroll_timer(term);
2162
2163 /* Update selection */
2164 if (!term->is_searching) {
2165 if (auto_scroll_direction != SELECTION_SCROLL_NOT) {
2166 /*
2167 * Start ‘selection auto-scrolling’
2168 *
2169 * The speed of the scrolling is proportional to the
2170 * distance between the mouse and the grid; the
2171 * further away the mouse is, the faster we scroll.
2172 *
2173 * Note that the speed is measured in ‘intervals (in
2174 * ns) between each timed scroll of a single line’.
2175 *
2176 * Thus, the further away the mouse is, the smaller
2177 * interval value we use.
2178 */
2179
2180 int distance = auto_scroll_direction == SELECTION_SCROLL_UP
2181 ? term->margins.top - y
2182 : y - (term->height - term->margins.bottom);
2183
2184 xassert(distance > 0);
2185 int divisor
2186 = distance * term->conf->scrollback.multiplier / term->scale;
2187
2188 selection_start_scroll_timer(
2189 term, 400000000 / (divisor > 0 ? divisor : 1),
2190 auto_scroll_direction, selection_col);
2191 }
2192
2193 if (term->selection.ongoing && (cursor_is_on_new_cell ||
2194 term->selection.end.row < 0))
2195 {
2196 selection_update(term, selection_col, selection_row);
2197 }
2198 }
2199
2200 /* Send mouse event to client application */
2201 if (!term_mouse_grabbed(term, seat) &&
2202 cursor_is_on_new_cell &&
2203 ((button == 0 && cursor_is_on_grid) ||
2204 (button != 0 && send_to_client)))
2205 {
2206 xassert(seat->mouse.col < term->cols);
2207 xassert(seat->mouse.row < term->rows);
2208
2209 term_mouse_motion(
2210 term, button,
2211 seat->mouse.row, seat->mouse.col,
2212 seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
2213 }
2214 break;
2215 }
2216 }
2217 }
2218
2219 static bool
fdm_csd_move(struct fdm * fdm,int fd,int events,void * data)2220 fdm_csd_move(struct fdm *fdm, int fd, int events, void *data)
2221 {
2222 struct seat *seat = data;
2223 fdm_del(fdm, fd);
2224
2225 if (seat->mouse_focus == NULL) {
2226 LOG_WARN(
2227 "%s: CSD move timeout triggered, but seat's has no mouse focused terminal",
2228 seat->name);
2229 return true;
2230 }
2231
2232 struct wl_window *win = seat->mouse_focus->window;
2233
2234 win->csd.move_timeout_fd = -1;
2235 xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
2236 return true;
2237 }
2238
2239 static void
wl_pointer_button(void * data,struct wl_pointer * wl_pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state)2240 wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
2241 uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
2242 {
2243 LOG_DBG("BUTTON: pointer=%p, serial=%u, button=%x, state=%u",
2244 (void *)wl_pointer, serial, button, state);
2245
2246 struct seat *seat = data;
2247 struct wayland *wayl = seat->wayl;
2248 struct terminal *term = seat->mouse_focus;
2249
2250 seat->pointer.serial = serial;
2251 seat->pointer.hidden = false;
2252
2253 xassert(term != NULL);
2254
2255 enum term_surface surf_kind = TERM_SURF_NONE;
2256 bool send_to_client = false;
2257
2258 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
2259 /* Time since last click */
2260 struct timeval now, since_last;
2261 gettimeofday(&now, NULL);
2262 timersub(&now, &seat->mouse.last_time, &since_last);
2263
2264 if (seat->mouse.last_released_button == button &&
2265 since_last.tv_sec == 0 && since_last.tv_usec <= 300 * 1000)
2266 {
2267 seat->mouse.count++;
2268 } else
2269 seat->mouse.count = 1;
2270
2271 /*
2272 * Workaround GNOME bug
2273 *
2274 * Dragging the window, then stopping the drag (releasing the
2275 * mouse button), *without* moving the mouse, and then
2276 * clicking twice, waiting for the CSD timer, and finally
2277 * clicking once more, results in the following sequence
2278 * (keyboard and other irrelevant events filtered out, unless
2279 * they’re needed to prove a point):
2280 *
2281 * dbg: input.c:1551: cancelling drag timer, moving window
2282 * dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=873, surface=0x6070000036d0
2283 * dbg: input.c:1432: seat0: pointer-leave: pointer=0x607000003660, serial=874, surface = 0x6070000396e0, old-moused = 0x622000006100
2284 *
2285 * --> drag stopped here
2286 *
2287 * --> LMB clicked first time after the drag (generates the
2288 * enter event on *release*, but no button events)
2289 * dbg: input.c:1360: pointer-enter: pointer=0x607000003660, serial=876, surface = 0x6070000396e0, new-moused = 0x622000006100
2290 *
2291 * --> LMB clicked, and held until the timer times out, second
2292 * time after the drag
2293 * dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=877, button=110, state=1
2294 * dbg: input.c:1806: starting move timer
2295 * dbg: input.c:1692: move timer timed out
2296 * dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=878, surface=0x6070000036d0
2297 *
2298 * --> NOTE: ^^ no pointer leave event this time, only the
2299 * keyboard leave
2300 *
2301 * --> LMB clicked one last time
2302 * dbg: input.c:697: seat0: keyboard_enter: keyboard=0x607000003580, serial=879, surface=0x6070000036d0
2303 * dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=880, button=110, state=1
2304 * err: input.c:1741: BUG in wl_pointer_button(): assertion failed: 'it->item.button != button'
2305 *
2306 * What are we seeing?
2307 *
2308 * - GNOME does *not* send a pointer *enter* event after the drag
2309 * has stopped
2310 * - The second drag does *not* generate a pointer *leave* event
2311 * - The missing leave event means we’re still tracking LMB as
2312 * being held down in our seat struct.
2313 * - This leads to an assert (debug builds) when LMB is clicked
2314 * again (seat’s button list already contains LMB).
2315 *
2316 * Note: I’ve also observed variants of the above
2317 */
2318 tll_foreach(seat->mouse.buttons, it) {
2319 if (it->item.button == button) {
2320 LOG_WARN("multiple button press events for button %d "
2321 "(compositor bug?)", button);
2322 tll_remove(seat->mouse.buttons, it);
2323 break;
2324 }
2325 }
2326
2327 #if defined(_DEBUG)
2328 tll_foreach(seat->mouse.buttons, it)
2329 xassert(it->item.button != button);
2330 #endif
2331
2332 /*
2333 * Remember which surface "owns" this button, so that we can
2334 * send motion and button release events to that surface, even
2335 * if the pointer is no longer over it.
2336 */
2337 tll_push_back(
2338 seat->mouse.buttons,
2339 ((struct button_tracker){
2340 .button = button,
2341 .surf_kind = term->active_surface,
2342 .send_to_client = false}));
2343
2344 seat->mouse.last_time = now;
2345
2346 surf_kind = term->active_surface;
2347 send_to_client = false; /* For now, may be set to true if a binding consumes the button */
2348 } else {
2349 bool UNUSED have_button = false;
2350 tll_foreach(seat->mouse.buttons, it) {
2351 if (it->item.button == button) {
2352 have_button = true;
2353 surf_kind = it->item.surf_kind;
2354 send_to_client = it->item.send_to_client;
2355 tll_remove(seat->mouse.buttons, it);
2356 break;
2357 }
2358 }
2359
2360 if (!have_button) {
2361 /*
2362 * Seen on Sway with slurp
2363 *
2364 * 1. Run slurp
2365 * 2. Press, and hold left mouse button
2366 * 3. Press escape, to cancel slurp
2367 * 4. Release mouse button
2368 * 5. BAM!
2369 */
2370 LOG_WARN("stray button release event (compositor bug?)");
2371 return;
2372 }
2373
2374 seat->mouse.last_released_button = button;
2375 }
2376
2377 switch (surf_kind) {
2378 case TERM_SURF_TITLE:
2379 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
2380
2381 struct wl_window *win = term->window;
2382
2383 /* Toggle maximized state on double-click */
2384 if (button == BTN_LEFT && seat->mouse.count == 2) {
2385 if (win->is_maximized)
2386 xdg_toplevel_unset_maximized(win->xdg_toplevel);
2387 else
2388 xdg_toplevel_set_maximized(win->xdg_toplevel);
2389 }
2390
2391 else if (button == BTN_LEFT && win->csd.move_timeout_fd < 0) {
2392 const struct itimerspec timeout = {
2393 .it_value = {.tv_nsec = 200000000},
2394 };
2395
2396 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
2397 if (fd >= 0 &&
2398 timerfd_settime(fd, 0, &timeout, NULL) == 0 &&
2399 fdm_add(wayl->fdm, fd, EPOLLIN, &fdm_csd_move, seat))
2400 {
2401 win->csd.move_timeout_fd = fd;
2402 win->csd.serial = serial;
2403 } else {
2404 LOG_ERRNO("failed to configure XDG toplevel move timer FD");
2405 if (fd >= 0)
2406 close(fd);
2407 }
2408 }
2409
2410 if (button == BTN_RIGHT && tll_length(seat->mouse.buttons) == 1) {
2411 const struct csd_data info = get_csd_data(term, CSD_SURF_TITLE);
2412 xdg_toplevel_show_window_menu(
2413 win->xdg_toplevel,
2414 seat->wl_seat,
2415 seat->pointer.serial,
2416 seat->mouse.x + info.x, seat->mouse.y + info.y);
2417 }
2418 }
2419
2420 else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
2421 struct wl_window *win = term->window;
2422 if (win->csd.move_timeout_fd >= 0) {
2423 fdm_del(wayl->fdm, win->csd.move_timeout_fd);
2424 win->csd.move_timeout_fd = -1;
2425 }
2426 }
2427 return;
2428
2429 case TERM_SURF_BORDER_LEFT:
2430 case TERM_SURF_BORDER_RIGHT:
2431 case TERM_SURF_BORDER_TOP:
2432 case TERM_SURF_BORDER_BOTTOM: {
2433 static const enum xdg_toplevel_resize_edge map[] = {
2434 [TERM_SURF_BORDER_LEFT] = XDG_TOPLEVEL_RESIZE_EDGE_LEFT,
2435 [TERM_SURF_BORDER_RIGHT] = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT,
2436 [TERM_SURF_BORDER_TOP] = XDG_TOPLEVEL_RESIZE_EDGE_TOP,
2437 [TERM_SURF_BORDER_BOTTOM] = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM,
2438 };
2439
2440 if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
2441 enum xdg_toplevel_resize_edge resize_type;
2442
2443 int x = seat->mouse.x;
2444 int y = seat->mouse.y;
2445
2446 if (is_top_left(term, x, y))
2447 resize_type = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
2448 else if (is_top_right(term, x, y))
2449 resize_type = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
2450 else if (is_bottom_left(term, x, y))
2451 resize_type = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
2452 else if (is_bottom_right(term, x, y))
2453 resize_type = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
2454 else
2455 resize_type = map[term->active_surface];
2456
2457 xdg_toplevel_resize(
2458 term->window->xdg_toplevel, seat->wl_seat, serial, resize_type);
2459 }
2460 return;
2461 }
2462
2463 case TERM_SURF_BUTTON_MINIMIZE:
2464 if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
2465 xdg_toplevel_set_minimized(term->window->xdg_toplevel);
2466 break;
2467
2468 case TERM_SURF_BUTTON_MAXIMIZE:
2469 if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
2470 if (term->window->is_maximized)
2471 xdg_toplevel_unset_maximized(term->window->xdg_toplevel);
2472 else
2473 xdg_toplevel_set_maximized(term->window->xdg_toplevel);
2474 }
2475 break;
2476
2477 case TERM_SURF_BUTTON_CLOSE:
2478 if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
2479 term_shutdown(term);
2480 break;
2481
2482 case TERM_SURF_SEARCH:
2483 case TERM_SURF_SCROLLBACK_INDICATOR:
2484 case TERM_SURF_RENDER_TIMER:
2485 case TERM_SURF_JUMP_LABEL:
2486 break;
2487
2488 case TERM_SURF_GRID: {
2489 search_cancel(term);
2490 urls_reset(term);
2491
2492 bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0;
2493
2494 switch (state) {
2495 case WL_POINTER_BUTTON_STATE_PRESSED: {
2496 bool consumed = false;
2497
2498 if (cursor_is_on_grid && term_mouse_grabbed(term, seat)) {
2499 if (seat->wl_keyboard != NULL && seat->kbd.xkb_state != NULL) {
2500 /* Seat has keyboard - use mouse bindings *with* modifiers */
2501
2502 xkb_mod_mask_t mods;
2503 get_current_modifiers(seat, &mods, NULL, 0);
2504 mods &= seat->kbd.bind_significant;
2505
2506 /* Ignore Shift when matching modifiers, since it is
2507 * used to enable selection in mouse grabbing client
2508 * applications */
2509 if (seat->kbd.mod_shift != XKB_MOD_INVALID)
2510 mods &= ~(1 << seat->kbd.mod_shift);
2511
2512 const struct mouse_binding *match = NULL;
2513
2514 tll_foreach(seat->mouse.bindings, it) {
2515 const struct mouse_binding *binding = &it->item;
2516
2517 if (binding->button != button) {
2518 /* Wrong button */
2519 continue;
2520 }
2521
2522 if (binding->mods != mods) {
2523 /* Modifier mismatch */
2524 continue;
2525 }
2526
2527 if (binding->count > seat->mouse.count) {
2528 /* Not correct click count */
2529 continue;
2530 }
2531
2532 if (match == NULL || binding->count > match->count)
2533 match = binding;
2534 }
2535
2536 if (match != NULL) {
2537 consumed = execute_binding(
2538 seat, term, match->action, match->pipe_argv, serial);
2539 }
2540 }
2541
2542 else {
2543 /* Seat does NOT have a keyboard - use mouse bindings *without* modifiers */
2544 const struct config_mouse_binding *match = NULL;
2545 const struct config *conf = seat->wayl->conf;
2546
2547 for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
2548 const struct config_mouse_binding *binding =
2549 &conf->bindings.mouse.arr[i];
2550
2551 if (binding->button != button) {
2552 /* Wrong button */
2553 continue;
2554 }
2555
2556 if (binding->count > seat->mouse.count) {
2557 /* Incorrect click count */
2558 continue;
2559 }
2560
2561 const struct config_key_modifiers no_mods = {0};
2562 if (memcmp(&binding->modifiers, &no_mods, sizeof(no_mods)) != 0) {
2563 /* Binding has modifiers */
2564 continue;
2565 }
2566
2567 if (match == NULL || binding->count > match->count)
2568 match = binding;
2569 }
2570
2571 if (match != NULL) {
2572 consumed = execute_binding(
2573 seat, term, match->action, match->pipe.argv.args,
2574 serial);
2575 }
2576 }
2577 }
2578
2579 send_to_client = !consumed && cursor_is_on_grid;
2580
2581 if (send_to_client)
2582 tll_back(seat->mouse.buttons).send_to_client = true;
2583
2584 if (send_to_client &&
2585 !term_mouse_grabbed(term, seat) &&
2586 cursor_is_on_grid)
2587 {
2588 term_mouse_down(
2589 term, button, seat->mouse.row, seat->mouse.col,
2590 seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
2591 }
2592 break;
2593 }
2594
2595 case WL_POINTER_BUTTON_STATE_RELEASED:
2596 selection_finalize(seat, term, serial);
2597
2598 if (send_to_client && !term_mouse_grabbed(term, seat)) {
2599 term_mouse_up(
2600 term, button, seat->mouse.row, seat->mouse.col,
2601 seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
2602 }
2603 break;
2604 }
2605 break;
2606 }
2607
2608 case TERM_SURF_NONE:
2609 BUG("Invalid surface type");
2610 break;
2611
2612 }
2613 }
2614
2615 static void
alternate_scroll(struct seat * seat,int amount,int button)2616 alternate_scroll(struct seat *seat, int amount, int button)
2617 {
2618 if (seat->wl_keyboard == NULL)
2619 return;
2620
2621 /* Should be cleared in leave event */
2622 xassert(seat->mouse_focus != NULL);
2623 struct terminal *term = seat->mouse_focus;
2624
2625 assert(button == BTN_BACK || button == BTN_FORWARD);
2626
2627 xkb_keycode_t key = button == BTN_BACK
2628 ? seat->kbd.key_arrow_up : seat->kbd.key_arrow_down;
2629
2630 for (int i = 0; i < amount; i++)
2631 key_press_release(seat, term, seat->kbd.serial, key, XKB_KEY_DOWN);
2632 key_press_release(seat, term, seat->kbd.serial, key, XKB_KEY_UP);
2633 }
2634
2635 static void
mouse_scroll(struct seat * seat,int amount,enum wl_pointer_axis axis)2636 mouse_scroll(struct seat *seat, int amount, enum wl_pointer_axis axis)
2637 {
2638 struct terminal *term = seat->mouse_focus;
2639 xassert(term != NULL);
2640
2641 int button = axis == WL_POINTER_AXIS_VERTICAL_SCROLL
2642 ? amount < 0 ? BTN_BACK : BTN_FORWARD
2643 : amount < 0 ? BTN_WHEEL_LEFT : BTN_WHEEL_RIGHT;
2644 amount = abs(amount);
2645
2646 if (term_mouse_grabbed(term, seat)) {
2647 if (term->grid == &term->alt) {
2648 if (term->alt_scrolling) {
2649 switch (button) {
2650 case BTN_BACK:
2651 case BTN_FORWARD:
2652 alternate_scroll(seat, amount, button);
2653 break;
2654 }
2655 }
2656 } else {
2657 switch (button) {
2658 case BTN_BACK:
2659 cmd_scrollback_up(term, amount);
2660 break;
2661
2662 case BTN_FORWARD:
2663 cmd_scrollback_down(term, amount);
2664 break;
2665 }
2666 }
2667 }
2668
2669 else if (seat->mouse.col >= 0 && seat->mouse.row >= 0) {
2670 xassert(seat->mouse.col < term->cols);
2671 xassert(seat->mouse.row < term->rows);
2672
2673 for (int i = 0; i < amount; i++) {
2674 term_mouse_down(
2675 term, button, seat->mouse.row, seat->mouse.col,
2676 seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
2677 }
2678
2679 term_mouse_up(
2680 term, button, seat->mouse.row, seat->mouse.col,
2681 seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
2682 }
2683 }
2684
2685 static float
mouse_scroll_multiplier(const struct terminal * term)2686 mouse_scroll_multiplier(const struct terminal *term)
2687 {
2688 return term->grid == &term->normal
2689 ? term->conf->scrollback.multiplier
2690 : 1.0;
2691 }
2692
2693 static void
wl_pointer_axis(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis,wl_fixed_t value)2694 wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
2695 uint32_t time, uint32_t axis, wl_fixed_t value)
2696 {
2697 struct seat *seat = data;
2698
2699 if (seat->mouse.have_discrete)
2700 return;
2701
2702 xassert(seat->mouse_focus != NULL);
2703 xassert(axis < ALEN(seat->mouse.aggregated));
2704
2705 /*
2706 * Aggregate scrolled amount until we get at least 1.0
2707 *
2708 * Without this, very slow scrolling will never actually scroll
2709 * anything.
2710 */
2711 seat->mouse.aggregated[axis] +=
2712 mouse_scroll_multiplier(seat->mouse_focus) * wl_fixed_to_double(value);
2713 if (fabs(seat->mouse.aggregated[axis]) < seat->mouse_focus->cell_height)
2714 return;
2715
2716 int lines = seat->mouse.aggregated[axis] / seat->mouse_focus->cell_height;
2717 mouse_scroll(seat, lines, axis);
2718 seat->mouse.aggregated[axis] -= (double)lines * seat->mouse_focus->cell_height;
2719 }
2720
2721 static void
wl_pointer_axis_discrete(void * data,struct wl_pointer * wl_pointer,uint32_t axis,int32_t discrete)2722 wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
2723 uint32_t axis, int32_t discrete)
2724 {
2725 struct seat *seat = data;
2726 seat->mouse.have_discrete = true;
2727
2728 int amount = discrete;
2729
2730 if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
2731 /* Treat mouse wheel left/right as regular buttons */
2732 } else
2733 amount *= mouse_scroll_multiplier(seat->mouse_focus);
2734
2735 mouse_scroll(seat, amount, axis);
2736 }
2737
2738 static void
wl_pointer_frame(void * data,struct wl_pointer * wl_pointer)2739 wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
2740 {
2741 struct seat *seat = data;
2742 seat->mouse.have_discrete = false;
2743 }
2744
2745 static void
wl_pointer_axis_source(void * data,struct wl_pointer * wl_pointer,uint32_t axis_source)2746 wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
2747 uint32_t axis_source)
2748 {
2749 }
2750
2751 static void
wl_pointer_axis_stop(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis)2752 wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
2753 uint32_t time, uint32_t axis)
2754 {
2755 struct seat *seat = data;
2756
2757 xassert(axis < ALEN(seat->mouse.aggregated));
2758 seat->mouse.aggregated[axis] = 0.;
2759 }
2760
2761 const struct wl_pointer_listener pointer_listener = {
2762 .enter = wl_pointer_enter,
2763 .leave = wl_pointer_leave,
2764 .motion = wl_pointer_motion,
2765 .button = wl_pointer_button,
2766 .axis = wl_pointer_axis,
2767 .frame = wl_pointer_frame,
2768 .axis_source = wl_pointer_axis_source,
2769 .axis_stop = wl_pointer_axis_stop,
2770 .axis_discrete = wl_pointer_axis_discrete,
2771 };
2772