[PATCH libevdev 1/3] tools: add a libevdev-measure-device tool

Peter Hutterer peter.hutterer at who-t.net
Tue Jan 20 19:48:09 PST 2015


On Tue, Jan 20, 2015 at 11:57:27AM -0500, Benjamin Tissoires wrote:
> On Mon, Jan 12, 2015 at 7:57 PM, Peter Hutterer
> <peter.hutterer at who-t.net> wrote:
> > We shouldn't add a new tool for each small functionality, incorporate them
> > into one tool with a couple of options instead.
> >
> > The current tools, touchpad-edge-detector and mouse-dpi-tool are kept for
> > backwards compatibility. Only change here is the usage() function which now
> > returns the new tool.
> >
> > Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> > ---
> >  tools/.gitignore                |   1 +
> >  tools/Makefile.am               |  17 +++-
> >  tools/libevdev-measure-device.1 |  42 ++++++++++
> >  tools/libevdev-measure-device.c | 172 ++++++++++++++++++++++++++++++++++++++++
> >  tools/libevdev-measure-device.h |  35 ++++++++
> >  tools/mouse-dpi-tool.c          |  52 +++---------
> >  tools/touchpad-edge-detector.c  |  56 +++----------
> >  7 files changed, 286 insertions(+), 89 deletions(-)
> >  create mode 100644 tools/libevdev-measure-device.1
> >  create mode 100644 tools/libevdev-measure-device.c
> >  create mode 100644 tools/libevdev-measure-device.h
> >
> > diff --git a/tools/.gitignore b/tools/.gitignore
> > index c2a2645..e583387 100644
> > --- a/tools/.gitignore
> > +++ b/tools/.gitignore
> > @@ -2,3 +2,4 @@ libevdev-events
> >  touchpad-edge-detector
> >  mouse-dpi-tool
> >  libevdev-tweak-device
> > +libevdev-measure-device
> > diff --git a/tools/Makefile.am b/tools/Makefile.am
> > index d699c5c..562bba1 100644
> > --- a/tools/Makefile.am
> > +++ b/tools/Makefile.am
> > @@ -1,5 +1,6 @@
> >  noinst_PROGRAMS = libevdev-events
> >  bin_PROGRAMS = \
> > +              libevdev-measure-device \
> >                touchpad-edge-detector \
> >                mouse-dpi-tool \
> >                libevdev-tweak-device
> > @@ -10,11 +11,19 @@ libevdev_ldadd = $(top_builddir)/libevdev/libevdev.la
> >  libevdev_events_SOURCES = libevdev-events.c
> >  libevdev_events_LDADD = $(libevdev_ldadd)
> >
> > -touchpad_edge_detector_SOURCES = touchpad-edge-detector.c
> > -touchpad_edge_detector_LDADD = $(libevdev_ldadd)
> > +libevdev_measure_device_SOURCES = \
> > +                                 libevdev-measure-device.c \
> > +                                 libevdev-measure-device.h \
> > +                                 touchpad-edge-detector.c \
> > +                                 mouse-dpi-tool.c
> > +libevdev_measure_device_LDADD = $(libevdev_ldadd)
> > +libevdev_measure_device_MANS = libevdev-measure-device.1
> >
> > -mouse_dpi_tool_SOURCES = mouse-dpi-tool.c
> > -mouse_dpi_tool_LDADD = $(libevdev_ldadd)
> > +touchpad_edge_detector_SOURCES = $(libevdev_measure_device_SOURCES)
> > +touchpad_edge_detector_LDADD = $(libevdev_measure_device_LDADD)
> > +
> > +mouse_dpi_tool_SOURCES = $(libevdev_measure_device_SOURCES)
> > +mouse_dpi_tool_LDADD = $(libevdev_measure_device_LDADD)
> >
> >  libevdev_tweak_device_SOURCES = libevdev-tweak-device.c
> >  libevdev_tweak_device_LDADD = $(libevdev_ldadd)
> > diff --git a/tools/libevdev-measure-device.1 b/tools/libevdev-measure-device.1
> > new file mode 100644
> > index 0000000..69d0d31
> > --- /dev/null
> > +++ b/tools/libevdev-measure-device.1
> > @@ -0,0 +1,42 @@
> > +.TH LIBEVDEV-MEASURE-DEVICE "1"
> > +.SH NAME
> > +libevdev-measure-device \- measure properties of an evdev kernel device
> > +.SH SYNOPSIS
> > +.B libevdev-measure-device
> > +<type> <mode> /dev/input/eventX
> > +.PP
> > +.SH DESCRIPTION
> > +.PP
> > +The
> > +.I libevdev-measure-device
> > +tool measures properties of the evdev kernel device at
> > +.I /dev/input/eventX.
> > +.SH OPTIONS
> > +The <type> may be one of "touchpad" or "mouse", each type has different
> > +modes and options.
> > +.SS Touchpad-specific options
> > +.TP 8
> > +.B edges
> > +Measure the min/max edge values used by the touchpad. Each touchpad
> > +advertises a min/max range for the x and y axis. On some touchpads, these
> > +values do not reflect what the touchpad actually supports.
> > +.SS Mouse-specific options
> > +.TP 8
> > +.B dpi
> > +Measure the mouse sensor's resolution and frequency. See the section
> > +"Measuring the sensor resolution" for details.
> > +.SH NOTES
> > +.SS Measuring the sensor resolution
> > +.PP
> > +The best way to measure the sensor resolution is to take a piece of paper
> > +and mark two spots a fixed distance apart. Line up the left edge of the mouse
> > +with the left spot, then move the mouse until the left edge of the mouse
> > +lines up with the right spot. It is recommended that the two spots are at
> > +least 25cm/10in apart. If the two spots are exactly 254mm/10in apart, the
> > +sensor resolution is one-tenth of the device units measured.
> > +.PP
> > +The frequency reported by
> > +.B libevdev-measure-device
> > +is the maximum frequency encountered. Some mouse devices provide dynamic
> > +frequencies, it is recommended to measure multiple times to obtain the
> > +highest value.
> > diff --git a/tools/libevdev-measure-device.c b/tools/libevdev-measure-device.c
> > new file mode 100644
> > index 0000000..b6cf4b5
> > --- /dev/null
> > +++ b/tools/libevdev-measure-device.c
> > @@ -0,0 +1,172 @@
> > +/*
> > + * Copyright © 2015 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 Red Hat
> > + * not be used in advertising or publicity pertaining to distribution
> > + * of the software without specific, written prior permission.  Red
> > + * Hat makes no representations about the suitability of this software
> > + * for any purpose.  It is provided "as is" without express or implied
> > + * warranty.
> > + *
> > + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
> > + * NO EVENT SHALL THE AUTHORS 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
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +
> > +#include <libevdev/libevdev.h>
> > +
> > +#include "libevdev-measure-device.h"
> > +
> > +static int
> > +mouse_run(int argc, char **argv)
> > +{
> > +       int rc;
> > +
> > +       if (argc < 2)
> > +               rc = EXIT_USAGE;
> > +       else if (strcmp(argv[0], "dpi") == 0)
> > +               rc = mouse_dpi_tool(argc - 1, &argv[1]);
> > +       else
> > +               rc = EXIT_USAGE;
> > +
> > +       return rc;
> > +}
> > +
> > +static int
> > +touchpad_run(int argc, char **argv)
> > +{
> > +       int rc;
> > +
> > +       if (argc < 2)
> > +               rc = EXIT_USAGE;
> > +       else if (strcmp(argv[0], "edges") == 0)
> > +               rc = touchpad_edge_detector(argc - 1, &argv[1]);
> > +       else
> > +               rc = EXIT_USAGE;
> > +
> > +       return rc;
> > +}
> > +
> > +struct mode {
> > +       const char *mode;
> > +       int (*run)(int argc, char **argv);
> > +};
> > +
> > +static const struct mode modes[] = {
> > +       { "touchpad", touchpad_run },
> > +       { "mouse", mouse_run },
> > +       { NULL, NULL },
> > +};
> > +
> > +struct libevdev *
> > +open_device(const char *path)
> > +{
> > +       struct libevdev *dev = NULL;
> > +       int fd, rc;
> > +
> > +       fd = open(path, O_RDONLY|O_NONBLOCK);
> > +       if (fd < 0) {
> > +               fprintf(stderr, "Error opening the device: %s\n", strerror(errno));
> > +               goto error;
> > +       }
> > +
> > +       rc = libevdev_new_from_fd(fd, &dev);
> > +       if (rc != 0) {
> > +               fprintf(stderr, "Error fetching the device info: %s\n", strerror(-rc));
> > +               goto error;
> > +       }
> > +
> > +       if (libevdev_grab(dev, LIBEVDEV_GRAB) != 0) {
> > +               fprintf(stderr, "Error: cannot grab the device, something else is grabbing it.\n");
> > +               fprintf(stderr, "Use 'fuser -v %s' to find processes with an open fd\n", path);
> > +               goto error;
> > +       }
> > +       libevdev_grab(dev, LIBEVDEV_UNGRAB);
> > +
> > +       return dev;
> > +
> > +error:
> > +       libevdev_free(dev);
> > +       if (fd != -1)
> > +               close(fd);
> > +       return NULL;
> > +}
> > +
> > +void
> > +close_device(struct libevdev *dev)
> > +{
> > +       int fd = libevdev_get_fd(dev);
> > +       libevdev_free(dev);
> > +       close(fd);
> > +}
> > +
> > +static void
> > +usage(void)
> > +{
> > +       printf("libevdev-measure-device <type> <mode> [options] <path>\n"
> > +              "\n"
> > +              "For type \"touchpad\":\n"
> > +              "    mode \"edges\" ... measure the edges of the touchpad\n"
> > +              "\n"
> > +              "For type \"mouse\":\n"
> > +              "    mode \"dpi\" ... measure the DPI/frequency of the mouse\n");
> > +}
> > +
> > +int
> > +main (int argc, char **argv) {
> > +       int rc = EXIT_USAGE;
> > +       const struct mode *mode;
> > +       const char *prgname = program_invocation_short_name;
> > +
> > +       if (strcmp(prgname, "mouse-dpi-tool") == 0 ||
> > +           strcmp(prgname, "lt-mouse-dpi-tool") == 0) {
> > +               rc = mouse_dpi_tool(argc - 1, &argv[1]);
> > +       } else if (strcmp(prgname, "touchpad-edge-detector") == 0 ||
> > +                  strcmp(prgname, "lt-touchpad-edge-detector") == 0) {
> > +               rc = touchpad_edge_detector(argc - 1, &argv[1]);
> 
> Can't you unify these 2 tests with the mode->run code below?

not quite sure what you mean tbt. the problem is that we use argv[1] here vs
argv[2] for the new case with keywords. So there's some strcmp/special
casing needed anyway - this way it's at least very explicit.

> 
> > +       } else {
> > +
> > +               if (argc >= 2 &&
> > +                   (strcmp(argv[1], "--help") == 0 ||
> > +                          strcmp(argv[1], "-h") == 0)) {
> > +                       usage();
> > +                       return 0;
> 
> I would have a validate_params() function and call usage() only once
> when rc == EXIT_USAGE.

this bit covers the libevdev-measure-device --help case which is a valid
invocation - hence the return 0 instead of the error. Could be unified but
would feel dirty :)

> > +               } else if (argc < 3) {
> > +                       usage();
> > +                       return EXIT_USAGE;
> > +               }
> 
> If I call the program with "./libevdev-measure-device foo bar --help",
> the following loop will be executed. Not that it matters that much,
> but why do we check for -h and --help previously if the general case
> will deal with it?

mostly because that will allow us (in the future) to have keyword-specific
help options. Which is currently missing but 
  libevdev-measure-device touchpad --help
should be a bit more explanatory than what usage() provides. We could just
display the man page then though...

Cheers,
   Peter

 
> Just nitpicking because it was not obvious at first how the option
> parsing was working.
> 
> Cheers,
> Benjamin
> 
> > +
> > +               mode = modes;
> > +               while (mode->mode) {
> > +                       if (strcmp(mode->mode, argv[1]) == 0) {
> > +                               rc = mode->run(argc - 2, &argv[2]);
> > +                               break;
> > +                       }
> > +                       mode++;
> > +               }
> > +       }
> > +
> > +       if (rc == EXIT_USAGE)
> > +               usage();
> > +       return rc;
> > +}
> > diff --git a/tools/libevdev-measure-device.h b/tools/libevdev-measure-device.h
> > new file mode 100644
> > index 0000000..94579e7
> > --- /dev/null
> > +++ b/tools/libevdev-measure-device.h
> > @@ -0,0 +1,35 @@
> > +/*
> > + * Copyright © 2015 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 Red Hat
> > + * not be used in advertising or publicity pertaining to distribution
> > + * of the software without specific, written prior permission.  Red
> > + * Hat makes no representations about the suitability of this software
> > + * for any purpose.  It is provided "as is" without express or implied
> > + * warranty.
> > + *
> > + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
> > + * NO EVENT SHALL THE AUTHORS 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.
> > + */
> > +
> > +
> > +#ifndef LIBEVDEV_MEASURE_DEVICE_H
> > +#define LIBEVDEV_MEASURE_DEVICE_H
> > +
> > +#define EXIT_USAGE 2
> > +
> > +int touchpad_edge_detector(int argc, char **argv);
> > +int mouse_dpi_tool(int argc, char **argv);
> > +
> > +struct libevdev * open_device(const char *path);
> > +void close_device(struct libevdev * dev);
> > +#endif /* LIBEVDEV_MEASURE_DEVICE_H */
> > diff --git a/tools/mouse-dpi-tool.c b/tools/mouse-dpi-tool.c
> > index be30a4d..b0543f0 100644
> > --- a/tools/mouse-dpi-tool.c
> > +++ b/tools/mouse-dpi-tool.c
> > @@ -26,9 +26,9 @@
> >  #endif
> >
> >  #include <libevdev/libevdev.h>
> > +#include <libevdev/libevdev-util.h>
> >  #include <sys/signalfd.h>
> >  #include <errno.h>
> > -#include <fcntl.h>
> >  #include <limits.h>
> >  #include <poll.h>
> >  #include <signal.h>
> > @@ -36,10 +36,8 @@
> >  #include <stdlib.h>
> >  #include <stdio.h>
> >  #include <string.h>
> > -#include <unistd.h>
> >
> > -#define min(a, b) (((a) < (b)) ? (a) : (b))
> > -#define max(a, b) (((a) > (b)) ? (a) : (b))
> > +#include "libevdev-measure-device.h"
> >
> >  struct measurements {
> >         int distance;
> > @@ -47,17 +45,6 @@ struct measurements {
> >         uint32_t ms;
> >  };
> >
> > -static int
> > -usage(void) {
> > -       printf("Usage: %s /dev/input/event0\n", program_invocation_short_name);
> > -       printf("\n");
> > -       printf("This tool reads relative events from the kernel and calculates\n"
> > -              "the distance covered and maximum frequency of the incoming events.\n"
> > -              "Some mouse devices provide dynamic frequencies, it is\n"
> > -              "recommended to measure multiple times to obtain the highest value.\n");
> > -       return 1;
> > -}
> > -
> >  static inline uint32_t
> >  tv2ms(const struct timeval *tv)
> >  {
> > @@ -207,38 +194,20 @@ bustype(int bustype)
> >  }
> >
> >  int
> > -main (int argc, char **argv) {
> > +mouse_dpi_tool (int argc, char **argv) {
> >         int rc;
> > -       int fd;
> >         const char *path;
> >         struct libevdev *dev;
> >         struct measurements measurements = {0, 0, 0};
> >
> > -       if (argc < 2)
> > -               return usage();
> > +       if (argc < 1)
> > +               return EXIT_USAGE;
> >
> > -       path = argv[1];
> > -       if (path[0] == '-')
> > -               return usage();
> > +       path = argv[0];
> >
> > -       fd = open(path, O_RDONLY|O_NONBLOCK);
> > -       if (fd < 0) {
> > -               fprintf(stderr, "Error opening the device: %s\n", strerror(errno));
> > -               return 1;
> > -       }
> > -
> > -       rc = libevdev_new_from_fd(fd, &dev);
> > -       if (rc != 0) {
> > -               fprintf(stderr, "Error fetching the device info: %s\n", strerror(-rc));
> > -               return 1;
> > -       }
> > -
> > -       if (libevdev_grab(dev, LIBEVDEV_GRAB) != 0) {
> > -               fprintf(stderr, "Error: cannot grab the device, something else is grabbing it.\n");
> > -               fprintf(stderr, "Use 'fuser -v %s' to find processes with an open fd\n", path);
> > -               return 1;
> > -       }
> > -       libevdev_grab(dev, LIBEVDEV_UNGRAB);
> > +       dev = open_device(path);
> > +       if (!dev)
> > +               return EXIT_FAILURE;
> >
> >         printf("Mouse %s on %s\n", libevdev_get_name(dev), path);
> >         printf("Move the device 250mm/10in or more along the x-axis.\n");
> > @@ -261,8 +230,7 @@ main (int argc, char **argv) {
> >                libevdev_get_name(dev),
> >                (int)measurements.frequency);
> >
> > -       libevdev_free(dev);
> > -       close(fd);
> > +       close_device(dev);
> >
> >         return rc;
> >  }
> > diff --git a/tools/touchpad-edge-detector.c b/tools/touchpad-edge-detector.c
> > index b857934..df0f032 100644
> > --- a/tools/touchpad-edge-detector.c
> > +++ b/tools/touchpad-edge-detector.c
> > @@ -26,9 +26,9 @@
> >  #endif
> >
> >  #include <libevdev/libevdev.h>
> > +#include <libevdev/libevdev-util.h>
> >  #include <sys/signalfd.h>
> >  #include <errno.h>
> > -#include <fcntl.h>
> >  #include <limits.h>
> >  #include <poll.h>
> >  #include <signal.h>
> > @@ -36,19 +36,8 @@
> >  #include <stdlib.h>
> >  #include <stdio.h>
> >  #include <string.h>
> > -#include <unistd.h>
> >
> > -#define min(a, b) (((a) < (b)) ? (a) : (b))
> > -#define max(a, b) (((a) > (b)) ? (a) : (b))
> > -
> > -static int
> > -usage(void) {
> > -       printf("Usage: %s /dev/input/event0\n", program_invocation_short_name);
> > -       printf("\n");
> > -       printf("This tool reads the touchpad events from the kernel and calculates\n "
> > -              "the minimum and maximum for the x and y coordinates, respectively.\n");
> > -       return 1;
> > -}
> > +#include "libevdev-measure-device.h"
> >
> >  struct dimensions {
> >         int top, bottom, left, right;
> > @@ -123,10 +112,10 @@ mainloop(struct libevdev *dev, struct dimensions *dim) {
> >                         rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
> >                         if (rc == LIBEVDEV_READ_STATUS_SYNC) {
> >                                 fprintf(stderr, "Error: cannot keep up\n");
> > -                               return 1;
> > +                               return EXIT_FAILURE;
> >                         } else if (rc != -EAGAIN && rc < 0) {
> >                                 fprintf(stderr, "Error: %s\n", strerror(-rc));
> > -                               return 1;
> > +                               return EXIT_FAILURE;
> >                         } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
> >                                 handle_event(dim, &ev);
> >                         }
> > @@ -136,38 +125,20 @@ mainloop(struct libevdev *dev, struct dimensions *dim) {
> >         return 0;
> >  }
> >
> > -int main (int argc, char **argv) {
> > +int
> > +touchpad_edge_detector (int argc, char **argv) {
> >         int rc;
> > -       int fd;
> >         const char *path;
> >         struct libevdev *dev;
> >         struct dimensions dim;
> >
> > -       if (argc < 2)
> > -               return usage();
> > +       if (argc < 1)
> > +               return EXIT_USAGE;
> >
> > -       path = argv[1];
> > -       if (path[0] == '-')
> > -               return usage();
> > -
> > -       fd = open(path, O_RDONLY|O_NONBLOCK);
> > -       if (fd < 0) {
> > -               fprintf(stderr, "Error opening the device: %s\n", strerror(errno));
> > -               return 1;
> > -       }
> > -
> > -       rc = libevdev_new_from_fd(fd, &dev);
> > -       if (rc != 0) {
> > -               fprintf(stderr, "Error fetching the device info: %s\n", strerror(-rc));
> > -               return 1;
> > -       }
> > -
> > -       if (libevdev_grab(dev, LIBEVDEV_GRAB) != 0) {
> > -               fprintf(stderr, "Error: cannot grab the device, something else is grabbing it.\n");
> > -               fprintf(stderr, "Use 'fuser -v %s' to find processes with an open fd\n", path);
> > -               return 1;
> > -       }
> > -       libevdev_grab(dev, LIBEVDEV_UNGRAB);
> > +       path = argv[0];
> > +       dev = open_device(path);
> > +       if (!dev)
> > +               return EXIT_FAILURE;
> >
> >         dim.left = INT_MAX;
> >         dim.right = INT_MIN;
> > @@ -188,8 +159,7 @@ int main (int argc, char **argv) {
> >
> >         printf("\n");
> >
> > -       libevdev_free(dev);
> > -       close(fd);
> > +       close_device(dev);
> >
> >         return rc;
> >  }
> > --
> > 2.1.0
> >
> > _______________________________________________
> > Input-tools mailing list
> > Input-tools at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/input-tools
> 


More information about the Input-tools mailing list