blob: a432204a1ef567dfe06fb147cafb8bd17241f3a2 [file] [log] [blame]
Kristian Høgsberg43db4012011-01-14 14:45:42 -05001/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <linux/input.h>
27#include <unistd.h>
28#include <fcntl.h>
29
30#include "compositor.h"
31
32struct evdev_input {
33 struct wlsc_input_device base;
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -040034 struct wl_list devices_list;
35 struct udev_monitor *udev_monitor;
36 char *seat_id;
Kristian Høgsberg43db4012011-01-14 14:45:42 -050037};
38
39struct evdev_input_device {
40 struct evdev_input *master;
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -040041 struct wl_list link;
Kristian Høgsberg43db4012011-01-14 14:45:42 -050042 struct wl_event_source *source;
Kristian Høgsberge7b5b412011-09-01 13:25:50 -040043 struct wlsc_output *output;
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -040044 char *devnode;
Tiago Vignattid9f7d1f2011-10-28 13:09:42 -040045 int tool;
Kristian Høgsberg43db4012011-01-14 14:45:42 -050046 int fd;
Kristian Høgsberg96c8be92011-01-14 14:49:46 -050047 int min_x, max_x, min_y, max_y;
Matt Peterson63900ec2011-08-01 13:46:29 -060048 int is_touchpad, old_x_value, old_y_value, reset_x_value, reset_y_value;
Kristian Høgsberg43db4012011-01-14 14:45:42 -050049};
50
Tiago Vignatti8be003b2011-09-01 19:00:03 +030051static inline void
52evdev_process_key(struct evdev_input_device *device,
53 struct input_event *e, int value, int time)
54{
55 switch (e->code) {
Tiago Vignatti8be003b2011-09-01 19:00:03 +030056 case BTN_TOOL_PEN:
57 case BTN_TOOL_RUBBER:
58 case BTN_TOOL_BRUSH:
59 case BTN_TOOL_PENCIL:
60 case BTN_TOOL_AIRBRUSH:
61 case BTN_TOOL_FINGER:
62 case BTN_TOOL_MOUSE:
63 case BTN_TOOL_LENS:
64 device->tool = value ? e->code : 0;
65 if (device->is_touchpad)
66 {
67 device->reset_x_value = 1;
68 device->reset_y_value = 1;
69 }
70 break;
71
Tiago Vignattid9043592011-09-01 19:00:05 +030072 case BTN_TOUCH:
73 /* Treat BTN_TOUCH from devices that only have BTN_TOUCH as
74 * BTN_LEFT */
75 e->code = BTN_LEFT;
76 /* Intentional fallthrough! */
Tiago Vignatti8be003b2011-09-01 19:00:03 +030077 case BTN_LEFT:
78 case BTN_RIGHT:
79 case BTN_MIDDLE:
80 case BTN_SIDE:
81 case BTN_EXTRA:
82 case BTN_FORWARD:
83 case BTN_BACK:
84 case BTN_TASK:
85 notify_button(&device->master->base.input_device,
86 time, e->code, value);
87 break;
88
89 default:
90 notify_key(&device->master->base.input_device,
91 time, e->code, value);
92 break;
93 }
94}
95
96static inline void
97evdev_process_absolute_motion(struct evdev_input_device *device,
98 struct input_event *e, int value, int *x, int *y,
Kristian Høgsberge7b5b412011-09-01 13:25:50 -040099 int *absolute_event)
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300100{
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400101 const int screen_width = device->output->current->width;
102 const int screen_height = device->output->current->height;
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300103
104 switch (e->code) {
105 case ABS_X:
106 *absolute_event = device->tool;
107 *x = (value - device->min_x) * screen_width /
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400108 (device->max_x - device->min_x) + device->output->x;
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300109 break;
110 case ABS_Y:
111 *absolute_event = device->tool;
112 *y = (value - device->min_y) * screen_height /
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400113 (device->max_y - device->min_y) + device->output->y;
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300114 break;
115 }
116}
117
118static inline void
119evdev_process_absolute_motion_touchpad(struct evdev_input_device *device,
120 struct input_event *e, int value, int *dx, int *dy)
121{
122 /* FIXME: Make this configurable somehow. */
123 const int touchpad_speed = 700;
124
125 switch (e->code) {
126 case ABS_X:
127 value -= device->min_x;
128 if (device->reset_x_value)
129 device->reset_x_value = 0;
130 else {
131 *dx = (value - device->old_x_value) * touchpad_speed /
132 (device->max_x - device->min_x);
133 }
134 device->old_x_value = value;
135 break;
136 case ABS_Y:
137 value -= device->min_y;
138 if (device->reset_y_value)
139 device->reset_y_value = 0;
140 else {
141 *dy = (value - device->old_y_value) * touchpad_speed /
142 /* maybe use x size here to have the same scale? */
143 (device->max_y - device->min_y);
144 }
145 device->old_y_value = value;
146 break;
147 }
148}
149
150static inline void
151evdev_process_relative_motion(struct input_event *e, int value, int *dx,
152 int *dy)
153{
154 switch (e->code) {
155 case REL_X:
156 *dx += value;
157 break;
158 case REL_Y:
159 *dy += value;
160 break;
161 }
162}
163
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400164static int
165evdev_input_device_data(int fd, uint32_t mask, void *data)
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500166{
167 struct wlsc_compositor *ec;
168 struct evdev_input_device *device = data;
169 struct input_event ev[8], *e, *end;
170 int len, value, dx, dy, absolute_event;
171 int x, y;
172 uint32_t time;
173
174 ec = (struct wlsc_compositor *)
175 device->master->base.input_device.compositor;
176 if (!ec->focus)
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400177 return 1;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500178
179 dx = 0;
180 dy = 0;
181 absolute_event = 0;
182 x = device->master->base.input_device.x;
183 y = device->master->base.input_device.y;
184
185 len = read(fd, &ev, sizeof ev);
186 if (len < 0 || len % sizeof e[0] != 0) {
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -0400187 /* FIXME: call device_removed when errno is ENODEV. */;
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400188 return 1;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500189 }
190
191 e = ev;
192 end = (void *) ev + len;
193 for (e = ev; e < end; e++) {
194 /* Get the signed value, earlier kernels had this as unsigned */
195 value = e->value;
196 time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
197
198 switch (e->type) {
199 case EV_REL:
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300200 evdev_process_relative_motion(e, value, &dx, &dy);
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500201 break;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500202 case EV_ABS:
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300203 if (device->is_touchpad)
204 evdev_process_absolute_motion_touchpad(device,
205 e, value, &dx, &dy);
206 else
207 evdev_process_absolute_motion(device, e, value,
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400208 &x, &y, &absolute_event);
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500209 break;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500210 case EV_KEY:
211 if (value == 2)
212 break;
Tiago Vignatti8be003b2011-09-01 19:00:03 +0300213 evdev_process_key(device, e, value, time);
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500214 }
215 }
216
217 if (dx != 0 || dy != 0)
218 notify_motion(&device->master->base.input_device,
219 time, x + dx, y + dy);
Kristian Høgsberg96c8be92011-01-14 14:49:46 -0500220 if (absolute_event)
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500221 notify_motion(&device->master->base.input_device, time, x, y);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400222
223 return 1;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500224}
225
Matt Peterson63900ec2011-08-01 13:46:29 -0600226
227/* copied from udev/extras/input_id/input_id.c */
228/* we must use this kernel-compatible implementation */
229#define BITS_PER_LONG (sizeof(unsigned long) * 8)
230#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
231#define OFF(x) ((x)%BITS_PER_LONG)
232#define BIT(x) (1UL<<OFF(x))
233#define LONG(x) ((x)/BITS_PER_LONG)
234#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
235/* end copied */
Kristian Høgsberg96c8be92011-01-14 14:49:46 -0500236
Tiago Vignattic0827fd2011-08-19 17:07:40 +0300237static int
Tiago Vignattid9c82502011-08-19 15:06:20 +0300238evdev_configure_device(struct evdev_input_device *device)
239{
240 struct input_absinfo absinfo;
241 unsigned long ev_bits[NBITS(EV_MAX)];
242 unsigned long abs_bits[NBITS(ABS_MAX)];
243 unsigned long key_bits[NBITS(KEY_MAX)];
Tiago Vignattic0827fd2011-08-19 17:07:40 +0300244 int has_key, has_abs;
245
246 has_key = 0;
247 has_abs = 0;
Tiago Vignattid9c82502011-08-19 15:06:20 +0300248
249 ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
250 if (TEST_BIT(ev_bits, EV_ABS)) {
Tiago Vignattic0827fd2011-08-19 17:07:40 +0300251 has_abs = 1;
Tiago Vignattid9c82502011-08-19 15:06:20 +0300252 ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),
253 abs_bits);
254 if (TEST_BIT(abs_bits, ABS_X)) {
255 ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo);
256 device->min_x = absinfo.minimum;
257 device->max_x = absinfo.maximum;
258 }
259 if (TEST_BIT(abs_bits, ABS_Y)) {
260 ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo);
261 device->min_y = absinfo.minimum;
262 device->max_y = absinfo.maximum;
263 }
264 }
265 if (TEST_BIT(ev_bits, EV_KEY)) {
Tiago Vignattic0827fd2011-08-19 17:07:40 +0300266 has_key = 1;
Tiago Vignattid9c82502011-08-19 15:06:20 +0300267 ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),
268 key_bits);
269 if (TEST_BIT(key_bits, BTN_TOOL_FINGER) &&
270 !TEST_BIT(key_bits, BTN_TOOL_PEN))
271 device->is_touchpad = 1;
272 }
Tiago Vignattic0827fd2011-08-19 17:07:40 +0300273
274 /* This rule tries to catch accelerometer devices and opt out. We may
275 * want to adjust the protocol later adding a proper event for dealing
276 * with accelerometers and implement here accordingly */
277 if (has_abs && !has_key)
278 return -1;
279
280 return 0;
Tiago Vignattid9c82502011-08-19 15:06:20 +0300281}
282
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500283static struct evdev_input_device *
284evdev_input_device_create(struct evdev_input *master,
285 struct wl_display *display, const char *path)
286{
287 struct evdev_input_device *device;
288 struct wl_event_loop *loop;
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400289 struct wlsc_compositor *ec;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500290
291 device = malloc(sizeof *device);
292 if (device == NULL)
293 return NULL;
294
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400295 ec = (struct wlsc_compositor *) master->base.input_device.compositor;
Tiago Vignattiac9cfd32011-10-28 13:15:25 -0400296 device->output =
Kristian Høgsberge7b5b412011-09-01 13:25:50 -0400297 container_of(ec->output_list.next, struct wlsc_output, link);
298
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500299 device->tool = 1;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500300 device->master = master;
Matt Peterson63900ec2011-08-01 13:46:29 -0600301 device->is_touchpad = 0;
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -0400302 device->devnode = strdup(path);
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500303
304 device->fd = open(path, O_RDONLY);
Tiago Vignattiac9cfd32011-10-28 13:15:25 -0400305 if (device->fd < 0)
306 goto err0;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500307
Tiago Vignattiac9cfd32011-10-28 13:15:25 -0400308 if (evdev_configure_device(device) == -1)
309 goto err1;
Kristian Høgsberg96c8be92011-01-14 14:49:46 -0500310
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500311 loop = wl_display_get_event_loop(display);
312 device->source = wl_event_loop_add_fd(loop, device->fd,
313 WL_EVENT_READABLE,
314 evdev_input_device_data, device);
Tiago Vignattiac9cfd32011-10-28 13:15:25 -0400315 if (device->source == NULL)
316 goto err1;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500317
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -0400318 wl_list_insert(master->devices_list.prev, &device->link);
Tiago Vignattiac9cfd32011-10-28 13:15:25 -0400319
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500320 return device;
Tiago Vignattiac9cfd32011-10-28 13:15:25 -0400321
322err1:
323 close(device->fd);
324err0:
325 free(device->devnode);
326 free(device);
327 return NULL;
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500328}
329
Kristian Høgsberg86ec8e82011-07-19 16:10:11 -0700330static const char default_seat[] = "seat0";
331
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -0400332static void
333device_added(struct udev_device *udev_device, struct evdev_input *master)
334{
335 struct wlsc_compositor *c;
336 const char *devnode;
337 const char *device_seat;
338
339 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
340 if (!device_seat)
341 device_seat = default_seat;
342
343 if (strcmp(device_seat, master->seat_id))
344 return;
345
346 c = (struct wlsc_compositor *) master->base.input_device.compositor;
347 devnode = udev_device_get_devnode(udev_device);
348 if (evdev_input_device_create(master, c->wl_display, devnode))
349 fprintf(stderr, "evdev input device: added: %s\n", devnode);
350}
351
352static void
353device_removed(struct udev_device *udev_device, struct evdev_input *master)
354{
355 const char *devnode = udev_device_get_devnode(udev_device);
356 struct evdev_input_device *device, *next;
357
358 wl_list_for_each_safe(device, next, &master->devices_list, link) {
359 if (!strcmp(device->devnode, devnode)) {
360 wl_event_source_remove(device->source);
361 wl_list_remove(&device->link);
362 close(device->fd);
363 free(device->devnode);
364 free(device);
365 break;
366 }
367 }
368 fprintf(stderr, "evdev input device: removed: %s\n", devnode);
369}
370
371static int
372evdev_udev_handler(int fd, uint32_t mask, void *data)
373{
374 struct evdev_input *master = data;
375 struct udev_device *udev_device;
376 const char *action;
377
378 udev_device = udev_monitor_receive_device(master->udev_monitor);
379 if (!udev_device)
380 return 1;
381
382 action = udev_device_get_action(udev_device);
383 if (action) {
384 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
385 return 0;
386
387 if (!strcmp(action, "add")) {
388 device_added(udev_device, master);
389 }
390 else if (!strcmp(action, "remove"))
391 device_removed(udev_device, master);
392 }
393 udev_device_unref(udev_device);
394
395 return 0;
396}
397
398static int
399evdev_config_udev_monitor(struct udev *udev, struct evdev_input *master)
400{
401 struct wl_event_loop *loop;
402 struct wlsc_compositor *c =
403 (struct wlsc_compositor *) master->base.input_device.compositor;
404
405 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
406 if (!master->udev_monitor)
407 return 0;
408
409 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
410 "input", NULL);
411
412 if (udev_monitor_enable_receiving(master->udev_monitor)) {
413 fprintf(stderr, "udev: failed to bind the udev monitor\n");
414 return 0;
415 }
416
417 loop = wl_display_get_event_loop(c->wl_display);
418 wl_event_loop_add_fd(loop, udev_monitor_get_fd(master->udev_monitor),
419 WL_EVENT_READABLE, evdev_udev_handler, master);
420
421 return 1;
422}
423
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500424void
Kristian Høgsberg86ec8e82011-07-19 16:10:11 -0700425evdev_input_add_devices(struct wlsc_compositor *c,
426 struct udev *udev, const char *seat)
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500427{
428 struct evdev_input *input;
429 struct udev_enumerate *e;
430 struct udev_list_entry *entry;
431 struct udev_device *device;
432 const char *path;
433
434 input = malloc(sizeof *input);
435 if (input == NULL)
436 return;
437
438 memset(input, 0, sizeof *input);
439 wlsc_input_device_init(&input->base, c);
440
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -0400441 wl_list_init(&input->devices_list);
442 input->seat_id = strdup(seat);
443 if (!evdev_config_udev_monitor(udev, input)) {
444 free(input->seat_id);
445 free(input);
446 return;
447 }
448
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500449 e = udev_enumerate_new(udev);
450 udev_enumerate_add_match_subsystem(e, "input");
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500451 udev_enumerate_scan_devices(e);
452 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
453 path = udev_list_entry_get_name(entry);
454 device = udev_device_new_from_syspath(udev, path);
Kristian Høgsberg86ec8e82011-07-19 16:10:11 -0700455
Kristian Høgsberg1d266032011-07-21 06:46:26 -0700456 if (strncmp("event", udev_device_get_sysname(device), 5) != 0)
457 continue;
458
Tiago Vignattiac2dc6a2011-10-28 13:05:06 -0400459 device_added(device, input);
Kristian Høgsberg86ec8e82011-07-19 16:10:11 -0700460
461 udev_device_unref(device);
Kristian Høgsberg43db4012011-01-14 14:45:42 -0500462 }
463 udev_enumerate_unref(e);
464
465 c->input_device = &input->base.input_device;
466}