• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2006-2009 Simon Thum
3  * Copyright © 2012 Jonas Ådahl
4  * Copyright © 2014-2015 Red Hat, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 
33 #include "filter.h"
34 #include "libinput-util.h"
35 #include "filter-private.h"
36 
37 /*
38  * Default parameters for pointer acceleration profiles.
39  */
40 
41 #define DEFAULT_THRESHOLD v_ms2us(0.4)		/* in 1000dpi units/us */
42 #define MINIMUM_THRESHOLD v_ms2us(0.2)		/* in 1000dpi units/us */
43 #define DEFAULT_ACCELERATION 2.0		/* unitless factor */
44 #define DEFAULT_INCLINE 1.1			/* unitless factor */
45 
46 struct pointer_accelerator {
47 	struct motion_filter base;
48 
49 	accel_profile_func_t profile;
50 
51 	double velocity;	/* units/us */
52 	double last_velocity;	/* units/us */
53 
54 	struct pointer_trackers trackers;
55 
56 	double threshold;	/* 1000dpi units/us */
57 	double accel;		/* unitless factor */
58 	double incline;		/* incline of the function */
59 
60 	int dpi;
61 };
62 
63 /**
64  * Calculate the acceleration factor for the given delta with the timestamp.
65  *
66  * @param accel The acceleration filter
67  * @param unaccelerated The raw delta in the device's dpi
68  * @param data Caller-specific data
69  * @param time Current time in µs
70  *
71  * @return A unitless acceleration factor, to be applied to the delta
72  */
73 static inline double
calculate_acceleration_factor(struct pointer_accelerator * accel,const struct normalized_coords * unaccelerated,void * data,uint64_t time)74 calculate_acceleration_factor(struct pointer_accelerator *accel,
75 			      const struct normalized_coords *unaccelerated,
76 			      void *data,
77 			      uint64_t time)
78 {
79 	double velocity; /* units/us in normalized 1000dpi units*/
80 	double accel_factor;
81 
82 	/* The trackers API need device_float_coords, but note that we have
83 	 * normalized coordinates */
84 	const struct device_float_coords unaccel = {
85 		.x = unaccelerated->x,
86 		.y = unaccelerated->y,
87 	};
88 	trackers_feed(&accel->trackers, &unaccel, time);
89 	velocity = trackers_velocity(&accel->trackers, time);
90 	/* This will call into our pointer_accel_profile_linear() profile func */
91 	accel_factor = calculate_acceleration_simpsons(&accel->base,
92 						       accel->profile,
93 						       data,
94 						       velocity, /* normalized coords */
95 						       accel->last_velocity, /* normalized coords */
96 						       time);
97 	accel->last_velocity = velocity;
98 
99 	return accel_factor;
100 }
101 
102 static struct normalized_coords
accelerator_filter_linear(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)103 accelerator_filter_linear(struct motion_filter *filter,
104 			  const struct device_float_coords *unaccelerated,
105 			  void *data, uint64_t time)
106 {
107 	struct pointer_accelerator *accel =
108 		(struct pointer_accelerator *) filter;
109 
110 	/* Accelerate for normalized units and return normalized units */
111 	const struct normalized_coords normalized = normalize_for_dpi(unaccelerated,
112 								      accel->dpi);
113 	double accel_factor = calculate_acceleration_factor(accel,
114 							    &normalized,
115 							    data,
116 							    time);
117 	struct normalized_coords accelerated = {
118 		.x = normalized.x * accel_factor,
119 		.y = normalized.y * accel_factor,
120 	};
121 	return accelerated;
122 }
123 
124 /**
125  * Generic filter that does nothing beyond converting from the device's
126  * native dpi into normalized coordinates.
127  *
128  * @param filter The acceleration filter
129  * @param unaccelerated The raw delta in the device's dpi
130  * @param data Caller-specific data
131  * @param time Current time in µs
132  *
133  * @return An accelerated tuple of coordinates representing normalized
134  * motion
135  */
136 static struct normalized_coords
accelerator_filter_noop(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)137 accelerator_filter_noop(struct motion_filter *filter,
138 			const struct device_float_coords *unaccelerated,
139 			void *data, uint64_t time)
140 {
141 	struct pointer_accelerator *accel =
142 		(struct pointer_accelerator *) filter;
143 
144 	return normalize_for_dpi(unaccelerated, accel->dpi);
145 }
146 
147 static void
accelerator_restart(struct motion_filter * filter,void * data,uint64_t time)148 accelerator_restart(struct motion_filter *filter,
149 		    void *data,
150 		    uint64_t time)
151 {
152 	struct pointer_accelerator *accel =
153 		(struct pointer_accelerator *) filter;
154 
155 	trackers_reset(&accel->trackers, time);
156 }
157 
158 static void
accelerator_destroy(struct motion_filter * filter)159 accelerator_destroy(struct motion_filter *filter)
160 {
161 	struct pointer_accelerator *accel =
162 		(struct pointer_accelerator *) filter;
163 
164 	trackers_free(&accel->trackers);
165 	free(accel);
166 }
167 
168 static bool
accelerator_set_speed(struct motion_filter * filter,double speed_adjustment)169 accelerator_set_speed(struct motion_filter *filter,
170 		      double speed_adjustment)
171 {
172 	struct pointer_accelerator *accel_filter =
173 		(struct pointer_accelerator *)filter;
174 
175 	assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
176 
177 	/* Note: the numbers below are nothing but trial-and-error magic,
178 	   don't read more into them other than "they mostly worked ok" */
179 
180 	/* delay when accel kicks in */
181 	accel_filter->threshold = DEFAULT_THRESHOLD -
182 					v_ms2us(0.25) * speed_adjustment;
183 	if (accel_filter->threshold < MINIMUM_THRESHOLD)
184 		accel_filter->threshold = MINIMUM_THRESHOLD;
185 
186 	/* adjust max accel factor */
187 	accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5;
188 
189 	/* higher speed -> faster to reach max */
190 	accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75;
191 
192 	filter->speed_adjustment = speed_adjustment;
193 	return true;
194 }
195 
196 double
pointer_accel_profile_linear(struct motion_filter * filter,void * data,double speed_in,uint64_t time)197 pointer_accel_profile_linear(struct motion_filter *filter,
198 			     void *data,
199 			     double speed_in, /* in normalized units */
200 			     uint64_t time)
201 {
202 	struct pointer_accelerator *accel_filter =
203 		(struct pointer_accelerator *)filter;
204 	const double max_accel = accel_filter->accel; /* unitless factor */
205 	const double threshold = accel_filter->threshold; /* 1000dpi units/us */
206 	const double incline = accel_filter->incline;
207 	double factor; /* unitless */
208 
209 	/*
210 	   Our acceleration function calculates a factor to accelerate input
211 	   deltas with. The function is a double incline with a plateau,
212 	   with a rough shape like this:
213 
214 	  accel
215 	 factor
216 	   ^
217 	   |        /
218 	   |  _____/
219 	   | /
220 	   |/
221 	   +-------------> speed in
222 
223 	   The two inclines are linear functions in the form
224 		   y = ax + b
225 		   where y is speed_out
226 		         x is speed_in
227 			 a is the incline of acceleration
228 			 b is minimum acceleration factor
229 
230 	   for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
231 	   speed.
232 		   hence 1 = a * 0.07 + 0.3
233 		       0.7 = a * 0.07 => a := 10
234 		   deceleration function is thus:
235 			y = 10x + 0.3
236 
237 	  Note:
238 	  * 0.07u/ms as threshold is a result of trial-and-error and
239 	    has no other intrinsic meaning.
240 	  * 0.3 is chosen simply because it is above the Nyquist frequency
241 	    for subpixel motion within a pixel.
242 	*/
243 	if (v_us2ms(speed_in) < 0.07) {
244 		factor = 10 * v_us2ms(speed_in) + 0.3;
245 	/* up to the threshold, we keep factor 1, i.e. 1:1 movement */
246 	} else if (speed_in < threshold) {
247 		factor = 1;
248 
249 	} else {
250 	/* Acceleration function above the threshold:
251 		y = ax' + b
252 		where T is threshold
253 		      x is speed_in
254 		      x' is speed
255 	        and
256 			y(T) == 1
257 		hence 1 = ax' + 1
258 			=> x' := (x - T)
259 	 */
260 		factor = incline * v_us2ms(speed_in - threshold) + 1;
261 	}
262 
263 	/* Cap at the maximum acceleration factor */
264 	factor = min(max_accel, factor);
265 
266 	return factor;
267 }
268 
269 static const struct motion_filter_interface accelerator_interface = {
270 	.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
271 	.filter = accelerator_filter_linear,
272 	.filter_constant = accelerator_filter_noop,
273 	.filter_scroll = accelerator_filter_noop,
274 	.restart = accelerator_restart,
275 	.destroy = accelerator_destroy,
276 	.set_speed = accelerator_set_speed,
277 };
278 
279 static struct pointer_accelerator *
create_default_filter(int dpi,bool use_velocity_averaging)280 create_default_filter(int dpi, bool use_velocity_averaging)
281 {
282 	struct pointer_accelerator *filter;
283 
284 	filter = zalloc(sizeof *filter);
285 	filter->last_velocity = 0.0;
286 
287 	trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
288 
289 	filter->threshold = DEFAULT_THRESHOLD;
290 	filter->accel = DEFAULT_ACCELERATION;
291 	filter->incline = DEFAULT_INCLINE;
292 	filter->dpi = dpi;
293 
294 	return filter;
295 }
296 
297 struct motion_filter *
create_pointer_accelerator_filter_linear(int dpi,bool use_velocity_averaging)298 create_pointer_accelerator_filter_linear(int dpi, bool use_velocity_averaging)
299 {
300 	struct pointer_accelerator *filter;
301 
302 	filter = create_default_filter(dpi, use_velocity_averaging);
303 	if (!filter)
304 		return NULL;
305 
306 	filter->base.interface = &accelerator_interface;
307 	filter->profile = pointer_accel_profile_linear;
308 
309 	return &filter->base;
310 }
311