evdev: Add support for POINTINGSTICK_CONST_ACCEL udev property
authorHans de Goede <hdegoede@redhat.com>
Wed, 1 Apr 2015 09:03:19 +0000 (11:03 +0200)
committerHans de Goede <hdegoede@redhat.com>
Wed, 22 Apr 2015 07:35:28 +0000 (09:35 +0200)
There is quite a wide spread in the delta events generated by trackpoints,
some generate deltas of 1-2 under normal use, while others generate deltas
from 1-20.

It is desirable to normalize trackpoint deltas just like we are normalizing
mouse deltas to 1000 dpi, so as to give different model laptops aprox.
the same trackpoint cursor speed ootb.

Recent versions of udev + hwdb set a POINTINGSTICK_CONST_ACCEL udev property
which can be used to adjust trackpoints which are too slow / too fast
ootb, this commit implements support for that property.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
doc/device-configuration-via-udev.dox
src/evdev.c
src/evdev.h
src/libinput-util.c
src/libinput-util.h
test/misc.c

index c319c409d3d9d822faca5dfcc094f3c064b78f08..c22aafab9aea8aee30eea85b0479bbd310ea48dd 100644 (file)
@@ -60,6 +60,10 @@ See @ref motion_normalization for details.
 <dd>The angle in degrees for each click on a mouse wheel. See
 libinput_pointer_get_axis_source() for details.
 </dd>
+<dt>POINTINGSTICK_CONST_ACCEL</dt>
+<dd>A constant (linear) acceleration factor to apply to pointingstick deltas
+to normalize them.
+</dd>
 </dl>
 
 Below is an example udev rule to assign "seat1" to a device from vendor
index 1a7282d8cda5498f404c30c153847ff01977365b..8774a990da4b9559829891b5151159562b66da74 100644 (file)
@@ -1365,6 +1365,31 @@ evdev_read_wheel_click_prop(struct evdev_device *device)
 
        return angle;
 }
+
+static inline int
+evdev_get_trackpoint_dpi(struct evdev_device *device)
+{
+       struct libinput *libinput = device->base.seat->libinput;
+       const char *trackpoint_accel;
+       double accel = DEFAULT_TRACKPOINT_ACCEL;
+
+       trackpoint_accel = udev_device_get_property_value(
+                               device->udev_device, "POINTINGSTICK_CONST_ACCEL");
+       if (trackpoint_accel) {
+               accel = parse_trackpoint_accel_property(trackpoint_accel);
+               if (accel == 0.0) {
+                       log_error(libinput, "Trackpoint accel property for "
+                                           "'%s' is present but invalid, "
+                                           "using %.2f instead\n",
+                                           device->devname,
+                                           DEFAULT_TRACKPOINT_ACCEL);
+                       accel = DEFAULT_TRACKPOINT_ACCEL;
+               }
+       }
+
+       return DEFAULT_MOUSE_DPI / accel;
+}
+
 static inline int
 evdev_read_dpi_prop(struct evdev_device *device)
 {
@@ -1372,6 +1397,14 @@ evdev_read_dpi_prop(struct evdev_device *device)
        const char *mouse_dpi;
        int dpi = DEFAULT_MOUSE_DPI;
 
+       /*
+        * Trackpoints do not have dpi, instead hwdb may contain a
+        * POINTINGSTICK_CONST_ACCEL value to compensate for sensitivity
+        * differences between models, we translate this to a fake dpi.
+        */
+       if (libevdev_has_property(device->evdev, INPUT_PROP_POINTING_STICK))
+               return evdev_get_trackpoint_dpi(device);
+
        mouse_dpi = udev_device_get_property_value(device->udev_device,
                                                   "MOUSE_DPI");
        if (mouse_dpi) {
index 9b1dcc36a08ff5d2244e3fcc22fa0fe9beca2670..9969d5158f68f4efa9cc15f5a3142db87e442470 100644 (file)
 
 /* The HW DPI rate we normalize to before calculating pointer acceleration */
 #define DEFAULT_MOUSE_DPI 1000
+
+/*
+ * The constant (linear) acceleration factor we use to normalize trackpoint
+ * deltas before calculating pointer acceleration.
+ */
+#define DEFAULT_TRACKPOINT_ACCEL 1.0
+
 /* The fake resolution value for abs devices without resolution */
 #define EVDEV_FAKE_RESOLUTION 1
 
index 49e297af48ae94d6f1ef7af114206905a32f514b..4857435bf4b7ccb5d48026ecfb1397a51e2629cf 100644 (file)
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <ctype.h>
+#include <locale.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -201,3 +202,33 @@ parse_mouse_wheel_click_angle_property(const char *prop)
 
         return angle;
 }
+
+/**
+ * Helper function to parse the TRACKPOINT_CONST_ACCEL property from udev.
+ * Property is of the form:
+ * TRACKPOINT_CONST_ACCEL=<float>
+ *
+ * @param prop The value of the udev property (without the TRACKPOINT_CONST_ACCEL=)
+ * @return The acceleration, or 0.0 on error.
+ */
+double
+parse_trackpoint_accel_property(const char *prop)
+{
+       locale_t c_locale;
+       double accel;
+       char *endp;
+
+       /* Create a "C" locale to force strtod to use '.' as separator */
+       c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
+       if (c_locale == (locale_t)0)
+               return 0.0;
+
+       accel = strtod_l(prop, &endp, c_locale);
+
+       freelocale(c_locale);
+
+       if (*endp != '\0')
+               return 0.0;
+
+       return accel;
+}
index 30f59ecfdbf8e69524639c31b3d6452bd3de42b9..74226b962cfcebfd265e78de0cff44aadaf5140c 100644 (file)
@@ -242,5 +242,6 @@ 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);
+double parse_trackpoint_accel_property(const char *prop);
 
 #endif /* LIBINPUT_UTIL_H */
index db26d67e8168f141573f009d6f52ec280b503c6e..829da7d3a338700810f29b931b46bc9d5ca6a364 100644 (file)
@@ -557,6 +557,32 @@ START_TEST(wheel_click_parser)
 }
 END_TEST
 
+struct parser_test_float {
+       char *tag;
+       double expected_value;
+};
+
+START_TEST(trackpoint_accel_parser)
+{
+       struct parser_test_float tests[] = {
+               { "0.5", 0.5 },
+               { "1.0", 1.0 },
+               { "2.0", 2.0 },
+               { "fail1.0", 0.0 },
+               { "1.0fail", 0.0 },
+               { "0,5", 0.0 },
+               { NULL, 0.0 }
+       };
+       int i;
+       double accel;
+
+       for (i = 0; tests[i].tag != NULL; i++) {
+               accel = parse_trackpoint_accel_property(tests[i].tag);
+               ck_assert(accel == tests[i].expected_value);
+       }
+}
+END_TEST
+
 int main (int argc, char **argv) {
        litest_add_no_device("events:conversion", event_conversion_device_notify);
        litest_add_for_device("events:conversion", event_conversion_pointer, LITEST_MOUSE);
@@ -572,6 +598,7 @@ int main (int argc, char **argv) {
        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);
+       litest_add_no_device("misc:trackpoint accel parser", trackpoint_accel_parser);
 
        return litest_run(argc, argv);
 }