main neuswc / libswc / seat-evdev.c
  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}