[PATCH libinput 8/9] touchpad: parse the TOUCHPAD_RESOLUTION property
Peter Hutterer
peter.hutterer at who-t.net
Mon Mar 16 22:34:32 PDT 2015
Not all touchpad kernel drivers supply the x/y resolution. Let the udev hwdb
fix this up where possible and read the value from it.
This is intentionally only used on touchpads, touchscreen devices without
resolution should be considered buggy and fixed in the kernel.
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Specifically for the Apple laptops this should be a fairly straightforward
addition to the udev hwdb. Elantech and ALPS will take a bit longer and
require DMI matching but AFAICT they are working well-enough with the
current settings.
doc/device-configuration-via-udev.dox | 5 ++++
src/evdev-mt-touchpad.c | 28 ++++++++++++++++++++
src/libinput-util.c | 30 +++++++++++++++++++++
src/libinput-util.h | 3 +++
test/misc.c | 49 +++++++++++++++++++++++++++++++++++
5 files changed, 115 insertions(+)
diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox
index fc1c0af..87e92e6 100644
--- a/doc/device-configuration-via-udev.dox
+++ b/doc/device-configuration-via-udev.dox
@@ -57,6 +57,11 @@ 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>TOUCHPAD_RESOLUTION</dt>
+<dd>The x and y resolution in units/mm for a touchpad. This value is only
+used if the touchpad kernel driver does not supply a valid resolution. It
+is only used on touchpad devices. The format is two unsigned integer values
+separated by a literal 'x', e.g. "42x129".</dd>
</dl>
Below is an example udev rule to assign "seat1" to a device from vendor
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index b7760c2..998249f 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -1117,6 +1117,32 @@ tp_init_sendevents(struct tp_dispatch *tp,
return 0;
}
+static void
+tp_fix_resolution(struct tp_dispatch *tp, struct evdev_device *device)
+{
+ struct libinput *libinput = device->base.seat->libinput;
+ const char *prop;
+ unsigned int resx, resy;
+
+ prop = udev_device_get_property_value(device->udev_device,
+ "TOUCHPAD_RESOLUTION");
+ if (!prop)
+ return;
+
+ if (parse_touchpad_resolution_property(prop, &resx, &resy) == -1) {
+ log_error(libinput,
+ "Touchpad resolution property set for '%s', but invalid.\n",
+ device->devname);
+ return;
+ }
+
+ if (evdev_fix_abs_resolution(device,
+ tp->has_mt ? ABS_MT_POSITION_X : ABS_X,
+ tp->has_mt ? ABS_MT_POSITION_Y : ABS_Y,
+ resx, resy))
+ device->abs.fake_resolution = 0;
+}
+
static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
@@ -1130,6 +1156,8 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_slots(tp, device) != 0)
return -1;
+ tp_fix_resolution(tp, device);
+
width = abs(device->abs.absinfo_x->maximum -
device->abs.absinfo_x->minimum);
height = abs(device->abs.absinfo_y->maximum -
diff --git a/src/libinput-util.c b/src/libinput-util.c
index 49e297a..cd3b18d 100644
--- a/src/libinput-util.c
+++ b/src/libinput-util.c
@@ -201,3 +201,33 @@ parse_mouse_wheel_click_angle_property(const char *prop)
return angle;
}
+
+/**
+ * Helper function to parse the TOUCHPAD_RESOLUTION property from udev.
+ * Property is of the form
+ * TOUCHPAD_RESOLUTION=<integer>x<integer>
+ * With both integer values in device units per mm.
+ * @param prop The value of the udev property (without the
+ * TOUCHPAD_RESOLUTION=)
+ * @return
+ */
+int
+parse_touchpad_resolution_property(const char *prop,
+ unsigned int *res_x,
+ unsigned int *res_y)
+{
+ int nconverted = 0;
+ unsigned int rx, ry;
+ nconverted = sscanf(prop, "%ux%u", &rx, &ry);
+ if (nconverted != 2 || rx == 0 || ry == 0)
+ return -1;
+
+ if (rx > 1000 || ry > 1000 || /* yeah, right... */
+ rx < 10 || ry < 10) /* what is this? the 90s? */
+ return -1;
+
+ *res_x = rx;
+ *res_y = ry;
+
+ return 0;
+}
diff --git a/src/libinput-util.h b/src/libinput-util.h
index f76439f..bd71a1f 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -299,5 +299,8 @@ 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_touchpad_resolution_property(const char *prop,
+ unsigned int *res_x,
+ unsigned int *res_y);
#endif /* LIBINPUT_UTIL_H */
diff --git a/test/misc.c b/test/misc.c
index db26d67..414d7cb 100644
--- a/test/misc.c
+++ b/test/misc.c
@@ -557,6 +557,54 @@ START_TEST(wheel_click_parser)
}
END_TEST
+struct res_parser_test {
+ const char *value;
+ int retvalue;
+ int rx, ry;
+};
+
+START_TEST(touchpad_resolution_parser)
+{
+ struct res_parser_test tests[] = {
+ { "43x85", 0, 43, 85},
+ { "242x428", 0, 242, 428 },
+ { "1x1", -1, 0, 0},
+ { "abcd", -1, 0, 0},
+ { "", -1, 0, 0 },
+ { "x", -1, 0, 0 },
+ { "23x", -1, 0, 0 },
+ { "x58", -1, 0, 0 },
+ { "1x1", -1, 0, 0 },
+ { "9x9", -1, 0, 0 },
+ { "-34x-19", -1, 0, 0 },
+ { "-34x19", -1, 0, 0 },
+ { "34x-19", -1, 0, 0 },
+ { NULL, 0, 0, 0 }
+
+ };
+
+ struct res_parser_test *test = tests;
+ int rc;
+ unsigned int rx, ry;
+
+ while (test->value != NULL) {
+ rx = 0xab;
+ ry = 0xcd;
+ rc = parse_touchpad_resolution_property(test->value, &rx, &ry);
+ ck_assert_int_eq(rc, test->retvalue);
+ if (rc == 0) {
+ ck_assert_int_eq(rx, test->rx);
+ ck_assert_int_eq(ry, test->ry);
+ } else {
+ ck_assert_int_eq(rx, 0xab);
+ ck_assert_int_eq(ry, 0xcd);
+ }
+
+ test++;
+ }
+}
+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 +620,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:touchpad resolution parser", touchpad_resolution_parser);
return litest_run(argc, argv);
}
--
2.3.2
More information about the wayland-devel
mailing list