[PATCH libinput v5] evdev: use a different filter for low resolution touchpad on the Lenovo X230

Benjamin Tissoires benjamin.tissoires at gmail.com
Thu Apr 23 11:32:40 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.

Apply a factor to minimize those jumps at low speed, and try
keeping the same feeling as regular touchpads at high speed.
It still feels slower but it is usable at least

Signed-off-by: Benjamin Tissoires <benjamin.tissoires at gmail.com>
---

Hi,

So this will hopefully be validated and pulled upstream.
This patch needs the one Peter sent out yesterday (evdev: add support for
LIBINPUT_MODEL_* udev tags). It is thus much smaller given that the generic
bits are in the other patch.

The final choice for the acceleration profile is the one I sent in the v1 of
the series. A nice drawing of the acceleration profile is available here:
http://people.freedesktop.org/~tissoire/x230-v5.png

If anybody wants to polish it, I am all for it.

Some special notes if you want to use the patch without rebooting:
- do not forget to update the hwdb (sudo udevadm hwdb --update)
- reload the udev rules (sudo udevadm control --reload)
- and trigger the input nodes (sudo udevadm trigger /dev/input/event*)
- the udev database should still show LIBINPUT_MODEL_LENOVO_X230 attached to the
  touchpad node (udevadm info --export-db | less)

Then kill X (or restart gdm), and you are good.

Cheers,
Benjamin

 src/evdev-mt-touchpad.c            |   14 ++++++++++--
 src/evdev.c                        |    1 +
 src/evdev.h                        |    1 +
 src/filter.c                       |   37 ++++++++++++++++++++++++++++++++++++
 src/filter.h                       |    5 ++++
 udev/90-libinput-model-quirks.hwdb |    8 +++++++
 6 files changed, 63 insertions(+), 3 deletions(-)

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 e3bba93..6a9df49 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1429,6 +1429,7 @@ evdev_read_model(struct evdev_device *device)
 		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;
diff --git a/src/evdev.h b/src/evdev.h
index edd4011..151d103 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -95,6 +95,7 @@ enum evdev_middlebutton_event {
 
 enum evdev_device_model {
 	EVDEV_MODEL_DEFAULT,
+	EVDEV_MODEL_LENOVO_X230,
 };
 
 struct mt_slot {
diff --git a/src/filter.c b/src/filter.c
index 962d74d..b953bee 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -345,3 +345,40 @@ 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)
+{
+	/* Keep the magic factor from touchpad_accel_profile_linear.  */
+	const double TP_MAGIC_SLOWDOWN = 0.4;
+
+	/* 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.
+	 * Apply a factor to minimize those jumps at low speed, and try
+	 * keeping the same feeling as regular touchpads at high speed.
+	 * It still feels slower but it is usable at least */
+	const double TP_MAGIC_LOW_RES_FACTOR = 4.0;
+	double speed_out;
+	struct pointer_accelerator *accel_filter =
+		(struct pointer_accelerator *)filter;
+
+	double s1, s2;
+	const double max_accel = accel_filter->accel *
+				  TP_MAGIC_LOW_RES_FACTOR; /* unitless factor */
+	const double threshold = accel_filter->threshold /
+				  TP_MAGIC_LOW_RES_FACTOR; /* units/ms */
+	const double incline = accel_filter->incline * TP_MAGIC_LOW_RES_FACTOR;
+
+	speed_in *= TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
+
+	s1 = min(1, speed_in * 5);
+	s2 = 1 + (speed_in - threshold) * incline;
+
+	speed_out = min(max_accel, s2 > 1 ? s2 : s1);
+
+	return speed_out * TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
+}
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 */
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index 02bb8f9..959be0f 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -14,3 +14,11 @@
 
 #
 # Sort by brand, model
+
+##########################################
+# LENOVO
+##########################################
+
+# X230 (Tablet)
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX230*
+ LIBINPUT_MODEL_LENOVO_X230=1
-- 
1.7.1



More information about the wayland-devel mailing list