[PATCH libevdev 2/3] tools: add wheel click measurement

Benjamin Tissoires benjamin.tissoires at gmail.com
Tue Jan 20 09:09:09 PST 2015


On Mon, Jan 12, 2015 at 7:57 PM, Peter Hutterer
<peter.hutterer at who-t.net> wrote:
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>  tools/Makefile.am               |   3 +-
>  tools/libevdev-measure-device.1 |   9 +++
>  tools/libevdev-measure-device.c |   5 +-
>  tools/libevdev-measure-device.h |   1 +
>  tools/mouse-wheel-tool.c        | 169 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 185 insertions(+), 2 deletions(-)
>  create mode 100644 tools/mouse-wheel-tool.c
>
> diff --git a/tools/Makefile.am b/tools/Makefile.am
> index 562bba1..5d9706d 100644
> --- a/tools/Makefile.am
> +++ b/tools/Makefile.am
> @@ -15,7 +15,8 @@ libevdev_measure_device_SOURCES = \
>                                   libevdev-measure-device.c \
>                                   libevdev-measure-device.h \
>                                   touchpad-edge-detector.c \
> -                                 mouse-dpi-tool.c
> +                                 mouse-dpi-tool.c \
> +                                 mouse-wheel-tool.c
>  libevdev_measure_device_LDADD = $(libevdev_ldadd)
>  libevdev_measure_device_MANS = libevdev-measure-device.1
>
> diff --git a/tools/libevdev-measure-device.1 b/tools/libevdev-measure-device.1
> index 69d0d31..cecd275 100644
> --- a/tools/libevdev-measure-device.1
> +++ b/tools/libevdev-measure-device.1
> @@ -25,6 +25,10 @@ values do not reflect what the touchpad actually supports.
>  .B dpi
>  Measure the mouse sensor's resolution and frequency. See the section
>  "Measuring the sensor resolution" for details.
> +.TP 8
> +.B wheel
> +Measure the angle of each mouse wheel click. See the section "measuring
> +wheel click angles" for details.
>  .SH NOTES
>  .SS Measuring the sensor resolution
>  .PP
> @@ -40,3 +44,8 @@ The frequency reported by
>  is the maximum frequency encountered. Some mouse devices provide dynamic
>  frequencies, it is recommended to measure multiple times to obtain the
>  highest value.
> +.SS Measuring wheel click angles
> +.PP
> +The best way to measure the wheel click angles is to mark the mouse wheel
> +with a pen. Then rotate the wheel once until the marked spot lines up with
> +the previous physical location again.
> diff --git a/tools/libevdev-measure-device.c b/tools/libevdev-measure-device.c
> index b6cf4b5..0f459be 100644
> --- a/tools/libevdev-measure-device.c
> +++ b/tools/libevdev-measure-device.c
> @@ -46,6 +46,8 @@ mouse_run(int argc, char **argv)
>                 rc = EXIT_USAGE;
>         else if (strcmp(argv[0], "dpi") == 0)
>                 rc = mouse_dpi_tool(argc - 1, &argv[1]);
> +       else if (strcmp(argv[0], "wheel") == 0)
> +               rc = mouse_wheel_tool(argc - 1, &argv[1]);

I missed that in the previous patch. You are mixing function pointers
in an array for the first arg, but then a plain function call for the
second arg.

Maybe we should either have only one array, or plain functions calls,
but this seems a little bit weird (not to mention that the code of
mouse_run and touchpad_run are similar).

>         else
>                 rc = EXIT_USAGE;
>
> @@ -129,7 +131,8 @@ usage(void)
>                "    mode \"edges\" ... measure the edges of the touchpad\n"
>                "\n"
>                "For type \"mouse\":\n"
> -              "    mode \"dpi\" ... measure the DPI/frequency of the mouse\n");
> +              "    mode \"dpi\" ... measure the DPI/frequency of the mouse\n"
> +              "    mode \"wheel\" ... measure the angle for wheel clicks\n");
>  }
>
>  int
> diff --git a/tools/libevdev-measure-device.h b/tools/libevdev-measure-device.h
> index 94579e7..151244e 100644
> --- a/tools/libevdev-measure-device.h
> +++ b/tools/libevdev-measure-device.h
> @@ -29,6 +29,7 @@
>
>  int touchpad_edge_detector(int argc, char **argv);
>  int mouse_dpi_tool(int argc, char **argv);
> +int mouse_wheel_tool(int argc, char **argv);
>
>  struct libevdev * open_device(const char *path);
>  void close_device(struct libevdev * dev);
> diff --git a/tools/mouse-wheel-tool.c b/tools/mouse-wheel-tool.c
> new file mode 100644
> index 0000000..9b56cac
> --- /dev/null
> +++ b/tools/mouse-wheel-tool.c
> @@ -0,0 +1,169 @@
> +/*
> + * 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 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.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include <libevdev/libevdev.h>
> +#include <sys/signalfd.h>
> +#include <errno.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <signal.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include "libevdev-measure-device.h"
> +
> +
> +static int
> +print_current_values(int wheel_counts)
> +{
> +       static int progress = 0;
> +       char status = 0;
> +
> +       switch (progress) {
> +               case 0: status = '|'; break;
> +               case 1: status = '/'; break;
> +               case 2: status = '-'; break;
> +               case 3: status = '\\'; break;
> +               default:
> +                       status = '?';
> +                       break;
> +       }
> +
> +       progress = (progress + 1) % 4;
> +       printf("\rWheel steps counted: %8d      %c",
> +               wheel_counts, status);
> +
> +       return 0;
> +}
> +
> +static unsigned int
> +mainloop(struct libevdev *dev) {
> +       struct pollfd fds[2];
> +       sigset_t mask;
> +       int wheel_counts = 0;
> +
> +       fds[0].fd = libevdev_get_fd(dev);
> +       fds[0].events = POLLIN;
> +
> +       sigemptyset(&mask);
> +       sigaddset(&mask, SIGINT);
> +       fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK);
> +       fds[1].events = POLLIN;
> +
> +       sigprocmask(SIG_BLOCK, &mask, NULL);
> +
> +       while (poll(fds, 2, -1)) {
> +               struct input_event ev;
> +               int rc;
> +
> +               if (fds[1].revents)
> +                       break;
> +
> +               do {
> +                       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;
> +                       } else if (rc != -EAGAIN && rc < 0) {
> +                               fprintf(stderr, "Error: %s\n", strerror(-rc));
> +                               return 1;
> +                       } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
> +                               if (libevdev_event_is_code(&ev,
> +                                                          EV_REL,
> +                                                          REL_WHEEL)) {
> +                                       wheel_counts += ev.value;
> +                                       print_current_values(abs(wheel_counts));
> +                               }
> +                       }
> +               } while (rc != -EAGAIN);
> +       }
> +
> +       return abs(wheel_counts);
> +}
> +
> +static inline const char*
> +bustype(int bustype)
> +{
> +       const char *bus;
> +
> +       switch(bustype) {
> +               case BUS_PCI: bus = "pci"; break;
> +               case BUS_ISAPNP: bus = "isapnp"; break;
> +               case BUS_USB: bus = "usb"; break;
> +               case BUS_HIL: bus = "hil"; break;
> +               case BUS_BLUETOOTH: bus = "bluetooth"; break;
> +               case BUS_VIRTUAL: bus = "virtual"; break;
> +               default: bus = "unknown bus type"; break;
> +       }
> +
> +       return bus;
> +}

Isn't this code also in the dpi tool?

> +
> +int
> +mouse_wheel_tool(int argc, char **argv) {
> +       const char *path;
> +       struct libevdev *dev;
> +       unsigned int wheel_count = 0;
> +
> +       if (argc < 1)
> +               return EXIT_USAGE;
> +
> +       path = argv[0];
> +       dev = open_device(path);
> +       if (!dev)
> +               return EXIT_FAILURE;
> +
> +       if (!libevdev_has_event_code(dev, EV_REL, REL_WHEEL)) {
> +               fprintf(stderr, "Error: this device doesn't have a wheel.\n");
> +               close_device(dev);
> +               return EXIT_FAILURE;
> +       }
> +
> +       printf("Mouse %s on %s\n", libevdev_get_name(dev), path);
> +       printf("Rotate the wheel by one full rotation. Ctrl+C to exit.\n");
> +       setbuf(stdout, NULL);
> +
> +       wheel_count = mainloop(dev);
> +
> +       printf("\n");
> +
> +       printf("Entry for hwdb match (replace XXX with the resolution in DPI):\n"
> +              "mouse:%s:v%04xp%04x:name:%s:\n"
> +              " MOUSE_WHEEL_CLICK_ANGLE=%d\n",
> +              bustype(libevdev_get_id_bustype(dev)),
> +              libevdev_get_id_vendor(dev),
> +              libevdev_get_id_product(dev),
> +              libevdev_get_name(dev),
> +              360/wheel_count);
> +
> +       close_device(dev);
> +
> +       return 0;
> +}
> --
> 2.1.0

I agree that this code works. But if you have one tool, and the
sub-tools code share a lot of similarities, can't we have only one
generic call and a few variant callbacks (are plain calls)?

On the other hand, maybe we don't want you to spend too much time on
this either :)

Cheers,
Benjamin


More information about the Input-tools mailing list