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