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 #include <limits.h>
33 #include <math.h>
34 
35 #include "filter.h"
36 #include "libinput-util.h"
37 #include "filter-private.h"
38 
39 #define MOTION_TIMEOUT		ms2us(1000)
40 
41 struct normalized_coords
filter_dispatch(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)42 filter_dispatch(struct motion_filter *filter,
43 		const struct device_float_coords *unaccelerated,
44 		void *data, uint64_t time)
45 {
46 	return filter->interface->filter(filter, unaccelerated, data, time);
47 }
48 
49 struct normalized_coords
filter_dispatch_constant(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)50 filter_dispatch_constant(struct motion_filter *filter,
51 			 const struct device_float_coords *unaccelerated,
52 			 void *data, uint64_t time)
53 {
54 	return filter->interface->filter_constant(filter, unaccelerated, data, time);
55 }
56 
57 void
filter_restart(struct motion_filter * filter,void * data,uint64_t time)58 filter_restart(struct motion_filter *filter,
59 	       void *data, uint64_t time)
60 {
61 	if (filter->interface->restart)
62 		filter->interface->restart(filter, data, time);
63 }
64 
65 void
filter_destroy(struct motion_filter * filter)66 filter_destroy(struct motion_filter *filter)
67 {
68 	if (!filter || !filter->interface->destroy)
69 		return;
70 
71 	filter->interface->destroy(filter);
72 }
73 
74 bool
filter_set_speed(struct motion_filter * filter,double speed_adjustment)75 filter_set_speed(struct motion_filter *filter,
76 		 double speed_adjustment)
77 {
78 	return filter->interface->set_speed(filter, speed_adjustment);
79 }
80 
81 double
filter_get_speed(struct motion_filter * filter)82 filter_get_speed(struct motion_filter *filter)
83 {
84 	return filter->speed_adjustment;
85 }
86 
87 enum libinput_config_accel_profile
filter_get_type(struct motion_filter * filter)88 filter_get_type(struct motion_filter *filter)
89 {
90 	return filter->interface->type;
91 }
92 
93 void
trackers_init(struct pointer_trackers * trackers,int ntrackers)94 trackers_init(struct pointer_trackers *trackers, int ntrackers)
95 {
96 	trackers->trackers = zalloc(ntrackers *
97 				    sizeof(*trackers->trackers));
98 	trackers->ntrackers = ntrackers;
99 	trackers->cur_tracker = 0;
100 	trackers->smoothener = NULL;
101 }
102 
103 void
trackers_free(struct pointer_trackers * trackers)104 trackers_free(struct pointer_trackers *trackers)
105 {
106 	free(trackers->trackers);
107 	free(trackers->smoothener);
108 }
109 
110 void
trackers_reset(struct pointer_trackers * trackers,uint64_t time)111 trackers_reset(struct pointer_trackers *trackers,
112 	       uint64_t time)
113 {
114 	unsigned int offset;
115 	struct pointer_tracker *tracker;
116 
117 	for (offset = 1; offset < trackers->ntrackers; offset++) {
118 		tracker = trackers_by_offset(trackers, offset);
119 		tracker->time = 0;
120 		tracker->dir = 0;
121 		tracker->delta.x = 0;
122 		tracker->delta.y = 0;
123 	}
124 
125 	tracker = trackers_by_offset(trackers, 0);
126 	tracker->time = time;
127 	tracker->dir = UNDEFINED_DIRECTION;
128 }
129 
130 void
trackers_feed(struct pointer_trackers * trackers,const struct device_float_coords * delta,uint64_t time)131 trackers_feed(struct pointer_trackers *trackers,
132 	      const struct device_float_coords *delta,
133 	      uint64_t time)
134 {
135 	unsigned int i, current;
136 	struct pointer_tracker *ts = trackers->trackers;
137 
138 	assert(trackers->ntrackers);
139 
140 	for (i = 0; i < trackers->ntrackers; i++) {
141 		ts[i].delta.x += delta->x;
142 		ts[i].delta.y += delta->y;
143 	}
144 
145 	current = (trackers->cur_tracker + 1) % trackers->ntrackers;
146 	trackers->cur_tracker = current;
147 
148 	ts[current].delta.x = 0.0;
149 	ts[current].delta.y = 0.0;
150 	ts[current].time = time;
151 	ts[current].dir = device_float_get_direction(*delta);
152 }
153 
154 struct pointer_tracker *
trackers_by_offset(struct pointer_trackers * trackers,unsigned int offset)155 trackers_by_offset(struct pointer_trackers *trackers, unsigned int offset)
156 {
157 	unsigned int index =
158 		(trackers->cur_tracker + trackers->ntrackers - offset)
159 		% trackers->ntrackers;
160 	return &trackers->trackers[index];
161 }
162 
163 static double
calculate_trackers_velocity(struct pointer_tracker * tracker,uint64_t time,struct pointer_delta_smoothener * smoothener)164 calculate_trackers_velocity(struct pointer_tracker *tracker,
165 			   uint64_t time,
166 			   struct pointer_delta_smoothener *smoothener)
167 {
168 	uint64_t tdelta = time - tracker->time + 1;
169 
170 	if (smoothener && tdelta < smoothener->threshold)
171 		tdelta = smoothener->value;
172 
173 	return hypot(tracker->delta.x, tracker->delta.y) /
174 	       (double)tdelta; /* units/us */
175 }
176 
177 static double
trackers_velocity_after_timeout(struct pointer_tracker * tracker,struct pointer_delta_smoothener * smoothener)178 trackers_velocity_after_timeout(struct pointer_tracker *tracker,
179 				 struct pointer_delta_smoothener *smoothener)
180 {
181 	/* First movement after timeout needs special handling.
182 	 *
183 	 * When we trigger the timeout, the last event is too far in the
184 	 * past to use it for velocity calculation across multiple tracker
185 	 * values.
186 	 *
187 	 * Use the motion timeout itself to calculate the speed rather than
188 	 * the last tracker time. This errs on the side of being too fast
189 	 * for really slow movements but provides much more useful initial
190 	 * movement in normal use-cases (pause, move, pause, move)
191 	 */
192 	return calculate_trackers_velocity(tracker,
193 					  tracker->time + MOTION_TIMEOUT,
194 					  smoothener);
195 }
196 
197 /**
198  * Calculate the velocity based on the tracker data. Velocity is averaged
199  * across multiple historical values, provided those values aren't "too
200  * different" to our current one. That includes either being too far in the
201  * past, moving into a different direction or having too much of a velocity
202  * change between events.
203  */
204 double
trackers_velocity(struct pointer_trackers * trackers,uint64_t time)205 trackers_velocity(struct pointer_trackers *trackers, uint64_t time)
206 {
207 	const double MAX_VELOCITY_DIFF = v_ms2us(1); /* units/us */
208 	struct pointer_tracker *tracker;
209 	double velocity;
210 	double result = 0.0;
211 	double initial_velocity = 0.0;
212 	double velocity_diff;
213 	unsigned int offset;
214 
215 	unsigned int dir = trackers_by_offset(trackers, 0)->dir;
216 
217 	/* Find least recent vector within a timelimit, maximum velocity diff
218 	 * and direction threshold. */
219 	for (offset = 1; offset < trackers->ntrackers; offset++) {
220 		tracker = trackers_by_offset(trackers, offset);
221 
222 		/* Bug: time running backwards */
223 		if (tracker->time > time)
224 			break;
225 
226 		/* Stop if too far away in time */
227 		if (time - tracker->time > MOTION_TIMEOUT) {
228 			if (offset == 1)
229 				result = trackers_velocity_after_timeout(
230 							  tracker,
231 							  trackers->smoothener);
232 			break;
233 		}
234 
235 		velocity = calculate_trackers_velocity(tracker,
236 						      time,
237 						      trackers->smoothener);
238 
239 		/* Stop if direction changed */
240 		dir &= tracker->dir;
241 		if (dir == 0) {
242 			/* First movement after dirchange - velocity is that
243 			 * of the last movement */
244 			if (offset == 1)
245 				result = velocity;
246 			break;
247 		}
248 
249 		/* Always average the first two events. On some touchpads
250 		 * where the first event is jumpy, this somewhat reduces
251 		 * pointer jumps on slow motions. */
252 		if (initial_velocity == 0.0 || offset <= 2) {
253 			result = initial_velocity = velocity;
254 		} else {
255 			/* Stop if velocity differs too much from initial */
256 			velocity_diff = fabs(initial_velocity - velocity);
257 			if (velocity_diff > MAX_VELOCITY_DIFF)
258 				break;
259 
260 			result = velocity;
261 		}
262 	}
263 
264 	return result; /* units/us */
265 }
266 
267 /**
268  * Calculate the acceleration factor for our current velocity, averaging
269  * between our current and the most recent velocity to smoothen out changes.
270  *
271  * @param accel The acceleration filter
272  * @param data Caller-specific data
273  * @param velocity Velocity in device-units per µs
274  * @param last_velocity Previous velocity in device-units per µs
275  * @param time Current time in µs
276  *
277  * @return A unitless acceleration factor, to be applied to the delta
278  */
279 double
calculate_acceleration_simpsons(struct motion_filter * filter,accel_profile_func_t profile,void * data,double velocity,double last_velocity,uint64_t time)280 calculate_acceleration_simpsons(struct motion_filter *filter,
281 				accel_profile_func_t profile,
282 				void *data,
283 				double velocity,
284 				double last_velocity,
285 				uint64_t time)
286 {
287 	double factor;
288 
289 	/* Use Simpson's rule to calculate the avarage acceleration between
290 	 * the previous motion and the most recent. */
291 	factor = profile(filter, data, velocity, time);
292 	factor += profile(filter, data, last_velocity, time);
293 	factor += 4.0 * profile(filter, data,
294 				(last_velocity + velocity) / 2,
295 				time);
296 
297 	factor = factor / 6.0;
298 
299 	return factor; /* unitless factor */
300 }
301