[PATCH libinput 15/23] filter: split the low-dpi acceleration into a separate file

Peter Hutterer peter.hutterer at who-t.net
Thu Apr 12 06:34:41 UTC 2018


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 at who-t.net>
---
 meson.build          |   1 +
 src/filter-low-dpi.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/filter.c         |  85 -----------------
 3 files changed, 254 insertions(+), 85 deletions(-)
 create mode 100644 src/filter-low-dpi.c

diff --git a/meson.build b/meson.build
index 933e2f3f..9473dc12 100644
--- a/meson.build
+++ b/meson.build
@@ -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
index 00000000..f22929ad
--- /dev/null
+++ b/src/filter-low-dpi.c
@@ -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;
+}
diff --git a/src/filter.c b/src/filter.c
index 1261bc22..82d0ccce 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -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;
-}
-- 
2.14.3



More information about the wayland-devel mailing list