Parse the MOUSE_WHEEL_CLICK_ANGLE udev property if present
authorPeter Hutterer <peter.hutterer@who-t.net>
Sun, 11 Jan 2015 22:39:47 +0000 (08:39 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Tue, 13 Jan 2015 03:35:42 +0000 (13:35 +1000)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com>
doc/device-configuration-via-udev.dox
src/evdev.c
src/evdev.h
src/libinput-util.c
src/libinput-util.h
test/misc.c

index b8540351e99e1ed1a35e910e8ec2cf50c6e45536..bee3659801b685d8c28ba96669e2482ea68936f3 100644 (file)
@@ -23,6 +23,10 @@ context. Defaults to "default".</dd>
 <dd>HW resolution and sampling frequency of a relative pointer device.
 See @ref motion_normalization for details.
 </dd>
+<dt>MOUSE_WHEEL_CLICK_ANGLE</dt>
+<dd>The angle in degrees for each click on a mouse wheel. See
+libinput_pointer_get_axis_source() for details.
+</dd>
 </dl>
 
 Below is an example udev rule to assign "seat1" to a device from vendor
index d8b61299e40735d75cac2883237d8d6b595675e0..d80594dffff6344f3809ec481285600735ebec96 100644 (file)
@@ -577,7 +577,7 @@ evdev_process_relative(struct evdev_device *device,
                        time,
                        LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
                        LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
-                       -1 * e->value * DEFAULT_WHEEL_CLICK_ANGLE);
+                       -1 * e->value * device->scroll.wheel_click_angle);
                break;
        case REL_HWHEEL:
                evdev_flush_pending_event(device, time);
@@ -586,7 +586,7 @@ evdev_process_relative(struct evdev_device *device,
                        time,
                        LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
                        LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
-                       e->value * DEFAULT_WHEEL_CLICK_ANGLE);
+                       e->value * device->scroll.wheel_click_angle);
                break;
        }
 }
@@ -1239,6 +1239,29 @@ evdev_tag_device(struct evdev_device *device)
                                                        device->udev_device);
 }
 
+static inline int
+evdev_read_wheel_click_prop(struct evdev_device *device)
+{
+       struct libinput *libinput = device->base.seat->libinput;
+       const char *prop;
+       int angle = DEFAULT_WHEEL_CLICK_ANGLE;
+
+       prop = udev_device_get_property_value(device->udev_device,
+                                             "MOUSE_WHEEL_CLICK_ANGLE");
+       if (prop) {
+               angle = parse_mouse_wheel_click_angle_property(prop);
+               if (!angle) {
+                       log_error(libinput,
+                                 "Mouse wheel click angle '%s' is present but invalid,"
+                                 "using %d degrees instead\n",
+                                 device->devname,
+                                 DEFAULT_WHEEL_CLICK_ANGLE);
+                       angle = DEFAULT_WHEEL_CLICK_ANGLE;
+               }
+       }
+
+       return angle;
+}
 static inline int
 evdev_read_dpi_prop(struct evdev_device *device)
 {
@@ -1568,6 +1591,8 @@ evdev_device_create(struct libinput_seat *seat,
        device->devname = libevdev_get_name(device->evdev);
        device->scroll.threshold = 5.0; /* Default may be overridden */
        device->scroll.direction = 0;
+       device->scroll.wheel_click_angle =
+               evdev_read_wheel_click_prop(device);
        device->dpi = evdev_read_dpi_prop(device);
        /* at most 5 SYN_DROPPED log-messages per 30s */
        ratelimit_init(&device->syn_drop_limit, 30ULL * 1000, 5);
index a75dd134f8de475c3abb16ee3178d742a04068fc..2171c5adf2a31e25429f35f7b4206a0639e74c4a 100644 (file)
@@ -119,6 +119,9 @@ struct evdev_device {
                /* set during device init if we want natural scrolling,
                 * used at runtime to enable/disable the feature */
                bool natural_scrolling_enabled;
+
+               /* angle per REL_WHEEL click in degrees */
+               int wheel_click_angle;
        } scroll;
 
        enum evdev_event_type pending_event;
index c16de1bf164244a0ecbf085ec5983c4d30466fee..49e297af48ae94d6f1ef7af114206905a32f514b 100644 (file)
@@ -171,3 +171,33 @@ parse_mouse_dpi_property(const char *prop)
        }
        return dpi;
 }
+
+/**
+ * Helper function to parse the MOUSE_WHEEL_CLICK_ANGLE property from udev.
+ * Property is of the form:
+ * MOUSE_WHEEL_CLICK_ANGLE=<integer>
+ * Where the number indicates the degrees travelled for each click.
+ *
+ * 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_ANGLE=)
+ * @return The angle of the wheel (may be negative) or 0 on error.
+ */
+int
+parse_mouse_wheel_click_angle_property(const char *prop)
+{
+       int angle = 0,
+           nread = 0;
+
+       while(*prop != 0 && *prop == ' ')
+               prop++;
+
+       sscanf(prop, "%d%n", &angle, &nread);
+       if (nread == 0 || angle == 0 || abs(angle) > 360)
+               return 0;
+       if (prop[nread] != ' ' && prop[nread] != '\0')
+               return 0;
+
+        return angle;
+}
index 68258414bca7ea7e630801d83519930e5f457ef1..dc70bcd2c5bcadfded9c275e5d8fbf304815079c 100644 (file)
@@ -297,5 +297,6 @@ void ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst);
 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);
 
 #endif /* LIBINPUT_UTIL_H */
index c7d9ddf526e909932bee09b6bf763d96731481d7..779b600fa21bc65e93a44f47b5fa720a5292d2d4 100644 (file)
@@ -531,7 +531,7 @@ END_TEST
 
 struct parser_test {
        char *tag;
-       int expected_dpi;
+       int expected_value;
 };
 
 START_TEST(dpi_parser)
@@ -565,7 +565,36 @@ START_TEST(dpi_parser)
 
        for (i = 0; tests[i].tag != NULL; i++) {
                dpi = parse_mouse_dpi_property(tests[i].tag);
-               ck_assert_int_eq(dpi, tests[i].expected_dpi);
+               ck_assert_int_eq(dpi, tests[i].expected_value);
+       }
+}
+END_TEST
+
+START_TEST(wheel_click_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_angle_property(tests[i].tag);
+               ck_assert_int_eq(angle, tests[i].expected_value);
        }
 }
 END_TEST
@@ -582,6 +611,7 @@ int main (int argc, char **argv) {
        litest_add_no_device("misc:matrix", matrix_helpers);
        litest_add_no_device("misc:ratelimit", ratelimit_helpers);
        litest_add_no_device("misc:dpi parser", dpi_parser);
+       litest_add_no_device("misc:wheel click parser", wheel_click_parser);
 
        return litest_run(argc, argv);
 }