[PATCH libinput 5/5] tools: add a tool for basic event debugging
Jonas Ådahl
jadahl at gmail.com
Wed Jan 29 12:38:34 PST 2014
On Wed, Jan 29, 2014 at 11:55:37AM +1000, Peter Hutterer wrote:
> Simply prints the various events to make it easier to check what's coming out
> of libinput. Works for --udev (the default) or for --device /dev/input/event0.
> Example output:
>
> event7 DEVICE_ADDED seat0 default
> event8 DEVICE_ADDED seat0 default
> event4 POINTER_BUTTON +1.35s 272 pressed
> event5 POINTER_MOTION +2.31s -3.00/ 2.00
>
> Time is displayed relative to the starting time.
>
> Note: statically linked for easier debugging, but we don't distribute it
> (yet) anyway.
>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
Neat tool!
This and the other 4, Reviewed-by: Jonas Ådahl <jadahl at gmail.com>
> ---
> Makefile.am | 2 +-
> configure.ac | 3 +-
> tools/.gitignore | 1 +
> tools/Makefile.am | 7 +
> tools/event-debug.c | 453 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 464 insertions(+), 2 deletions(-)
> create mode 100644 tools/.gitignore
> create mode 100644 tools/Makefile.am
> create mode 100644 tools/event-debug.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 07bfcd4..08bf7ce 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -1,3 +1,3 @@
> -SUBDIRS = src doc test
> +SUBDIRS = src doc test tools
>
> ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
> diff --git a/configure.ac b/configure.ac
> index 7281bb4..44729a9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -87,5 +87,6 @@ AC_CONFIG_FILES([Makefile
> src/Makefile
> src/libinput.pc
> src/libinput-version.h
> - test/Makefile])
> + test/Makefile
> + tools/Makefile])
> AC_OUTPUT
> diff --git a/tools/.gitignore b/tools/.gitignore
> new file mode 100644
> index 0000000..2cdd654
> --- /dev/null
> +++ b/tools/.gitignore
> @@ -0,0 +1 @@
> +event-debug
> diff --git a/tools/Makefile.am b/tools/Makefile.am
> new file mode 100644
> index 0000000..9c29f56
> --- /dev/null
> +++ b/tools/Makefile.am
> @@ -0,0 +1,7 @@
> +noinst_PROGRAMS = event-debug
> +
> +AM_CPPFLAGS = -I$(top_srcdir)/src
> +
> +event_debug_SOURCES = event-debug.c
> +event_debug_LDADD = ../src/libinput.la
> +event_debug_LDFLAGS = -static
> diff --git a/tools/event-debug.c b/tools/event-debug.c
> new file mode 100644
> index 0000000..53e92b0
> --- /dev/null
> +++ b/tools/event-debug.c
> @@ -0,0 +1,453 @@
> +/*
> + * Copyright © 2014 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#define _GNU_SOURCE
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <getopt.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <time.h>
> +#include <unistd.h>
> +#include <linux/input.h>
> +#include <sys/ioctl.h>
> +#include <sys/signalfd.h>
> +
> +#include <libinput.h>
> +
> +static enum {
> + MODE_UDEV,
> + MODE_DEVICE,
> +} mode = MODE_UDEV;
> +static const char *device;
> +static const char *seat = "seat0";
> +static struct udev *udev;
> +uint32_t start_time;
> +
> +static void
> +usage(void)
> +{
> + printf("Usage: %s [--udev [<seat>]|--device /dev/input/event0]\n"
> + "--udev <seat>.... Use udev device discovery (default).\n"
> + " Specifying a seat ID is optional.\n"
> + "--device /path/to/device .... open the given device only\n",
> + program_invocation_short_name);
> +}
> +
> +static int
> +parse_args(int argc, char **argv)
> +{
> + while (1) {
> + int c;
> + int option_index = 0;
> + static struct option opts[] = {
> + { "device", 1, 0, 'd' },
> + { "udev", 0, 0, 'u' },
> + { "help", 0, 0, 'h' },
> + { 0, 0, 0, 0}
> + };
> +
> + c = getopt_long(argc, argv, "h", opts, &option_index);
> + if (c == -1)
> + break;
> +
> + switch(c) {
> + case 'h': /* --help */
> + usage();
> + exit(0);
> + case 'd': /* --device */
> + mode = MODE_DEVICE;
> + if (!optarg) {
> + usage();
> + return 1;
> + }
> + device = optarg;
> + break;
> + case 'u': /* --udev */
> + mode = MODE_UDEV;
> + if (optarg)
> + seat = optarg;
> + break;
> + default:
> + usage();
> + return 1;
> + }
> +
> + }
> +
> + if (optind < argc) {
> + usage();
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +open_restricted(const char *path, int flags, void *user_data)
> +{
> + int fd = open(path, flags);
> + int clockid = CLOCK_MONOTONIC;
> +
> + if (fd >= 0 && ioctl(fd, EVIOCSCLOCKID, &clockid) < 0)
> + fprintf(stderr, "Changing clock on %s failed, timestamps "
> + "will be off\n", path);
> +
> + return fd < 0 ? -errno : fd;
> +}
> +
> +static void
> +close_restricted(int fd, void *user_data)
> +{
> + close(fd);
> +}
> +
> +static void get_current_screen_dimensions(struct libinput_device *device,
> + int *width,
> + int *height,
> + void *user_data)
> +{
> + /* display absdata in % of the screen */
> + *width = 100;
> + *height = 100;
> +}
> +
> +const static struct libinput_interface interface = {
> + .open_restricted = open_restricted,
> + .close_restricted = close_restricted,
> + .get_current_screen_dimensions = get_current_screen_dimensions,
> +};
> +
> +static int
> +open_udev(struct libinput **li)
> +{
> + udev = udev_new();
> + if (!udev) {
> + fprintf(stderr, "Failed to initialize udev\n");
> + return 1;
> + }
> +
> + *li = libinput_create_from_udev(&interface, NULL, udev, seat);
> + if (!*li) {
> + fprintf(stderr, "Failed to initialize context from udev\n");
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +open_device(struct libinput **li, const char *path)
> +{
> + *li = libinput_create_from_path(&interface, NULL, path);
> + if (!*li) {
> + fprintf(stderr, "Failed to initialize context from %s\n", path);
> + return 1;
> + }
> + return 0;
> +}
> +
> +static void
> +print_event_header(struct libinput_event *ev)
> +{
> + struct libinput_device *dev = libinput_event_get_device(ev);
> + const char *type;
> +
> + switch(libinput_event_get_type(ev)) {
> + case LIBINPUT_EVENT_NONE:
> + abort();
> + case LIBINPUT_EVENT_DEVICE_ADDED:
> + type = "DEVICE_ADDED";
> + break;
> + case LIBINPUT_EVENT_DEVICE_REMOVED:
> + type = "DEVICE_REMOVED";
> + break;
> + case LIBINPUT_EVENT_KEYBOARD_KEY:
> + type = "KEYBOARD_KEY";
> + break;
> + case LIBINPUT_EVENT_POINTER_MOTION:
> + type = "POINTER_MOTION";
> + break;
> + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
> + type = "POINTER_MOTION_ABSOLUTE";
> + break;
> + case LIBINPUT_EVENT_POINTER_BUTTON:
> + type = "POINTER_BUTTON";
> + break;
> + case LIBINPUT_EVENT_POINTER_AXIS:
> + type = "POINTER_AXIS";
> + break;
> + case LIBINPUT_EVENT_TOUCH_TOUCH:
> + type = "TOUCH_TOUCH";
> + break;
> + case LIBINPUT_EVENT_TOUCH_FRAME:
> + type = "TOUCH_FRAME";
> + break;
> + }
> +
> + printf("%-7s %s ", libinput_device_get_sysname(dev), type);
> +}
> +
> +static void
> +print_event_time(uint32_t time)
> +{
> + printf("%+6.2fs ", (time - start_time) / 1000.0);
> +}
> +
> +static void
> +print_device_notify(struct libinput_event *ev)
> +{
> + struct libinput_device *dev = libinput_event_get_device(ev);
> + struct libinput_seat *seat = libinput_device_get_seat(dev);
> +
> + printf("%s %s\n",
> + libinput_seat_get_physical_name(seat),
> + libinput_seat_get_logical_name(seat));
> +}
> +
> +static void
> +print_key_event(struct libinput_event *ev)
> +{
> + struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
> + enum libinput_keyboard_key_state state;
> +
> + print_event_time(libinput_event_keyboard_get_time(k));
> + state = libinput_event_keyboard_get_key_state(k);
> + printf("%d %s\n",
> + libinput_event_keyboard_get_key(k),
> + state == LIBINPUT_KEYBOARD_KEY_STATE_PRESSED ? "pressed" : "released");
> +}
> +
> +static void
> +print_motion_event(struct libinput_event *ev)
> +{
> + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
> + li_fixed_t x = libinput_event_pointer_get_dx(p),
> + y = libinput_event_pointer_get_dy(p);
> +
> + print_event_time(libinput_event_pointer_get_time(p));
> +
> + printf("%6.2f/%6.2f\n",
> + li_fixed_to_double(x),
> + li_fixed_to_double(y));
> +}
> +
> +static void
> +print_absmotion_event(struct libinput_event *ev)
> +{
> + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
> + li_fixed_t x = libinput_event_pointer_get_absolute_x(p),
> + y = libinput_event_pointer_get_absolute_y(p);
> +
> + print_event_time(libinput_event_pointer_get_time(p));
> + printf("%6.2f/%6.2f\n",
> + li_fixed_to_double(x),
> + li_fixed_to_double(y));
> +}
> +
> +static void
> +print_button_event(struct libinput_event *ev)
> +{
> + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
> + enum libinput_pointer_button_state state;
> +
> + print_event_time(libinput_event_pointer_get_time(p));
> +
> + state = libinput_event_pointer_get_button_state(p);
> + printf("%3d %s\n",
> + libinput_event_pointer_get_button(p),
> + state == LIBINPUT_POINTER_BUTTON_STATE_PRESSED ? "pressed" : "released");
> +}
> +
> +static void
> +print_axis_event(struct libinput_event *ev)
> +{
> + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
> + enum libinput_pointer_axis axis = libinput_event_pointer_get_axis(p);
> + const char *ax;
> + li_fixed_t val;
> +
> + switch (axis) {
> + case LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL:
> + ax = "vscroll";
> + break;
> + case LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL:
> + ax = "hscroll";
> + break;
> + default:
> + abort();
> + }
> +
> + print_event_time(libinput_event_pointer_get_time(p));
> + val = libinput_event_pointer_get_axis_value(p);
> + printf("%s %.2f\n",
> + ax, li_fixed_to_double(val));
> +}
> +
> +static void
> +print_touch_frame_event(struct libinput_event *ev)
> +{
> + struct libinput_event_touch *t = libinput_event_get_touch_event(ev);
> +
> + print_event_time(libinput_event_touch_get_time(t));
> + printf("\n");
> +}
> +
> +static void
> +print_touch_event(struct libinput_event *ev)
> +{
> + struct libinput_event_touch *t = libinput_event_get_touch_event(ev);
> + li_fixed_t x = libinput_event_touch_get_x(t),
> + y = libinput_event_touch_get_y(t);
> + const char *type;
> +
> + switch (libinput_event_touch_get_touch_type(t)) {
> + case LIBINPUT_TOUCH_TYPE_DOWN: type = "down"; break;
> + case LIBINPUT_TOUCH_TYPE_UP: type = "up"; break;
> + case LIBINPUT_TOUCH_TYPE_MOTION: type = "motion"; break;
> + case LIBINPUT_TOUCH_TYPE_CANCEL: type = "cancel"; break;
> + default:
> + abort();
> + }
> +
> + print_event_time(libinput_event_touch_get_time(t));
> +
> + printf("%6s %u %5.2f/%5.2f\n",
> + type,
> + libinput_event_touch_get_slot(t),
> + li_fixed_to_double(x),
> + li_fixed_to_double(y));
> +}
> +
> +static int
> +handle_and_print_events(struct libinput *li)
> +{
> + int rc = -1;
> + struct libinput_event *ev;
> +
> + libinput_dispatch(li);
> + while ((ev = libinput_get_event(li))) {
> + print_event_header(ev);
> +
> + switch (libinput_event_get_type(ev)) {
> + case LIBINPUT_EVENT_NONE:
> + abort();
> + case LIBINPUT_EVENT_DEVICE_ADDED:
> + case LIBINPUT_EVENT_DEVICE_REMOVED:
> + print_device_notify(ev);
> + break;
> + case LIBINPUT_EVENT_KEYBOARD_KEY:
> + print_key_event(ev);
> + break;
> + case LIBINPUT_EVENT_POINTER_MOTION:
> + print_motion_event(ev);
> + break;
> + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
> + print_absmotion_event(ev);
> + break;
> + case LIBINPUT_EVENT_POINTER_BUTTON:
> + print_button_event(ev);
> + break;
> + case LIBINPUT_EVENT_POINTER_AXIS:
> + print_axis_event(ev);
> + break;
> + case LIBINPUT_EVENT_TOUCH_TOUCH:
> + print_touch_event(ev);
> + break;
> + case LIBINPUT_EVENT_TOUCH_FRAME:
> + print_touch_frame_event(ev);
> + break;
> + }
> +
> + libinput_event_destroy(ev);
> + libinput_dispatch(li);
> + rc = 0;
> + }
> + return rc;
> +}
> +
> +void
> +mainloop(struct libinput *li)
> +{
> + struct pollfd fds[2];
> + sigset_t mask;
> +
> + fds[0].fd = libinput_get_fd(li);
> + fds[0].events = POLLIN;
> + fds[0].revents = 0;
> +
> + sigemptyset(&mask);
> + sigaddset(&mask, SIGINT);
> +
> + fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK);
> + fds[1].events = POLLIN;
> + fds[1].revents = 0;
> +
> + if (fds[1].fd == -1 ||
> + sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
> + fprintf(stderr, "Failed to set up signal handling (%s)\n",
> + strerror(errno));
> + }
> +
> + /* Handle already-pending device added events */
> + if (handle_and_print_events(li))
> + fprintf(stderr, "Expected device added events on startup but got none. "
> + "Maybe you don't have the right permissions?\n");
> +
> + while (poll(fds, 2, -1) > -1) {
> + if (fds[1].revents)
> + break;
> +
> + handle_and_print_events(li);
> + }
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> + struct libinput *li;
> + struct timespec tp;
> +
> + if (parse_args(argc, argv))
> + return 1;
> +
> + if (mode == MODE_UDEV) {
> + if (open_udev(&li))
> + return 1;
> + } else if (mode == MODE_DEVICE) {
> + if (open_device(&li, device))
> + return 1;
> + } else
> + abort();
> +
> + clock_gettime(CLOCK_MONOTONIC, &tp);
> + start_time = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
> +
> + mainloop(li);
> +
> + if (udev)
> + udev_unref(udev);
> +
> + return 0;
> +}
> --
> 1.8.4.2
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
More information about the wayland-devel
mailing list