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