filter: split the low-dpi acceleration into a separate file
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 11 Apr 2018 01:05:12 +0000 (11:05 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 18 Apr 2018 06:24:52 +0000 (16:24 +1000)
Plenty of duplication there from the normal filter.c, but that also makes it
less likely to break if we adjust the other one.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
meson.build
src/filter-low-dpi.c [new file with mode: 0644]
src/filter.c

index 33bc7c0..14dddd4 100644 (file)
@@ -152,6 +152,7 @@ dep_libinput_util = declare_dependency(link_with : libinput_util)
 src_libfilter = [
                'src/filter.c',
                'src/filter-flat.c',
+               'src/filter-low-dpi.c',
                'src/filter-touchpad.c',
                'src/filter-touchpad-x230.c',
                'src/filter-tablet.c',
diff --git a/src/filter-low-dpi.c b/src/filter-low-dpi.c
new file mode 100644 (file)
index 0000000..f22929a
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright © 2006-2009 Simon Thum
+ * Copyright © 2012 Jonas Ådahl
+ * Copyright © 2014-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+
+#include "filter.h"
+#include "libinput-util.h"
+#include "filter-private.h"
+
+/*
+ * Default parameters for pointer acceleration profiles.
+ */
+
+#define DEFAULT_THRESHOLD v_ms2us(0.4)         /* in units/us */
+#define MINIMUM_THRESHOLD v_ms2us(0.2)         /* in units/us */
+#define DEFAULT_ACCELERATION 2.0               /* unitless factor */
+#define DEFAULT_INCLINE 1.1                    /* unitless factor */
+
+#define NUM_POINTER_TRACKERS   16
+/**
+ * Custom acceleration function for mice < 1000dpi.
+ * At slow motion, a single device unit causes a one-pixel movement.
+ * The threshold/max accel depends on the DPI, the smaller the DPI the
+ * earlier we accelerate and the higher the maximum acceleration is. Result:
+ * at low speeds we get pixel-precision, at high speeds we get approx. the
+ * same movement as a high-dpi mouse.
+ *
+ * Note: data fed to this function is in device units, not normalized.
+ */
+double
+pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
+                                    void *data,
+                                    double speed_in, /* in device units (units/us) */
+                                    uint64_t time)
+{
+       struct pointer_accelerator *accel_filter =
+               (struct pointer_accelerator *)filter;
+
+       double max_accel = accel_filter->accel; /* unitless factor */
+       double threshold = accel_filter->threshold; /* units/us */
+       const double incline = accel_filter->incline;
+       double dpi_factor = accel_filter->dpi/(double)DEFAULT_MOUSE_DPI;
+       double factor; /* unitless */
+
+       /* dpi_factor is always < 1.0, increase max_accel, reduce
+          the threshold so it kicks in earlier */
+       max_accel /= dpi_factor;
+       threshold *= dpi_factor;
+
+       /* see pointer_accel_profile_linear for a long description */
+       if (v_us2ms(speed_in) < 0.07)
+               factor = 10 * v_us2ms(speed_in) + 0.3;
+       else if (speed_in < threshold)
+               factor = 1;
+       else
+               factor = incline * v_us2ms(speed_in - threshold) + 1;
+
+       factor = min(max_accel, factor);
+
+       return factor;
+}
+
+static inline double
+calculate_acceleration_factor(struct pointer_accelerator *accel,
+                             const struct device_float_coords *unaccelerated,
+                             void *data,
+                             uint64_t time)
+{
+       double velocity; /* units/us in device-native dpi*/
+       double accel_factor;
+
+       feed_trackers(&accel->trackers, unaccelerated, time);
+       velocity = calculate_velocity(&accel->trackers, time);
+       accel_factor = calculate_acceleration_simpsons(&accel->base,
+                                                      accel->profile,
+                                                      data,
+                                                      velocity,
+                                                      accel->last_velocity,
+                                                      time);
+       accel->last_velocity = velocity;
+
+       return accel_factor;
+}
+
+static struct device_float_coords
+accelerator_filter_generic(struct motion_filter *filter,
+                          const struct device_float_coords *unaccelerated,
+                          void *data, uint64_t time)
+{
+       struct pointer_accelerator *accel =
+               (struct pointer_accelerator *) filter;
+       double accel_value; /* unitless factor */
+       struct device_float_coords accelerated;
+
+       accel_value = calculate_acceleration_factor(accel,
+                                                   unaccelerated,
+                                                   data,
+                                                   time);
+
+       accelerated.x = accel_value * unaccelerated->x;
+       accelerated.y = accel_value * unaccelerated->y;
+
+       return accelerated;
+}
+
+static struct normalized_coords
+accelerator_filter_unnormalized(struct motion_filter *filter,
+                               const struct device_float_coords *unaccelerated,
+                               void *data, uint64_t time)
+{
+       struct device_float_coords accelerated;
+       struct normalized_coords normalized;
+
+       /* Accelerate for device units and return device units */
+       accelerated = accelerator_filter_generic(filter,
+                                                unaccelerated,
+                                                data,
+                                                time);
+       normalized.x = accelerated.x;
+       normalized.y = accelerated.y;
+       return normalized;
+}
+
+static struct normalized_coords
+accelerator_filter_noop(struct motion_filter *filter,
+                       const struct device_float_coords *unaccelerated,
+                       void *data, uint64_t time)
+{
+       struct pointer_accelerator *accel =
+               (struct pointer_accelerator *) filter;
+
+       return normalize_for_dpi(unaccelerated, accel->dpi);
+}
+
+static void
+accelerator_restart(struct motion_filter *filter,
+                   void *data,
+                   uint64_t time)
+{
+       struct pointer_accelerator *accel =
+               (struct pointer_accelerator *) filter;
+
+       reset_trackers(&accel->trackers, time);
+}
+
+static void
+accelerator_destroy(struct motion_filter *filter)
+{
+       struct pointer_accelerator *accel =
+               (struct pointer_accelerator *) filter;
+
+       free_trackers(&accel->trackers);
+       free(accel);
+}
+
+static bool
+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 = DEFAULT_THRESHOLD -
+                                       v_ms2us(0.25) * speed_adjustment;
+       if (accel_filter->threshold < MINIMUM_THRESHOLD)
+               accel_filter->threshold = MINIMUM_THRESHOLD;
+
+       /* adjust max accel factor */
+       accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5;
+
+       /* higher speed -> faster to reach max */
+       accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75;
+
+       filter->speed_adjustment = speed_adjustment;
+       return true;
+}
+
+struct motion_filter_interface accelerator_interface_low_dpi = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
+       .filter = accelerator_filter_unnormalized,
+       .filter_constant = accelerator_filter_noop,
+       .restart = accelerator_restart,
+       .destroy = accelerator_destroy,
+       .set_speed = accelerator_set_speed,
+};
+
+static struct pointer_accelerator *
+create_default_filter(int dpi)
+{
+       struct pointer_accelerator *filter;
+
+       filter = zalloc(sizeof *filter);
+       filter->last_velocity = 0.0;
+
+       init_trackers(&filter->trackers, NUM_POINTER_TRACKERS);
+
+       filter->threshold = DEFAULT_THRESHOLD;
+       filter->accel = DEFAULT_ACCELERATION;
+       filter->incline = DEFAULT_INCLINE;
+       filter->dpi = dpi;
+
+       return filter;
+}
+
+struct motion_filter *
+create_pointer_accelerator_filter_linear_low_dpi(int dpi)
+{
+       struct pointer_accelerator *filter;
+
+       filter = create_default_filter(dpi);
+       if (!filter)
+               return NULL;
+
+       filter->base.interface = &accelerator_interface_low_dpi;
+       filter->profile = pointer_accel_profile_linear_low_dpi;
+
+       return &filter->base;
+}
index 1261bc2..82d0ccc 100644 (file)
@@ -401,24 +401,6 @@ accelerator_filter_pre_normalized(struct motion_filter *filter,
        return normalized;
 }
 
-static struct normalized_coords
-accelerator_filter_unnormalized(struct motion_filter *filter,
-                               const struct device_float_coords *unaccelerated,
-                               void *data, uint64_t time)
-{
-       struct device_float_coords accelerated;
-       struct normalized_coords normalized;
-
-       /* Accelerate for device units and return device units */
-       accelerated = accelerator_filter_generic(filter,
-                                                unaccelerated,
-                                                data,
-                                                time);
-       normalized.x = accelerated.x;
-       normalized.y = accelerated.y;
-       return normalized;
-}
-
 /**
  * Generic filter that does nothing beyond converting from the device's
  * native dpi into normalized coordinates.
@@ -491,49 +473,6 @@ accelerator_set_speed(struct motion_filter *filter,
        return true;
 }
 
-/**
- * Custom acceleration function for mice < 1000dpi.
- * At slow motion, a single device unit causes a one-pixel movement.
- * The threshold/max accel depends on the DPI, the smaller the DPI the
- * earlier we accelerate and the higher the maximum acceleration is. Result:
- * at low speeds we get pixel-precision, at high speeds we get approx. the
- * same movement as a high-dpi mouse.
- *
- * Note: data fed to this function is in device units, not normalized.
- */
-double
-pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
-                                    void *data,
-                                    double speed_in, /* in device units (units/us) */
-                                    uint64_t time)
-{
-       struct pointer_accelerator *accel_filter =
-               (struct pointer_accelerator *)filter;
-
-       double max_accel = accel_filter->accel; /* unitless factor */
-       double threshold = accel_filter->threshold; /* units/us */
-       const double incline = accel_filter->incline;
-       double dpi_factor = accel_filter->dpi/(double)DEFAULT_MOUSE_DPI;
-       double factor; /* unitless */
-
-       /* dpi_factor is always < 1.0, increase max_accel, reduce
-          the threshold so it kicks in earlier */
-       max_accel /= dpi_factor;
-       threshold *= dpi_factor;
-
-       /* see pointer_accel_profile_linear for a long description */
-       if (v_us2ms(speed_in) < 0.07)
-               factor = 10 * v_us2ms(speed_in) + 0.3;
-       else if (speed_in < threshold)
-               factor = 1;
-       else
-               factor = incline * v_us2ms(speed_in - threshold) + 1;
-
-       factor = min(max_accel, factor);
-
-       return factor;
-}
-
 double
 pointer_accel_profile_linear(struct motion_filter *filter,
                             void *data,
@@ -651,27 +590,3 @@ create_pointer_accelerator_filter_linear(int dpi)
 
        return &filter->base;
 }
-
-struct motion_filter_interface accelerator_interface_low_dpi = {
-       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
-       .filter = accelerator_filter_unnormalized,
-       .filter_constant = accelerator_filter_noop,
-       .restart = accelerator_restart,
-       .destroy = accelerator_destroy,
-       .set_speed = accelerator_set_speed,
-};
-
-struct motion_filter *
-create_pointer_accelerator_filter_linear_low_dpi(int dpi)
-{
-       struct pointer_accelerator *filter;
-
-       filter = create_default_filter(dpi);
-       if (!filter)
-               return NULL;
-
-       filter->base.interface = &accelerator_interface_low_dpi;
-       filter->profile = pointer_accel_profile_linear_low_dpi;
-
-       return &filter->base;
-}