diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox index fc1c0af8..87e92e6e 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.
The angle in degrees for each click on a mouse wheel. See libinput_pointer_get_axis_source() for details.
+
TOUCHPAD_RESOLUTION
+
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".
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 b7760c23..998249ff 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 49e297af..cd3b18dc 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=x + * 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 f76439f1..bd71a1ff 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 db26d67e..414d7cb3 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); }