tools: add a tool for basic event debugging
[platform/upstream/libinput.git] / tools / event-debug.c
1 /*
2  * Copyright © 2014 Red Hat, Inc.
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 #define _GNU_SOURCE
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <getopt.h>
27 #include <poll.h>
28 #include <stdio.h>
29 #include <signal.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <linux/input.h>
34 #include <sys/ioctl.h>
35 #include <sys/signalfd.h>
36
37 #include <libinput.h>
38
39 static enum {
40         MODE_UDEV,
41         MODE_DEVICE,
42 } mode = MODE_UDEV;
43 static const char *device;
44 static const char *seat = "seat0";
45 static struct udev *udev;
46 uint32_t start_time;
47
48 static void
49 usage(void)
50 {
51         printf("Usage: %s [--udev [<seat>]|--device /dev/input/event0]\n"
52                "--udev <seat>.... Use udev device discovery (default).\n"
53                "                  Specifying a seat ID is optional.\n"
54                "--device /path/to/device .... open the given device only\n",
55                 program_invocation_short_name);
56 }
57
58 static int
59 parse_args(int argc, char **argv)
60 {
61         while (1) {
62                 int c;
63                 int option_index = 0;
64                 static struct option opts[] = {
65                         { "device", 1, 0, 'd' },
66                         { "udev", 0, 0, 'u' },
67                         { "help", 0, 0, 'h' },
68                         { 0, 0, 0, 0}
69                 };
70
71                 c = getopt_long(argc, argv, "h", opts, &option_index);
72                 if (c == -1)
73                         break;
74
75                 switch(c) {
76                         case 'h': /* --help */
77                                 usage();
78                                 exit(0);
79                         case 'd': /* --device */
80                                 mode = MODE_DEVICE;
81                                 if (!optarg) {
82                                         usage();
83                                         return 1;
84                                 }
85                                 device = optarg;
86                                 break;
87                         case 'u': /* --udev */
88                                 mode = MODE_UDEV;
89                                 if (optarg)
90                                         seat = optarg;
91                                 break;
92                         default:
93                                 usage();
94                                 return 1;
95                 }
96
97         }
98
99         if (optind < argc) {
100                 usage();
101                 return 1;
102         }
103
104         return 0;
105 }
106
107 static int
108 open_restricted(const char *path, int flags, void *user_data)
109 {
110         int fd = open(path, flags);
111         int clockid = CLOCK_MONOTONIC;
112
113         if (fd >= 0 && ioctl(fd, EVIOCSCLOCKID, &clockid) < 0)
114                 fprintf(stderr, "Changing clock on %s failed, timestamps "
115                                 "will be off\n", path);
116
117         return fd < 0 ? -errno : fd;
118 }
119
120 static void
121 close_restricted(int fd, void *user_data)
122 {
123         close(fd);
124 }
125
126 static void get_current_screen_dimensions(struct libinput_device *device,
127                                           int *width,
128                                           int *height,
129                                           void *user_data)
130 {
131         /* display absdata in % of the screen */
132         *width = 100;
133         *height = 100;
134 }
135
136 const static struct libinput_interface interface = {
137         .open_restricted = open_restricted,
138         .close_restricted = close_restricted,
139         .get_current_screen_dimensions = get_current_screen_dimensions,
140 };
141
142 static int
143 open_udev(struct libinput **li)
144 {
145         udev = udev_new();
146         if (!udev) {
147                 fprintf(stderr, "Failed to initialize udev\n");
148                 return 1;
149         }
150
151         *li = libinput_create_from_udev(&interface, NULL, udev, seat);
152         if (!*li) {
153                 fprintf(stderr, "Failed to initialize context from udev\n");
154                 return 1;
155         }
156
157         return 0;
158 }
159
160 static int
161 open_device(struct libinput **li, const char *path)
162 {
163         *li = libinput_create_from_path(&interface, NULL, path);
164         if (!*li) {
165                 fprintf(stderr, "Failed to initialize context from %s\n", path);
166                 return 1;
167         }
168         return 0;
169 }
170
171 static void
172 print_event_header(struct libinput_event *ev)
173 {
174         struct libinput_device *dev = libinput_event_get_device(ev);
175         const char *type;
176
177         switch(libinput_event_get_type(ev)) {
178         case LIBINPUT_EVENT_NONE:
179                 abort();
180         case LIBINPUT_EVENT_DEVICE_ADDED:
181                 type = "DEVICE_ADDED";
182                 break;
183         case LIBINPUT_EVENT_DEVICE_REMOVED:
184                 type = "DEVICE_REMOVED";
185                 break;
186         case LIBINPUT_EVENT_KEYBOARD_KEY:
187                 type = "KEYBOARD_KEY";
188                 break;
189         case LIBINPUT_EVENT_POINTER_MOTION:
190                 type = "POINTER_MOTION";
191                 break;
192         case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
193                 type = "POINTER_MOTION_ABSOLUTE";
194                 break;
195         case LIBINPUT_EVENT_POINTER_BUTTON:
196                 type = "POINTER_BUTTON";
197                 break;
198         case LIBINPUT_EVENT_POINTER_AXIS:
199                 type = "POINTER_AXIS";
200                 break;
201         case LIBINPUT_EVENT_TOUCH_TOUCH:
202                 type = "TOUCH_TOUCH";
203                 break;
204         case LIBINPUT_EVENT_TOUCH_FRAME:
205                 type = "TOUCH_FRAME";
206                 break;
207         }
208
209         printf("%-7s    %s      ", libinput_device_get_sysname(dev), type);
210 }
211
212 static void
213 print_event_time(uint32_t time)
214 {
215         printf("%+6.2fs ", (time - start_time) / 1000.0);
216 }
217
218 static void
219 print_device_notify(struct libinput_event *ev)
220 {
221         struct libinput_device *dev = libinput_event_get_device(ev);
222         struct libinput_seat *seat = libinput_device_get_seat(dev);
223
224         printf("%s      %s\n",
225                libinput_seat_get_physical_name(seat),
226                libinput_seat_get_logical_name(seat));
227 }
228
229 static void
230 print_key_event(struct libinput_event *ev)
231 {
232         struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
233         enum libinput_keyboard_key_state state;
234
235         print_event_time(libinput_event_keyboard_get_time(k));
236         state = libinput_event_keyboard_get_key_state(k);
237         printf("%d %s\n",
238                libinput_event_keyboard_get_key(k),
239                state == LIBINPUT_KEYBOARD_KEY_STATE_PRESSED ? "pressed" : "released");
240 }
241
242 static void
243 print_motion_event(struct libinput_event *ev)
244 {
245         struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
246         li_fixed_t x =  libinput_event_pointer_get_dx(p),
247                    y = libinput_event_pointer_get_dy(p);
248
249         print_event_time(libinput_event_pointer_get_time(p));
250
251         printf("%6.2f/%6.2f\n",
252                li_fixed_to_double(x),
253                li_fixed_to_double(y));
254 }
255
256 static void
257 print_absmotion_event(struct libinput_event *ev)
258 {
259         struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
260         li_fixed_t x = libinput_event_pointer_get_absolute_x(p),
261                    y = libinput_event_pointer_get_absolute_y(p);
262
263         print_event_time(libinput_event_pointer_get_time(p));
264         printf("%6.2f/%6.2f\n",
265                li_fixed_to_double(x),
266                li_fixed_to_double(y));
267 }
268
269 static void
270 print_button_event(struct libinput_event *ev)
271 {
272         struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
273         enum libinput_pointer_button_state state;
274
275         print_event_time(libinput_event_pointer_get_time(p));
276
277         state = libinput_event_pointer_get_button_state(p);
278         printf("%3d %s\n",
279                libinput_event_pointer_get_button(p),
280                state == LIBINPUT_POINTER_BUTTON_STATE_PRESSED ? "pressed" : "released");
281 }
282
283 static void
284 print_axis_event(struct libinput_event *ev)
285 {
286         struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
287         enum libinput_pointer_axis axis = libinput_event_pointer_get_axis(p);
288         const char *ax;
289         li_fixed_t val;
290
291         switch (axis) {
292         case LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL:
293                 ax = "vscroll";
294                 break;
295         case LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL:
296                 ax = "hscroll";
297                 break;
298         default:
299                 abort();
300         }
301
302         print_event_time(libinput_event_pointer_get_time(p));
303         val = libinput_event_pointer_get_axis_value(p);
304         printf("%s %.2f\n",
305                ax, li_fixed_to_double(val));
306 }
307
308 static void
309 print_touch_frame_event(struct libinput_event *ev)
310 {
311         struct libinput_event_touch *t = libinput_event_get_touch_event(ev);
312
313         print_event_time(libinput_event_touch_get_time(t));
314         printf("\n");
315 }
316
317 static void
318 print_touch_event(struct libinput_event *ev)
319 {
320         struct libinput_event_touch *t = libinput_event_get_touch_event(ev);
321         li_fixed_t x = libinput_event_touch_get_x(t),
322                    y = libinput_event_touch_get_y(t);
323         const char *type;
324
325         switch (libinput_event_touch_get_touch_type(t)) {
326         case LIBINPUT_TOUCH_TYPE_DOWN: type = "down"; break;
327         case LIBINPUT_TOUCH_TYPE_UP: type = "up"; break;
328         case LIBINPUT_TOUCH_TYPE_MOTION: type = "motion"; break;
329         case LIBINPUT_TOUCH_TYPE_CANCEL: type = "cancel"; break;
330         default:
331                 abort();
332         }
333
334         print_event_time(libinput_event_touch_get_time(t));
335
336         printf("%6s %u %5.2f/%5.2f\n",
337                type,
338                libinput_event_touch_get_slot(t),
339                li_fixed_to_double(x),
340                li_fixed_to_double(y));
341 }
342
343 static int
344 handle_and_print_events(struct libinput *li)
345 {
346         int rc = -1;
347         struct libinput_event *ev;
348
349         libinput_dispatch(li);
350         while ((ev = libinput_get_event(li))) {
351                 print_event_header(ev);
352
353                 switch (libinput_event_get_type(ev)) {
354                 case LIBINPUT_EVENT_NONE:
355                         abort();
356                 case LIBINPUT_EVENT_DEVICE_ADDED:
357                 case LIBINPUT_EVENT_DEVICE_REMOVED:
358                         print_device_notify(ev);
359                         break;
360                 case LIBINPUT_EVENT_KEYBOARD_KEY:
361                         print_key_event(ev);
362                         break;
363                 case LIBINPUT_EVENT_POINTER_MOTION:
364                         print_motion_event(ev);
365                         break;
366                 case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
367                         print_absmotion_event(ev);
368                         break;
369                 case LIBINPUT_EVENT_POINTER_BUTTON:
370                         print_button_event(ev);
371                         break;
372                 case LIBINPUT_EVENT_POINTER_AXIS:
373                         print_axis_event(ev);
374                         break;
375                 case LIBINPUT_EVENT_TOUCH_TOUCH:
376                         print_touch_event(ev);
377                         break;
378                 case LIBINPUT_EVENT_TOUCH_FRAME:
379                         print_touch_frame_event(ev);
380                         break;
381                 }
382
383                 libinput_event_destroy(ev);
384                 libinput_dispatch(li);
385                 rc = 0;
386         }
387         return rc;
388 }
389
390 void
391 mainloop(struct libinput *li)
392 {
393         struct pollfd fds[2];
394         sigset_t mask;
395
396         fds[0].fd = libinput_get_fd(li);
397         fds[0].events = POLLIN;
398         fds[0].revents = 0;
399
400         sigemptyset(&mask);
401         sigaddset(&mask, SIGINT);
402
403         fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK);
404         fds[1].events = POLLIN;
405         fds[1].revents = 0;
406
407         if (fds[1].fd == -1 ||
408             sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
409                 fprintf(stderr, "Failed to set up signal handling (%s)\n",
410                                 strerror(errno));
411         }
412
413         /* Handle already-pending device added events */
414         if (handle_and_print_events(li))
415                 fprintf(stderr, "Expected device added events on startup but got none. "
416                                 "Maybe you don't have the right permissions?\n");
417
418         while (poll(fds, 2, -1) > -1) {
419                 if (fds[1].revents)
420                         break;
421
422                 handle_and_print_events(li);
423         }
424
425         close(fds[1].fd);
426 }
427
428 int
429 main(int argc, char **argv)
430 {
431         struct libinput *li;
432         struct timespec tp;
433
434         if (parse_args(argc, argv))
435                 return 1;
436
437         if (mode == MODE_UDEV) {
438                 if (open_udev(&li))
439                         return 1;
440         } else if (mode == MODE_DEVICE) {
441                 if (open_device(&li, device))
442                         return 1;
443         } else
444                 abort();
445
446         clock_gettime(CLOCK_MONOTONIC, &tp);
447         start_time = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
448
449         mainloop(li);
450
451         if (udev)
452                 udev_unref(udev);
453
454         return 0;
455 }