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

Signed-off-by: Peter Hutterer <peter.hutte...@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

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to