[PATCH libinput v4 1/2] evdev: use a different filter for low resolution touchpad on the Lenovo X230

Benjamin Tissoires benjamin.tissoires at gmail.com
Mon Apr 20 11:29:44 PDT 2015


Those touchpads presents an actual lower resolution that what is
advertised.

We see some jumps from the cursor due to the big steps in X and Y
when we are receiving data.

For instance, we receive:

E: 13.471932 0003 0000 16366	# EV_ABS / ABS_X                16366
E: 13.471932 0003 0001 9591	# EV_ABS / ABS_Y                9591
E: 13.471932 0000 0000 0000	# ------------ SYN_REPORT (0) ----------
E: 13.479924 0003 0000 16316	# EV_ABS / ABS_X                16316
E: 13.479924 0003 0001 9491	# EV_ABS / ABS_Y                9491
E: 13.479924 0000 0000 0000	# ------------ SYN_REPORT (0) ----------
E: 13.487939 0003 0000 16271	# EV_ABS / ABS_X                16271
E: 13.487939 0003 0001 9403	# EV_ABS / ABS_Y                9403
E: 13.487939 0000 0000 0000	# ------------ SYN_REPORT (0) ----------

-> jumps of ~50 in X in each report, and ~100 for Y.

Use a three segments acceleration profile to sort this out:
- slow down a lot when speed is below 0.8 + threshold
- use a somewhat half acceleration when speed is in
  ]0.8 + threshold .. 2.0]
- use the same acceleration than regular touchpads if the speed is
  greater than 2.0

Signed-off-by: Benjamin Tissoires <benjamin.tissoires at gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---

Change in v4:
- dropped the generic linear pointer acceleration
- use our own 3 segments acceleration profile

 doc/device-configuration-via-udev.dox |    9 +++++++
 src/evdev-mt-touchpad.c               |   14 +++++++++--
 src/evdev.c                           |   23 +++++++++++++++++++
 src/evdev.h                           |    7 +++++
 src/filter.c                          |   40 +++++++++++++++++++++++++++++++++
 src/filter.h                          |    5 ++++
 6 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox
index fc1c0af..c570913 100644
--- a/doc/device-configuration-via-udev.dox
+++ b/doc/device-configuration-via-udev.dox
@@ -57,6 +57,15 @@ 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>LIBINPUT_MODEL_LENOVO_X230</dt>
+<dd><b>Do not use for anything except a Lenovo X230 series</b> (you have been
+warned).
+This flag allows libinput to apply a different acceleration profile for the
+touchpads of this series of laptops to counter a hardware deficiency. It may
+also be use to tune other parts of the inputs of these laptops, so the effects
+of this property may change anytime and will be only tested against the
+mentioned laptop series.
+</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 cccf033..d5ce880 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -998,6 +998,7 @@ static int
 tp_init_accel(struct tp_dispatch *tp, double diagonal)
 {
 	int res_x, res_y;
+	accel_profile_func_t profile;
 
 	res_x = tp->device->abs.absinfo_x->resolution;
 	res_y = tp->device->abs.absinfo_y->resolution;
@@ -1021,9 +1022,16 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
 		tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
 	}
 
-	if (evdev_device_init_pointer_acceleration(
-                                       tp->device,
-                                       touchpad_accel_profile_linear) == -1)
+	switch (tp->device->model) {
+	case EVDEV_MODEL_LENOVO_X230:
+		profile = touchpad_lenovo_x230_accel_profile;
+		break;
+	default:
+		profile = touchpad_accel_profile_linear;
+		break;
+	}
+
+	if (evdev_device_init_pointer_acceleration(tp->device, profile) == -1)
 		return -1;
 
 	return 0;
diff --git a/src/evdev.c b/src/evdev.c
index da33eae..7743c06 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1389,6 +1389,28 @@ evdev_read_dpi_prop(struct evdev_device *device)
 	return dpi;
 }
 
+static inline enum evdev_device_model
+evdev_read_model(struct evdev_device *device)
+{
+	const struct model_map {
+		const char *property;
+		enum evdev_device_model model;
+	} model_map[] = {
+		{ "LIBINPUT_MODEL_LENOVO_X230", EVDEV_MODEL_LENOVO_X230 },
+		{ NULL, EVDEV_MODEL_DEFAULT },
+	};
+	const struct model_map *m = model_map;
+
+	while (m->property) {
+		if (!!udev_device_get_property_value(device->udev_device,
+						     m->property))
+			break;
+		m++;
+	}
+
+	return m->model;
+}
+
 /* Return 1 if the given resolutions have been set, or 0 otherwise */
 inline int
 evdev_fix_abs_resolution(struct evdev_device *device,
@@ -1901,6 +1923,7 @@ evdev_device_create(struct libinput_seat *seat,
 	device->scroll.wheel_click_angle =
 		evdev_read_wheel_click_prop(device);
 	device->dpi = evdev_read_dpi_prop(device);
+	device->model = evdev_read_model(device);
 	/* at most 5 SYN_DROPPED log-messages per 30s */
 	ratelimit_init(&device->syn_drop_limit, 30ULL * 1000, 5);
 
diff --git a/src/evdev.h b/src/evdev.h
index 9b1dcc3..803f34d 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -86,6 +86,11 @@ enum evdev_middlebutton_event {
 	MIDDLEBUTTON_EVENT_ALL_UP,
 };
 
+enum evdev_device_model {
+	EVDEV_MODEL_DEFAULT,
+	EVDEV_MODEL_LENOVO_X230,
+};
+
 struct mt_slot {
 	int32_t seat_slot;
 	struct device_coords point;
@@ -195,6 +200,8 @@ struct evdev_device {
 
 	int dpi; /* HW resolution */
 	struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
+
+	enum evdev_device_model model;
 };
 
 #define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
diff --git a/src/filter.c b/src/filter.c
index 962d74d..5994571 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -345,3 +345,43 @@ touchpad_accel_profile_linear(struct motion_filter *filter,
 
 	return speed_out * TP_MAGIC_SLOWDOWN;
 }
+
+double
+touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
+				      void *data,
+				      double speed_in,
+				      uint64_t time)
+{
+	/* Those touchpads presents an actual lower resolution that what is
+	 * advertised. We see some jumps from the cursor due to the big steps
+	 * in X and Y when we are receiving data.
+	 * Use a three segments acceleration profile to sort this out:
+	 * - slow down a lot when speed is below 0.8 + threshold
+	 * - use a somewhat half acceleration when speed is in ]0.8 + threshold .. 2.0]
+	 * - use the same acceleration than regular touchpads if the speed is
+	 *   greater than 2.0
+	 */
+	double speed_out;
+	struct pointer_accelerator *accel_filter =
+		(struct pointer_accelerator *)filter;
+
+	double s1, s2, s3;
+	const double max_accel = accel_filter->accel * 0.4; /* unitless factor, same for regular touchpads */
+	const double threshold = accel_filter->threshold;
+	const double incline = accel_filter->incline;
+
+	s1 = speed_in * 0.05;
+	s2 = 0.1 + (speed_in - threshold * 0.5) * incline * 0.10;
+	s3 = 0.37 + (speed_in - threshold * 2.0) * incline * 0.16;
+
+	if (speed_in <= 0.8 + threshold)
+		speed_out = s1;
+	else if (speed_in <= 2)
+		speed_out = s2;
+	else
+		speed_out = s3;
+
+	speed_out = min(max_accel, speed_out);
+
+	return speed_out;
+}
diff --git a/src/filter.h b/src/filter.h
index 70363a6..a053860 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -67,4 +67,9 @@ touchpad_accel_profile_linear(struct motion_filter *filter,
 			      void *data,
 			      double speed_in,
 			      uint64_t time);
+double
+touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
+				      void *data,
+				      double speed_in,
+				      uint64_t time);
 #endif /* FILTER_H */
-- 
1.7.1



More information about the wayland-devel mailing list