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.hutte...@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; +} + 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; +} + +/** + * * 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); } -- 2.9.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel