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 units/us */
42 #define MINIMUM_THRESHOLD v_ms2us(0.2) /* in 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; /* 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 device_float_coords * unaccelerated,void * data,uint64_t time)74 calculate_acceleration_factor(struct pointer_accelerator *accel,
75 const struct device_float_coords *unaccelerated,
76 void *data,
77 uint64_t time)
78 {
79 double velocity; /* units/us in device-native dpi*/
80 double accel_factor;
81
82 trackers_feed(&accel->trackers, unaccelerated, time);
83 velocity = trackers_velocity(&accel->trackers, time);
84 accel_factor = calculate_acceleration_simpsons(&accel->base,
85 accel->profile,
86 data,
87 velocity,
88 accel->last_velocity,
89 time);
90 accel->last_velocity = velocity;
91
92 return accel_factor;
93 }
94
95 /**
96 * Generic filter that calculates the acceleration factor and applies it to
97 * the coordinates.
98 *
99 * @param filter The acceleration filter
100 * @param unaccelerated The raw delta in the device's dpi
101 * @param data Caller-specific data
102 * @param time Current time in µs
103 *
104 * @return An accelerated tuple of coordinates representing accelerated
105 * motion, still in device units.
106 */
107 static struct device_float_coords
accelerator_filter_generic(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)108 accelerator_filter_generic(struct motion_filter *filter,
109 const struct device_float_coords *unaccelerated,
110 void *data, uint64_t time)
111 {
112 struct pointer_accelerator *accel =
113 (struct pointer_accelerator *) filter;
114 double accel_value; /* unitless factor */
115 struct device_float_coords accelerated;
116
117 accel_value = calculate_acceleration_factor(accel,
118 unaccelerated,
119 data,
120 time);
121
122 accelerated.x = accel_value * unaccelerated->x;
123 accelerated.y = accel_value * unaccelerated->y;
124
125 return accelerated;
126 }
127
128 static struct normalized_coords
accelerator_filter_pre_normalized(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)129 accelerator_filter_pre_normalized(struct motion_filter *filter,
130 const struct device_float_coords *unaccelerated,
131 void *data, uint64_t time)
132 {
133 struct pointer_accelerator *accel =
134 (struct pointer_accelerator *) filter;
135 struct normalized_coords normalized;
136 struct device_float_coords converted, accelerated;
137
138 /* Accelerate for normalized units and return normalized units.
139 API requires device_floats, so we just copy the bits around */
140 normalized = normalize_for_dpi(unaccelerated, accel->dpi);
141 converted.x = normalized.x;
142 converted.y = normalized.y;
143
144 accelerated = accelerator_filter_generic(filter,
145 &converted,
146 data,
147 time);
148 normalized.x = accelerated.x;
149 normalized.y = accelerated.y;
150 return normalized;
151 }
152
153 /**
154 * Generic filter that does nothing beyond converting from the device's
155 * native dpi into normalized coordinates.
156 *
157 * @param filter The acceleration filter
158 * @param unaccelerated The raw delta in the device's dpi
159 * @param data Caller-specific data
160 * @param time Current time in µs
161 *
162 * @return An accelerated tuple of coordinates representing normalized
163 * motion
164 */
165 static struct normalized_coords
accelerator_filter_noop(struct motion_filter * filter,const struct device_float_coords * unaccelerated,void * data,uint64_t time)166 accelerator_filter_noop(struct motion_filter *filter,
167 const struct device_float_coords *unaccelerated,
168 void *data, uint64_t time)
169 {
170 struct pointer_accelerator *accel =
171 (struct pointer_accelerator *) filter;
172
173 return normalize_for_dpi(unaccelerated, accel->dpi);
174 }
175
176 static void
accelerator_restart(struct motion_filter * filter,void * data,uint64_t time)177 accelerator_restart(struct motion_filter *filter,
178 void *data,
179 uint64_t time)
180 {
181 struct pointer_accelerator *accel =
182 (struct pointer_accelerator *) filter;
183
184 trackers_reset(&accel->trackers, time);
185 }
186
187 static void
accelerator_destroy(struct motion_filter * filter)188 accelerator_destroy(struct motion_filter *filter)
189 {
190 struct pointer_accelerator *accel =
191 (struct pointer_accelerator *) filter;
192
193 trackers_free(&accel->trackers);
194 free(accel);
195 }
196
197 static bool
accelerator_set_speed(struct motion_filter * filter,double speed_adjustment)198 accelerator_set_speed(struct motion_filter *filter,
199 double speed_adjustment)
200 {
201 struct pointer_accelerator *accel_filter =
202 (struct pointer_accelerator *)filter;
203
204 assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
205
206 /* Note: the numbers below are nothing but trial-and-error magic,
207 don't read more into them other than "they mostly worked ok" */
208
209 /* delay when accel kicks in */
210 accel_filter->threshold = DEFAULT_THRESHOLD -
211 v_ms2us(0.25) * speed_adjustment;
212 if (accel_filter->threshold < MINIMUM_THRESHOLD)
213 accel_filter->threshold = MINIMUM_THRESHOLD;
214
215 /* adjust max accel factor */
216 accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5;
217
218 /* higher speed -> faster to reach max */
219 accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75;
220
221 filter->speed_adjustment = speed_adjustment;
222 return true;
223 }
224
225 double
pointer_accel_profile_linear(struct motion_filter * filter,void * data,double speed_in,uint64_t time)226 pointer_accel_profile_linear(struct motion_filter *filter,
227 void *data,
228 double speed_in, /* in device units (units/µs) */
229 uint64_t time)
230 {
231 struct pointer_accelerator *accel_filter =
232 (struct pointer_accelerator *)filter;
233 const double max_accel = accel_filter->accel; /* unitless factor */
234 const double threshold = accel_filter->threshold; /* units/us */
235 const double incline = accel_filter->incline;
236 double factor; /* unitless */
237
238 /* Normalize to 1000dpi, because the rest below relies on that */
239 speed_in = speed_in * DEFAULT_MOUSE_DPI/accel_filter->dpi;
240
241 /*
242 Our acceleration function calculates a factor to accelerate input
243 deltas with. The function is a double incline with a plateau,
244 with a rough shape like this:
245
246 accel
247 factor
248 ^
249 | /
250 | _____/
251 | /
252 |/
253 +-------------> speed in
254
255 The two inclines are linear functions in the form
256 y = ax + b
257 where y is speed_out
258 x is speed_in
259 a is the incline of acceleration
260 b is minimum acceleration factor
261
262 for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
263 speed.
264 hence 1 = a * 0.07 + 0.3
265 0.7 = a * 0.07 => a := 10
266 deceleration function is thus:
267 y = 10x + 0.3
268
269 Note:
270 * 0.07u/ms as threshold is a result of trial-and-error and
271 has no other intrinsic meaning.
272 * 0.3 is chosen simply because it is above the Nyquist frequency
273 for subpixel motion within a pixel.
274 */
275 if (v_us2ms(speed_in) < 0.07) {
276 factor = 10 * v_us2ms(speed_in) + 0.3;
277 /* up to the threshold, we keep factor 1, i.e. 1:1 movement */
278 } else if (speed_in < threshold) {
279 factor = 1;
280
281 } else {
282 /* Acceleration function above the threshold:
283 y = ax' + b
284 where T is threshold
285 x is speed_in
286 x' is speed
287 and
288 y(T) == 1
289 hence 1 = ax' + 1
290 => x' := (x - T)
291 */
292 factor = incline * v_us2ms(speed_in - threshold) + 1;
293 }
294
295 /* Cap at the maximum acceleration factor */
296 factor = min(max_accel, factor);
297
298 return factor;
299 }
300
301 struct motion_filter_interface accelerator_interface = {
302 .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
303 .filter = accelerator_filter_pre_normalized,
304 .filter_constant = accelerator_filter_noop,
305 .restart = accelerator_restart,
306 .destroy = accelerator_destroy,
307 .set_speed = accelerator_set_speed,
308 };
309
310 static struct pointer_accelerator *
create_default_filter(int dpi,bool use_velocity_averaging)311 create_default_filter(int dpi, bool use_velocity_averaging)
312 {
313 struct pointer_accelerator *filter;
314
315 filter = zalloc(sizeof *filter);
316 filter->last_velocity = 0.0;
317
318 trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
319
320 filter->threshold = DEFAULT_THRESHOLD;
321 filter->accel = DEFAULT_ACCELERATION;
322 filter->incline = DEFAULT_INCLINE;
323 filter->dpi = dpi;
324
325 return filter;
326 }
327
328 struct motion_filter *
create_pointer_accelerator_filter_linear(int dpi,bool use_velocity_averaging)329 create_pointer_accelerator_filter_linear(int dpi, bool use_velocity_averaging)
330 {
331 struct pointer_accelerator *filter;
332
333 filter = create_default_filter(dpi, use_velocity_averaging);
334 if (!filter)
335 return NULL;
336
337 filter->base.interface = &accelerator_interface;
338 filter->profile = pointer_accel_profile_linear;
339
340 return &filter->base;
341 }
342