[PATCH libinput] evdev: implement support for the MOUSE_WHEEL_CLICK_COUNT property
Hans de Goede
hdegoede at redhat.com
Fri Oct 28 10:57:38 UTC 2016
Hi,
On 28-10-16 07:08, Peter Hutterer wrote:
> Not all mice have a click angle with integer degrees. The new
> MOUSE_WHEEL_CLICK_COUNT property specifies how many clicks per full rotation,
> the angle can be calculated from that.
>
> See https://github.com/systemd/systemd/pull/4440 for more information
>
> CLICK_COUNT overrides CLICK_ANGLE, so we check for the former first and then
> fall back to the angle if need be. No changes to the user-facing API.
>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
> src/evdev.c | 51 +++++++++++++++---
> src/libinput-private.h | 2 +-
> src/libinput-util.c | 32 ++++++++++++
> src/libinput-util.h | 1 +
> test/Makefile.am | 1 +
> test/litest-device-mouse-wheel-click-count.c | 77 ++++++++++++++++++++++++++++
> test/litest.c | 2 +
> test/litest.h | 1 +
> test/misc.c | 30 +++++++++++
> test/pointer.c | 49 +++++++++++++++---
> 10 files changed, 229 insertions(+), 17 deletions(-)
> create mode 100644 test/litest-device-mouse-wheel-click-count.c
>
> diff --git a/src/evdev.c b/src/evdev.c
> index d49b391..1c46534 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -2008,7 +2008,7 @@ evdev_device_init_pointer_acceleration(struct evdev_device *device,
> static inline bool
> evdev_read_wheel_click_prop(struct evdev_device *device,
> const char *prop,
> - int *angle)
> + double *angle)
> {
> int val;
>
> @@ -2032,18 +2032,53 @@ evdev_read_wheel_click_prop(struct evdev_device *device,
> return false;
> }
>
> +static inline bool
> +evdev_read_wheel_click_count_prop(struct evdev_device *device,
> + const char *prop,
> + double *angle)
> +{
> + int val;
> +
> + prop = udev_device_get_property_value(device->udev_device, prop);
> + if (!prop)
> + return false;
> +
> + val = parse_mouse_wheel_click_angle_property(prop);
> + if (val) {
> + *angle = 360.0/val;
> + return true;
> + }
> +
> + log_error(evdev_libinput_context(device),
> + "Mouse wheel click count '%s' is present but invalid, "
> + "using %d degrees for angle instead instead\n",
> + device->devname,
> + DEFAULT_WHEEL_CLICK_ANGLE);
> + *angle = DEFAULT_WHEEL_CLICK_ANGLE;
> +
> + return false;
> +}
> +
This is almost a 100% copy of evdev_read_wheel_click_prop
how about giving evdev_read_wheel_click_prop an extra
"bool count" argument and then doing:
if (val) {
if (count)
*angle = 360.0 / val;
else
*angle = val;
return true;
}
Then we do not need the almost identical function.
> static inline struct wheel_angle
> evdev_read_wheel_click_props(struct evdev_device *device)
> {
> struct wheel_angle angles;
>
> - evdev_read_wheel_click_prop(device,
> - "MOUSE_WHEEL_CLICK_ANGLE",
> - &angles.x);
> - if (!evdev_read_wheel_click_prop(device,
> - "MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL",
> - &angles.y))
> - angles.y = angles.x;
> + /* CLICK_COUNT overrides CLICK_ANGLE */
> + if (!evdev_read_wheel_click_count_prop(device,
> + "MOUSE_WHEEL_CLICK_COUNT",
> + &angles.x))
> + evdev_read_wheel_click_prop(device,
> + "MOUSE_WHEEL_CLICK_ANGLE",
> + &angles.x);
> + if (!evdev_read_wheel_click_count_prop(device,
> + "MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL",
> + &angles.y)) {
> + if (!evdev_read_wheel_click_prop(device,
> + "MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL",
> + &angles.y))
> + angles.y = angles.x;
> + }
>
> return angles;
> }
> diff --git a/src/libinput-private.h b/src/libinput-private.h
> index 28656e0..2044cdd 100644
> --- a/src/libinput-private.h
> +++ b/src/libinput-private.h
> @@ -73,7 +73,7 @@ struct normalized_range_coords {
>
> /* A pair of angles in degrees */
> struct wheel_angle {
> - int x, y;
> + double x, y;
> };
>
> /* A pair of angles in degrees */
> diff --git a/src/libinput-util.c b/src/libinput-util.c
> index 4b90fbb..6c051c3 100644
> --- a/src/libinput-util.c
> +++ b/src/libinput-util.c
> @@ -176,6 +176,38 @@ parse_mouse_dpi_property(const char *prop)
> }
>
> /**
> + * Helper function to parse the MOUSE_WHEEL_CLICK_COUNT property from udev.
> + * Property is of the form:
> + * MOUSE_WHEEL_CLICK_COUNT=<integer>
> + * Where the number indicates the number of wheel clicks per 360 deg
> + * rotation.
> + *
> + * We skip preceding whitespaces and parse the first number seen. If
> + * multiple numbers are specified, we ignore those.
> + *
> + * @param prop The value of the udev property (without the MOUSE_WHEEL_CLICK_COUNT=)
> + * @return The click count of the wheel (may be negative) or 0 on error.
> + */
> +int
> +parse_mouse_wheel_click_count_property(const char *prop)
> +{
> + int count = 0,
> + nread = 0;
> +
> + while(*prop != 0 && *prop == ' ')
> + prop++;
> +
> + sscanf(prop, "%d%n", &count, &nread);
> + if (nread == 0 || count == 0 || abs(count) > 360)
> + return 0;
> + if (prop[nread] != ' ' && prop[nread] != '\0')
> + return 0;
> +
> + return count;
> +}
> +
> +/**
> + *
This is a 1:1 copy off parse_mouse_wheel_click_angle_property (with
s/angle/count/ but that does not change the functionality), please drop.
> * Helper function to parse the MOUSE_WHEEL_CLICK_ANGLE property from udev.
> * Property is of the form:
> * MOUSE_WHEEL_CLICK_ANGLE=<integer>
> diff --git a/src/libinput-util.h b/src/libinput-util.h
> index e31860d..b7bef80 100644
> --- a/src/libinput-util.h
> +++ b/src/libinput-util.h
> @@ -370,6 +370,7 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r);
>
> int parse_mouse_dpi_property(const char *prop);
> int parse_mouse_wheel_click_angle_property(const char *prop);
> +int parse_mouse_wheel_click_count_property(const char *prop);
> double parse_trackpoint_accel_property(const char *prop);
> bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
>
> diff --git a/test/Makefile.am b/test/Makefile.am
> index 7ff12e4..f4a9252 100644
> --- a/test/Makefile.am
> +++ b/test/Makefile.am
> @@ -35,6 +35,7 @@ liblitest_la_SOURCES = \
> litest-device-mouse-roccat.c \
> litest-device-mouse-low-dpi.c \
> litest-device-mouse-wheel-click-angle.c \
> + litest-device-mouse-wheel-click-count.c \
> litest-device-ms-surface-cover.c \
> litest-device-protocol-a-touch-screen.c \
> litest-device-qemu-usb-tablet.c \
> diff --git a/test/litest-device-mouse-wheel-click-count.c b/test/litest-device-mouse-wheel-click-count.c
> new file mode 100644
> index 0000000..419b702
> --- /dev/null
> +++ b/test/litest-device-mouse-wheel-click-count.c
> @@ -0,0 +1,77 @@
> +/*
> + * Copyright © 2016 Red Hat, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#if HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "litest.h"
> +#include "litest-int.h"
> +
> +static void litest_mouse_setup(void)
> +{
> + struct litest_device *d = litest_create_device(LITEST_MOUSE_WHEEL_CLICK_COUNT);
> + litest_set_current_device(d);
> +}
> +
> +static struct input_id input_id = {
> + .bustype = 0x3,
> + .vendor = 0x1234,
> + .product = 0x5678,
> +};
> +
> +static int events[] = {
> + EV_KEY, BTN_LEFT,
> + EV_KEY, BTN_RIGHT,
> + EV_KEY, BTN_MIDDLE,
> + EV_REL, REL_X,
> + EV_REL, REL_Y,
> + EV_REL, REL_WHEEL,
> + -1 , -1,
> +};
> +
> +static const char udev_rule[] =
> +"ACTION==\"remove\", GOTO=\"wheel_click_count_end\"\n"
> +"KERNEL!=\"event*\", GOTO=\"wheel_click_count_end\"\n"
> +"\n"
> +"ATTRS{name}==\"litest Wheel Click Count Mouse*\",\\\n"
> +" ENV{MOUSE_WHEEL_CLICK_ANGLE}=\"-15\",\n"
> +" ENV{MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL}=\"13\",\n\\"
> +" ENV{MOUSE_WHEEL_CLICK_COUNT}=\"-14\",\n"
> +" ENV{MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL}=\"27\"\\\n"
> +"\n"
> +"LABEL=\"wheel_click_count_end\"";
> +
> +struct litest_test_device litest_mouse_wheel_click_count_device = {
> + .type = LITEST_MOUSE_WHEEL_CLICK_COUNT,
> + .features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL,
> + .shortname = "mouse-wheelclickcount",
> + .setup = litest_mouse_setup,
> + .interface = NULL,
> +
> + .name = "Wheel Click Count Mouse",
> + .id = &input_id,
> + .absinfo = NULL,
> + .events = events,
> + .udev_rule = udev_rule,
> +};
> diff --git a/test/litest.c b/test/litest.c
> index fd62d21..515eb18 100644
> --- a/test/litest.c
> +++ b/test/litest.c
> @@ -402,6 +402,7 @@ extern struct litest_test_device litest_wacom_cintiq_13hdt_finger_device;
> extern struct litest_test_device litest_wacom_cintiq_13hdt_pen_device;
> extern struct litest_test_device litest_wacom_cintiq_13hdt_pad_device;
> extern struct litest_test_device litest_wacom_hid4800_tablet_device;
> +extern struct litest_test_device litest_mouse_wheel_click_count_device;
>
> struct litest_test_device* devices[] = {
> &litest_synaptics_clickpad_device,
> @@ -458,6 +459,7 @@ struct litest_test_device* devices[] = {
> &litest_wacom_cintiq_13hdt_pen_device,
> &litest_wacom_cintiq_13hdt_pad_device,
> &litest_wacom_hid4800_tablet_device,
> + &litest_mouse_wheel_click_count_device,
> NULL,
> };
>
> diff --git a/test/litest.h b/test/litest.h
> index 4602355..d52ebd2 100644
> --- a/test/litest.h
> +++ b/test/litest.h
> @@ -224,6 +224,7 @@ enum litest_device_type {
> LITEST_WACOM_CINTIQ_13HDT_PAD,
> LITEST_WACOM_CINTIQ_13HDT_FINGER,
> LITEST_WACOM_HID4800_PEN,
> + LITEST_MOUSE_WHEEL_CLICK_COUNT,
> };
>
> enum litest_device_feature {
> diff --git a/test/misc.c b/test/misc.c
> index 582d4fc..4afd4d0 100644
> --- a/test/misc.c
> +++ b/test/misc.c
> @@ -750,6 +750,35 @@ START_TEST(wheel_click_parser)
> }
> END_TEST
>
> +START_TEST(wheel_click_count_parser)
> +{
> + struct parser_test tests[] = {
> + { "1", 1 },
> + { "10", 10 },
> + { "-12", -12 },
> + { "360", 360 },
> + { "66 ", 66 },
> + { " 100 ", 100 },
> +
> + { "0", 0 },
> + { "-0", 0 },
> + { "a", 0 },
> + { "10a", 0 },
> + { "10-", 0 },
> + { "sadfasfd", 0 },
> + { "361", 0 },
> + { NULL, 0 }
> + };
> +
> + int i, angle;
> +
> + for (i = 0; tests[i].tag != NULL; i++) {
> + angle = parse_mouse_wheel_click_count_property(tests[i].tag);
> + ck_assert_int_eq(angle, tests[i].expected_value);
> + }
> +}
> +END_TEST
> +
> struct parser_test_float {
> char *tag;
> double expected_value;
> @@ -956,6 +985,7 @@ litest_setup_tests_misc(void)
> litest_add_no_device("misc:ratelimit", ratelimit_helpers);
> litest_add_no_device("misc:parser", dpi_parser);
> litest_add_no_device("misc:parser", wheel_click_parser);
> + litest_add_no_device("misc:parser", wheel_click_count_parser);
> litest_add_no_device("misc:parser", trackpoint_accel_parser);
> litest_add_no_device("misc:parser", dimension_prop_parser);
> litest_add_no_device("misc:time", time_conversion);
> diff --git a/test/pointer.c b/test/pointer.c
> index 175cb3b..4f33de5 100644
> --- a/test/pointer.c
> +++ b/test/pointer.c
> @@ -473,14 +473,45 @@ START_TEST(pointer_button_auto_release)
> }
> END_TEST
>
> -static inline int
> +static inline double
> +wheel_click_count(struct litest_device *dev, int which)
> +{
> + struct udev_device *d;
> + const char *prop = NULL;
> + int count;
> + double angle = 0.0;
> +
> + d = libinput_device_get_udev_device(dev->libinput_device);
> + litest_assert_ptr_notnull(d);
> +
> + if (which == REL_HWHEEL)
> + prop = udev_device_get_property_value(d, "MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL");
> + if(!prop)
> + prop = udev_device_get_property_value(d, "MOUSE_WHEEL_CLICK_COUNT");
> + if (!prop)
> + goto out;
> +
> + count = parse_mouse_wheel_click_count_property(prop);
> + angle = 360.0/count;
> +
> +out:
> + udev_device_unref(d);
> + return angle;
> +}
> +
> +static inline double
> wheel_click_angle(struct litest_device *dev, int which)
> {
> struct udev_device *d;
> const char *prop = NULL;
> const int default_angle = 15;
> - int angle = default_angle;
> + double angle;
>
> + angle = wheel_click_count(dev, which);
> + if (angle != 0.0)
> + return angle;
> +
> + angle = default_angle;
> d = libinput_device_get_udev_device(dev->libinput_device);
> litest_assert_ptr_notnull(d);
>
> @@ -492,7 +523,7 @@ wheel_click_angle(struct litest_device *dev, int which)
> goto out;
>
> angle = parse_mouse_wheel_click_angle_property(prop);
> - if (angle == 0)
> + if (angle == 0.0)
> angle = default_angle;
>
> out:
> @@ -508,7 +539,7 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
> struct libinput_event_pointer *ptrev;
> enum libinput_pointer_axis axis;
>
> - int scroll_step, expected, discrete;;
> + double scroll_step, expected, discrete;
>
> scroll_step = wheel_click_angle(dev, which);
> expected = amount * scroll_step;
> @@ -535,10 +566,12 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
> axis,
> LIBINPUT_POINTER_AXIS_SOURCE_WHEEL);
>
> - litest_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev, axis),
> - expected);
> - litest_assert_int_eq(libinput_event_pointer_get_axis_value_discrete(ptrev, axis),
> - discrete);
> + litest_assert_double_eq(
> + libinput_event_pointer_get_axis_value(ptrev, axis),
> + expected);
> + litest_assert_double_eq(
> + libinput_event_pointer_get_axis_value_discrete(ptrev, axis),
> + discrete);
> libinput_event_destroy(event);
> }
>
>
Regards,
Hans
More information about the wayland-devel
mailing list