[PATCH libinput 03/13] filter: duplicate pointer accel for touchpads

Peter Hutterer peter.hutterer at who-t.net
Mon Dec 19 05:20:54 UTC 2016


This duplicates the code so we can change it for touchpads without affecting
mice.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/filter.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 98 insertions(+), 5 deletions(-)

diff --git a/src/filter.c b/src/filter.c
index 06f07af..6f06ab9 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -117,6 +117,12 @@ filter_get_type(struct motion_filter *filter)
 #define DEFAULT_ACCELERATION 2.0		/* unitless factor */
 #define DEFAULT_INCLINE 1.1			/* unitless factor */
 
+/* Touchpad acceleration */
+#define TOUCHPAD_DEFAULT_THRESHOLD v_ms2us(0.4)
+#define TOUCHPAD_MINIMUM_THRESHOLD v_ms2us(0.2)
+#define TOUCHPAD_ACCELERATION 2.0		/* unitless factor */
+#define TOUCHPAD_INCLINE 1.1			/* unitless factor */
+
 /* for the Lenovo x230 custom accel. do not touch */
 #define X230_THRESHOLD v_ms2us(0.4)		/* in units/us */
 #define X230_ACCELERATION 2.0			/* unitless factor */
@@ -470,6 +476,34 @@ accelerator_filter_constant_x230(struct motion_filter *filter,
 	return normalized;
 }
 
+static bool
+touchpad_accelerator_set_speed(struct motion_filter *filter,
+		      double speed_adjustment)
+{
+	struct pointer_accelerator *accel_filter =
+		(struct pointer_accelerator *)filter;
+
+	assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
+
+	/* Note: the numbers below are nothing but trial-and-error magic,
+	   don't read more into them other than "they mostly worked ok" */
+
+	/* delay when accel kicks in */
+	accel_filter->threshold = TOUCHPAD_DEFAULT_THRESHOLD -
+					v_ms2us(0.25) * speed_adjustment;
+	if (accel_filter->threshold < TOUCHPAD_MINIMUM_THRESHOLD)
+		accel_filter->threshold = TOUCHPAD_MINIMUM_THRESHOLD;
+
+	/* adjust max accel factor */
+	accel_filter->accel = TOUCHPAD_ACCELERATION + speed_adjustment * 1.5;
+
+	/* higher speed -> faster to reach max */
+	accel_filter->incline = TOUCHPAD_INCLINE + speed_adjustment * 0.75;
+
+	filter->speed_adjustment = speed_adjustment;
+	return true;
+}
+
 static struct normalized_coords
 touchpad_constant_filter(struct motion_filter *filter,
 			 const struct normalized_coords *unaccelerated,
@@ -662,15 +696,74 @@ pointer_accel_profile_linear(struct motion_filter *filter,
 
 double
 touchpad_accel_profile_linear(struct motion_filter *filter,
-                              void *data,
-                              double speed_in, /* units/us */
-                              uint64_t time)
+			      void *data,
+			      double speed_in, /* 1000-dpi normalized */
+			      uint64_t time)
 {
+	struct pointer_accelerator *accel_filter =
+		(struct pointer_accelerator *)filter;
+	const double max_accel = accel_filter->accel; /* unitless factor */
+	const double threshold = accel_filter->threshold; /* units/us */
+	const double incline = accel_filter->incline;
 	double factor; /* unitless */
 
 	speed_in *= TP_MAGIC_SLOWDOWN;
 
-	factor = pointer_accel_profile_linear(filter, data, speed_in, time);
+	/*
+	   Our acceleration function calculates a factor to accelerate input
+	   deltas with. The function is a double incline with a plateau,
+	   with a rough shape like this:
+
+	  accel
+	 factor
+	   ^
+	   |        /
+	   |  _____/
+	   | /
+	   |/
+	   +-------------> speed in
+
+	   The two inclines are linear functions in the form
+		   y = ax + b
+		   where y is speed_out
+		         x is speed_in
+			 a is the incline of acceleration
+			 b is minimum acceleration factor
+
+	   for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
+	   speed.
+		   hence 1 = a * 0.07 + 0.3
+		       0.3 = a * 0.07  => a := 10
+		   deceleration function is thus:
+			y = 10x + 0.3
+
+	  Note:
+	  * 0.07u/ms as threshold is a result of trial-and-error and
+	    has no other intrinsic meaning.
+	  * 0.3 is chosen simply because it is above the Nyquist frequency
+	    for subpixel motion within a pixel.
+	*/
+	if (v_us2ms(speed_in) < 0.07) {
+		factor = 10 * v_us2ms(speed_in) + 0.3;
+	/* up to the threshold, we keep factor 1, i.e. 1:1 movement */
+	} else if (speed_in < threshold) {
+		factor = 1;
+	} else {
+	/* Acceleration function above the threshold:
+		y = ax' + b
+		where T is threshold
+		      x is speed_in
+		      x' is speed
+	        and
+			y(T) == 1
+		hence 1 = ax' + 1
+			=> x' := (x - T)
+	 */
+		factor = incline * v_us2ms(speed_in - threshold) + 1;
+	}
+
+	/* Cap at the maximum acceleration factor */
+	factor = min(max_accel, factor);
 
 	return factor * TP_MAGIC_SLOWDOWN;
 }
@@ -823,7 +916,7 @@ struct motion_filter_interface accelerator_interface_touchpad = {
 	.filter_constant = touchpad_constant_filter,
 	.restart = accelerator_restart,
 	.destroy = accelerator_destroy,
-	.set_speed = accelerator_set_speed,
+	.set_speed = touchpad_accelerator_set_speed,
 };
 
 struct motion_filter *
-- 
2.9.3



More information about the wayland-devel mailing list