1#include "compositor.h"
2#include "data_device.h"
3#include "event.h"
4#include "internal.h"
5#include "keyboard.h"
6#include "launch.h"
7#include "pointer.h"
8#include "screen.h"
9#include "seat.h"
10#include "surface.h"
11#include "util.h"
12
13#include <ctype.h>
14#include <dirent.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <limits.h>
18#include <stdbool.h>
19#include <stdint.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/ioctl.h>
24#include <unistd.h>
25
26#include <linux/input.h>
27
28struct seat {
29 struct swc_seat base;
30
31 char *name;
32 uint32_t capabilities;
33
34 int mouse_fd;
35 int kbd_fd;
36 bool ignore;
37
38 struct xkb_rule_names names;
39
40 struct wl_event_source *mouse_source;
41 struct wl_event_source *kbd_source;
42
43 struct wl_listener swc_listener;
44
45 struct wl_listener keyboard_focus_listener;
46 struct pointer pointer;
47 struct wl_listener data_device_listener;
48
49 struct wl_global *global;
50 struct wl_list resources;
51
52 wl_fixed_t abs_x;
53 wl_fixed_t abs_y;
54 bool abs_initialized;
55
56 bool shared_fd;
57};
58
59static void
60handle_keyboard_focus_event(struct wl_listener *listener, void *data)
61{
62 struct seat *seat =
63 wl_container_of(listener, seat, keyboard_focus_listener);
64 struct event *ev = data;
65 struct input_focus_event_data *event_data = ev->data;
66
67 if (ev->type != INPUT_FOCUS_EVENT_CHANGED) {
68 return;
69 }
70
71 if (event_data->new) {
72 struct wl_client *client =
73 wl_resource_get_client(event_data->new->surface->resource);
74
75 /* offer the selection to the new focus */
76 data_device_offer_selection(seat->base.data_device, client);
77 }
78}
79
80static void
81handle_data_device_event(struct wl_listener *listener, void *data)
82{
83 struct seat *seat = wl_container_of(listener, seat, data_device_listener);
84 struct event *ev = data;
85
86 if (ev->type != DATA_DEVICE_EVENT_SELECTION_CHANGED) {
87 return;
88 }
89
90 if (seat->base.keyboard->focus.client) {
91 data_device_offer_selection(seat->base.data_device,
92 seat->base.keyboard->focus.client);
93 }
94}
95
96static void
97handle_swc_event(struct wl_listener *listener, void *data)
98{
99 struct seat *seat = wl_container_of(listener, seat, swc_listener);
100 struct event *ev = data;
101
102 switch (ev->type) {
103 case SWC_EVENT_DEACTIVATED:
104 seat->ignore = true;
105 keyboard_reset(seat->base.keyboard);
106 break;
107 case SWC_EVENT_ACTIVATED:
108 seat->ignore = false;
109 break;
110 }
111}
112
113/* da seat */
114static void
115get_pointer(struct wl_client *client, struct wl_resource *resource, uint32_t id)
116{
117 struct seat *seat = wl_resource_get_user_data(resource);
118
119 pointer_bind(&seat->pointer, client, wl_resource_get_version(resource), id);
120}
121
122static void
123get_keyboard(struct wl_client *client, struct wl_resource *resource,
124 uint32_t id)
125{
126 struct seat *seat = wl_resource_get_user_data(resource);
127
128 keyboard_bind(seat->base.keyboard, client,
129 wl_resource_get_version(resource), id);
130}
131
132static void
133get_touch(struct wl_client *client, struct wl_resource *resource, uint32_t id)
134{
135}
136
137static struct wl_seat_interface seat_impl = {
138 .get_pointer = get_pointer,
139 .get_keyboard = get_keyboard,
140 .get_touch = get_touch,
141};
142
143static void
144bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
145{
146 struct seat *seat = data;
147 struct wl_resource *resource;
148
149 if (version > 4) {
150 version = 4;
151 }
152
153 resource = wl_resource_create(client, &wl_seat_interface, version, id);
154 wl_resource_set_implementation(resource, &seat_impl, seat,
155 &remove_resource);
156 wl_list_insert(&seat->resources, wl_resource_get_link(resource));
157
158 if (version >= 2) {
159 wl_seat_send_name(resource, seat->name);
160 }
161
162 wl_seat_send_capabilities(resource, seat->capabilities);
163}
164
165static uint32_t
166event_time_ms(const struct input_event *ev)
167{
168 return (uint32_t)(ev->time.tv_sec * 1000 + ev->time.tv_usec / 1000);
169}
170
171static void
172handle_evdev_key(struct seat *seat, const struct input_event *ev)
173{
174 uint32_t state;
175 uint32_t time = event_time_ms(ev);
176
177 if (ev->value == 2) {
178 return;
179 }
180
181 if (ev->code >= BTN_MISC) {
182 pointer_handle_button(seat->base.pointer, time, ev->code,
183 ev->value ? WL_POINTER_BUTTON_STATE_PRESSED
184 : WL_POINTER_BUTTON_STATE_RELEASED);
185 } else {
186 if (ev->code > 255) {
187 return;
188 }
189 state = (ev->value ? WL_KEYBOARD_KEY_STATE_PRESSED
190 : WL_KEYBOARD_KEY_STATE_RELEASED);
191 keyboard_handle_key(seat->base.keyboard, time, ev->code, state);
192 }
193}
194
195static void
196handle_evdev_rel(struct seat *seat, const struct input_event *ev)
197{
198 uint32_t time = event_time_ms(ev);
199 wl_fixed_t value;
200
201 switch (ev->code) {
202 case REL_X:
203 pointer_handle_relative_motion(seat->base.pointer, time,
204 wl_fixed_from_int(ev->value), 0);
205 break;
206 case REL_Y:
207 pointer_handle_relative_motion(seat->base.pointer, time, 0,
208 wl_fixed_from_int(ev->value));
209 break;
210 case REL_WHEEL:
211 value = wl_fixed_from_int(ev->value * 10);
212 pointer_handle_axis(
213 seat->base.pointer, time, WL_POINTER_AXIS_VERTICAL_SCROLL,
214 WL_POINTER_AXIS_SOURCE_WHEEL, value, ev->value * 120);
215 break;
216 case REL_HWHEEL:
217 value = wl_fixed_from_int(ev->value * 10);
218 pointer_handle_axis(
219 seat->base.pointer, time, WL_POINTER_AXIS_HORIZONTAL_SCROLL,
220 WL_POINTER_AXIS_SOURCE_WHEEL, value, ev->value * 120);
221 break;
222 default:
223 break;
224 }
225}
226
227static void
228handle_evdev_abs(struct seat *seat, const struct input_event *ev)
229{
230 uint32_t time = event_time_ms(ev);
231
232 switch (ev->code) {
233 case ABS_X:
234 seat->abs_x = wl_fixed_from_int(ev->value);
235 seat->abs_initialized = true;
236 break;
237 case ABS_Y:
238 seat->abs_y = wl_fixed_from_int(ev->value);
239 seat->abs_initialized = true;
240 break;
241 default:
242 return;
243 }
244
245 if (seat->abs_initialized) {
246 pointer_handle_absolute_motion(seat->base.pointer, time, seat->abs_x,
247 seat->abs_y);
248 }
249}
250
251static int
252handle_evdev_data(int fd, uint32_t mask, void *data)
253{
254 struct seat *seat = data;
255 struct input_event ev;
256 ssize_t n;
257
258 while (!seat->ignore) {
259 n = read(fd, &ev, sizeof(ev));
260 if (n == -1) {
261 if (errno == EAGAIN || errno == EINTR) {
262 break;
263 }
264 return 0;
265 }
266 if (n != (ssize_t)sizeof(ev)) {
267 break;
268 }
269
270 switch (ev.type) {
271 case EV_KEY:
272 handle_evdev_key(seat, &ev);
273 break;
274 case EV_REL:
275 handle_evdev_rel(seat, &ev);
276 break;
277 case EV_ABS:
278 handle_evdev_abs(seat, &ev);
279 break;
280 case EV_SYN:
281 if (ev.code == SYN_REPORT) {
282 pointer_handle_frame(seat->base.pointer);
283 }
284 break;
285 default:
286 break;
287 }
288 }
289
290 return 0;
291}
292
293static bool
294test_bit(const unsigned long *bits, size_t bit)
295{
296 return (bits[bit / (sizeof(unsigned long) * 8)] >>
297 (bit % (sizeof(unsigned long) * 8))) &
298 1;
299}
300
301static bool
302contains_ci(const char *haystack, const char *needle)
303{
304 size_t nlen;
305 const char *h;
306
307 if (!haystack || !needle || !*needle) {
308 return false;
309 }
310
311 nlen = strlen(needle);
312 for (h = haystack; *h; ++h) {
313 size_t i;
314 for (i = 0; i < nlen; ++i) {
315 unsigned char hc = (unsigned char)h[i];
316 unsigned char nc = (unsigned char)needle[i];
317 if (!h[i] || tolower(hc) != tolower(nc)) {
318 break;
319 }
320 }
321 if (i == nlen) {
322 return true;
323 }
324 }
325 return false;
326}
327
328static bool
329is_keyboard_device(int fd)
330{
331 unsigned long ev_bits[(EV_MAX + 8 * sizeof(unsigned long) - 1) /
332 (8 * sizeof(unsigned long))];
333 unsigned long key_bits[(KEY_MAX + 8 * sizeof(unsigned long) - 1) /
334 (8 * sizeof(unsigned long))];
335
336 memset(ev_bits, 0, sizeof(ev_bits));
337 memset(key_bits, 0, sizeof(key_bits));
338
339 if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
340 return false;
341 }
342 if (!test_bit(ev_bits, EV_KEY)) {
343 return false;
344 }
345 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) {
346 return false;
347 }
348
349 return test_bit(key_bits, KEY_A) && test_bit(key_bits, KEY_Z) &&
350 test_bit(key_bits, KEY_ENTER) && test_bit(key_bits, KEY_ESC) &&
351 test_bit(key_bits, KEY_SPACE);
352}
353
354static bool
355is_pointer_device(int fd)
356{
357 unsigned long ev_bits[(EV_MAX + 8 * sizeof(unsigned long) - 1) /
358 (8 * sizeof(unsigned long))];
359 unsigned long rel_bits[(REL_MAX + 8 * sizeof(unsigned long) - 1) /
360 (8 * sizeof(unsigned long))];
361 unsigned long key_bits[(KEY_MAX + 8 * sizeof(unsigned long) - 1) /
362 (8 * sizeof(unsigned long))];
363
364 memset(ev_bits, 0, sizeof(ev_bits));
365 memset(rel_bits, 0, sizeof(rel_bits));
366 memset(key_bits, 0, sizeof(key_bits));
367
368 if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
369 return false;
370 }
371
372 if (test_bit(ev_bits, EV_REL)) {
373 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) < 0) {
374 return false;
375 }
376 if (test_bit(rel_bits, REL_X) && test_bit(rel_bits, REL_Y)) {
377 return true;
378 }
379 }
380
381 if (test_bit(ev_bits, EV_KEY)) {
382 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) {
383 return false;
384 }
385 if (test_bit(key_bits, BTN_LEFT) && test_bit(key_bits, BTN_RIGHT)) {
386 return true;
387 }
388 }
389
390 return false;
391}
392
393static bool
394get_ev_bits(int fd, unsigned long *ev_bits, size_t ev_bits_len)
395{
396 memset(ev_bits, 0, ev_bits_len);
397 return ioctl(fd, EVIOCGBIT(0, ev_bits_len), ev_bits) >= 0;
398}
399
400static int
401score_candidate(int fd, bool want_keyboard, const char *id_name)
402{
403 char name[256];
404 unsigned long ev_bits[(EV_MAX + 8 * sizeof(unsigned long) - 1) /
405 (8 * sizeof(unsigned long))];
406 bool is_kbd;
407 bool is_ptr;
408 int score = 10;
409
410 is_kbd = is_keyboard_device(fd);
411 is_ptr = is_pointer_device(fd);
412
413 if (want_keyboard && !is_kbd) {
414 return -1;
415 }
416 if (!want_keyboard && !is_ptr) {
417 return -1;
418 }
419
420 if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
421 name[0] = '\0';
422 }
423
424 if (!get_ev_bits(fd, ev_bits, sizeof(ev_bits))) {
425 memset(ev_bits, 0, sizeof(ev_bits));
426 }
427
428 if (want_keyboard) {
429 if (is_ptr) {
430 score -= 6;
431 }
432 if (contains_ci(id_name, "mouse") || contains_ci(name, "mouse")) {
433 score -= 12;
434 }
435 if (contains_ci(id_name, "kbd") || contains_ci(id_name, "keyboard")) {
436 score += 4;
437 }
438 if (contains_ci(name, "keyboard")) {
439 score += 2;
440 }
441 if (test_bit(ev_bits, EV_LED)) {
442 score += 3;
443 }
444 if (test_bit(ev_bits, EV_REP)) {
445 score += 1;
446 }
447 } else {
448 if (contains_ci(id_name, "mouse") || contains_ci(name, "mouse")) {
449 score += 4;
450 }
451 if (contains_ci(id_name, "kbd") || contains_ci(id_name, "keyboard")) {
452 score -= 6;
453 }
454 if (contains_ci(name, "keyboard")) {
455 score -= 4;
456 }
457 }
458
459 return score;
460}
461
462static bool
463pick_best_device(const char *dir_path, const char *name_prefix,
464 const char *name_substr, bool want_keyboard, char *out,
465 size_t out_len)
466{
467 DIR *dir;
468 struct dirent *ent;
469 bool found = false;
470 int best_score = -1;
471 size_t prefix_len = name_prefix ? strlen(name_prefix) : 0;
472
473 dir = opendir(dir_path);
474 if (!dir) {
475 return false;
476 }
477
478 while ((ent = readdir(dir)) != NULL) {
479 char path[PATH_MAX];
480 int fd;
481 int score;
482
483 if (ent->d_name[0] == '.') {
484 continue;
485 }
486 if (name_prefix && strncmp(ent->d_name, name_prefix, prefix_len) != 0) {
487 continue;
488 }
489 if (name_substr && !strstr(ent->d_name, name_substr)) {
490 continue;
491 }
492
493 snprintf(path, sizeof(path), "%s/%s", dir_path, ent->d_name);
494 fd = launch_open_device(path, O_RDONLY | O_NONBLOCK);
495 if (fd == -1) {
496 continue;
497 }
498
499 score = score_candidate(fd, want_keyboard, ent->d_name);
500 if (score < 0) {
501 close(fd);
502 continue;
503 }
504
505 if (score > best_score) {
506 snprintf(out, out_len, "%s", path);
507 best_score = score;
508 found = true;
509 }
510
511 close(fd);
512 }
513
514 closedir(dir);
515 return found;
516}
517
518static bool
519initialize_evdev(struct seat *seat)
520{
521 char kbd_path[PATH_MAX];
522 char mouse_path[PATH_MAX];
523 const char *kbd_dev = EVDEV_KBD_DEVICE;
524 const char *mouse_dev = EVDEV_POINTER_DEVICE;
525
526 if (pick_best_device("/dev/input/by-id", NULL, "event-kbd", true, kbd_path,
527 sizeof(kbd_path))) {
528 kbd_dev = kbd_path;
529 } else if (pick_best_device("/dev/input/by-path", NULL, "event-kbd", true,
530 kbd_path, sizeof(kbd_path))) {
531 kbd_dev = kbd_path;
532 } else if (pick_best_device("/dev/input", "event", NULL, true, kbd_path,
533 sizeof(kbd_path))) {
534 kbd_dev = kbd_path;
535 }
536
537 if (pick_best_device("/dev/input/by-id", NULL, "event-mouse", false,
538 mouse_path, sizeof(mouse_path))) {
539 mouse_dev = mouse_path;
540 } else if (pick_best_device("/dev/input/by-path", NULL, "event-mouse",
541 false, mouse_path, sizeof(mouse_path))) {
542 mouse_dev = mouse_path;
543 } else if (pick_best_device("/dev/input", "event", NULL, false, mouse_path,
544 sizeof(mouse_path))) {
545 mouse_dev = mouse_path;
546 }
547
548 DEBUG("evdev devices: keyboard=%s pointer=%s\n", kbd_dev, mouse_dev);
549
550 seat->kbd_fd = launch_open_device(kbd_dev, O_RDONLY | O_NONBLOCK);
551 if (seat->kbd_fd == -1) {
552 ERROR("Could not open evdev keyboard device %s\n", kbd_dev);
553 goto error0;
554 }
555
556 if (strcmp(kbd_dev, mouse_dev) == 0) {
557 seat->mouse_fd = seat->kbd_fd;
558 seat->shared_fd = true;
559 return true;
560 }
561
562 seat->mouse_fd = launch_open_device(mouse_dev, O_RDONLY | O_NONBLOCK);
563 if (seat->mouse_fd == -1) {
564 ERROR("Could not open evdev pointer device %s\n", mouse_dev);
565 goto error1;
566 }
567
568 return true;
569
570error1:
571 close(seat->kbd_fd);
572error0:
573 return false;
574}
575
576struct swc_seat *
577seat_create(struct wl_display *display, const char *seat_name)
578{
579 struct seat *seat;
580
581 seat = malloc(sizeof(*seat));
582 if (!seat) {
583 goto error0;
584 }
585
586 memset(&seat->names, 0, sizeof(seat->names));
587 seat->names.rules = "base";
588 seat->names.model = "pc105";
589 seat->names.layout = "us";
590 seat->names.variant = "basic";
591 seat->shared_fd = false;
592
593 seat->name = strdup(seat_name);
594 if (!seat->name) {
595 ERROR("Could not allocate seat name string\n");
596 goto error1;
597 }
598
599 if (!initialize_evdev(seat)) {
600 goto error2;
601 }
602
603 seat->global =
604 wl_global_create(display, &wl_seat_interface, 4, seat, &bind_seat);
605 if (!seat->global) {
606 goto error2;
607 }
608 seat->capabilities =
609 WL_SEAT_CAPABILITY_KEYBOARD | WL_SEAT_CAPABILITY_POINTER;
610 wl_list_init(&seat->resources);
611
612 seat->swc_listener.notify = &handle_swc_event;
613 wl_signal_add(&swc.event_signal, &seat->swc_listener);
614
615 seat->base.data_device = data_device_create();
616 if (!seat->base.data_device) {
617 ERROR("could not initialize data device\n");
618 goto error3;
619 }
620 seat->data_device_listener.notify = &handle_data_device_event;
621 wl_signal_add(&seat->base.data_device->event_signal,
622 &seat->data_device_listener);
623
624 seat->base.keyboard = keyboard_create(&seat->names);
625 if (!seat->base.keyboard) {
626 ERROR("could not initialize keyboard\n");
627 goto error4;
628 }
629 seat->keyboard_focus_listener.notify = handle_keyboard_focus_event;
630 wl_signal_add(&seat->base.keyboard->focus.event_signal,
631 &seat->keyboard_focus_listener);
632
633 if (!pointer_initialize(&seat->pointer)) {
634 ERROR("Could not initialize pointer\n");
635 goto error5;
636 }
637 seat->base.pointer = &seat->pointer;
638
639 seat->kbd_source =
640 wl_event_loop_add_fd(swc.event_loop, seat->kbd_fd, WL_EVENT_READABLE,
641 &handle_evdev_data, seat);
642 if (!seat->shared_fd) {
643 seat->mouse_source =
644 wl_event_loop_add_fd(swc.event_loop, seat->mouse_fd,
645 WL_EVENT_READABLE, &handle_evdev_data, seat);
646 } else {
647 seat->mouse_source = NULL;
648 }
649
650 seat->abs_initialized = false;
651
652 return &seat->base;
653
654error5:
655 keyboard_destroy(seat->base.keyboard);
656error4:
657 data_device_destroy(seat->base.data_device);
658error3:
659 wl_global_destroy(seat->global);
660error2:
661 free(seat->name);
662error1:
663 free(seat);
664error0:
665 return NULL;
666}
667
668void
669seat_destroy(struct swc_seat *seat_base)
670{
671 struct seat *seat = wl_container_of(seat_base, seat, base);
672
673 if (seat->mouse_source) {
674 wl_event_source_remove(seat->mouse_source);
675 }
676 wl_event_source_remove(seat->kbd_source);
677 if (seat->mouse_source) {
678 close(seat->mouse_fd);
679 seat->mouse_fd = -1;
680 }
681 close(seat->kbd_fd);
682 seat->kbd_fd = -1;
683
684 pointer_finalize(&seat->pointer);
685 keyboard_destroy(seat->base.keyboard);
686 data_device_destroy(seat->base.data_device);
687
688 wl_global_destroy(seat->global);
689 free(seat->name);
690 free(seat);
691}