2 * Copyright © 2012 Jonas Ådahl
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 #include "libinput-util.h"
34 #include "filter-private.h"
37 filter_dispatch(struct motion_filter *filter,
38 struct motion_params *motion,
39 void *data, uint64_t time)
41 filter->interface->filter(filter, motion, data, time);
45 filter_destroy(struct motion_filter *filter)
50 filter->interface->destroy(filter);
54 filter_set_speed(struct motion_filter *filter,
57 return filter->interface->set_speed(filter, speed);
61 filter_get_speed(struct motion_filter *filter)
67 * Default parameters for pointer acceleration profiles.
70 #define DEFAULT_THRESHOLD 0.4 /* in units/ms */
71 #define DEFAULT_ACCELERATION 2.0 /* unitless factor */
72 #define DEFAULT_INCLINE 1.1 /* unitless factor */
75 * Pointer acceleration filter constants
78 #define MAX_VELOCITY_DIFF 1.0 /* units/ms */
79 #define MOTION_TIMEOUT 300 /* (ms) */
80 #define NUM_POINTER_TRACKERS 16
82 struct pointer_tracker {
83 double dx; /* delta to most recent event, in device units */
84 double dy; /* delta to most recent event, in device units */
85 uint64_t time; /* ms */
89 struct pointer_accelerator;
90 struct pointer_accelerator {
91 struct motion_filter base;
93 accel_profile_func_t profile;
95 double velocity; /* units/ms */
96 double last_velocity; /* units/ms */
97 int last_dx; /* device units */
98 int last_dy; /* device units */
100 struct pointer_tracker *trackers;
103 double threshold; /* units/ms */
104 double accel; /* unitless factor */
105 double incline; /* incline of the function */
109 feed_trackers(struct pointer_accelerator *accel,
110 double dx, double dy,
114 struct pointer_tracker *trackers = accel->trackers;
116 for (i = 0; i < NUM_POINTER_TRACKERS; i++) {
117 trackers[i].dx += dx;
118 trackers[i].dy += dy;
121 current = (accel->cur_tracker + 1) % NUM_POINTER_TRACKERS;
122 accel->cur_tracker = current;
124 trackers[current].dx = 0.0;
125 trackers[current].dy = 0.0;
126 trackers[current].time = time;
127 trackers[current].dir = vector_get_direction(dx, dy);
130 static struct pointer_tracker *
131 tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset)
134 (accel->cur_tracker + NUM_POINTER_TRACKERS - offset)
135 % NUM_POINTER_TRACKERS;
136 return &accel->trackers[index];
140 calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time)
148 distance = sqrt(dx*dx + dy*dy);
149 return distance / (double)(time - tracker->time); /* units/ms */
153 calculate_velocity(struct pointer_accelerator *accel, uint64_t time)
155 struct pointer_tracker *tracker;
158 double initial_velocity = 0.0;
159 double velocity_diff;
162 unsigned int dir = tracker_by_offset(accel, 0)->dir;
164 /* Find least recent vector within a timelimit, maximum velocity diff
165 * and direction threshold. */
166 for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) {
167 tracker = tracker_by_offset(accel, offset);
169 /* Stop if too far away in time */
170 if (time - tracker->time > MOTION_TIMEOUT ||
171 tracker->time > time)
174 /* Stop if direction changed */
179 velocity = calculate_tracker_velocity(tracker, time);
181 if (initial_velocity == 0.0) {
182 result = initial_velocity = velocity;
184 /* Stop if velocity differs too much from initial */
185 velocity_diff = fabs(initial_velocity - velocity);
186 if (velocity_diff > MAX_VELOCITY_DIFF)
193 return result; /* units/ms */
197 acceleration_profile(struct pointer_accelerator *accel,
198 void *data, double velocity, uint64_t time)
200 return accel->profile(&accel->base, data, velocity, time);
204 calculate_acceleration(struct pointer_accelerator *accel,
205 void *data, double velocity, uint64_t time)
209 /* Use Simpson's rule to calculate the avarage acceleration between
210 * the previous motion and the most recent. */
211 factor = acceleration_profile(accel, data, velocity, time);
212 factor += acceleration_profile(accel, data, accel->last_velocity, time);
214 acceleration_profile(accel, data,
215 (accel->last_velocity + velocity) / 2,
218 factor = factor / 6.0;
220 return factor; /* unitless factor */
224 accelerator_filter(struct motion_filter *filter,
225 struct motion_params *motion,
226 void *data, uint64_t time)
228 struct pointer_accelerator *accel =
229 (struct pointer_accelerator *) filter;
230 double velocity; /* units/ms */
231 double accel_value; /* unitless factor */
233 feed_trackers(accel, motion->dx, motion->dy, time);
234 velocity = calculate_velocity(accel, time);
235 accel_value = calculate_acceleration(accel, data, velocity, time);
237 motion->dx = accel_value * motion->dx;
238 motion->dy = accel_value * motion->dy;
240 accel->last_dx = motion->dx;
241 accel->last_dy = motion->dy;
243 accel->last_velocity = velocity;
247 accelerator_destroy(struct motion_filter *filter)
249 struct pointer_accelerator *accel =
250 (struct pointer_accelerator *) filter;
252 free(accel->trackers);
257 accelerator_set_speed(struct motion_filter *filter,
260 struct pointer_accelerator *accel_filter =
261 (struct pointer_accelerator *)filter;
263 assert(speed >= -1.0 && speed <= 1.0);
265 /* delay when accel kicks in */
266 accel_filter->threshold = DEFAULT_THRESHOLD - speed/6.0;
268 /* adjust max accel factor */
269 accel_filter->accel = DEFAULT_ACCELERATION + speed;
271 /* higher speed -> faster to reach max */
272 accel_filter->incline = DEFAULT_INCLINE + speed/2.0;
274 filter->speed = speed;
278 struct motion_filter_interface accelerator_interface = {
281 accelerator_set_speed,
284 struct motion_filter *
285 create_pointer_accelerator_filter(accel_profile_func_t profile)
287 struct pointer_accelerator *filter;
289 filter = malloc(sizeof *filter);
293 filter->base.interface = &accelerator_interface;
295 filter->profile = profile;
296 filter->last_velocity = 0.0;
301 calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
302 filter->cur_tracker = 0;
304 filter->threshold = DEFAULT_THRESHOLD;
305 filter->accel = DEFAULT_ACCELERATION;
306 filter->incline = DEFAULT_INCLINE;
308 return &filter->base;
312 calc_penumbral_gradient(double x)
316 return 0.5 + (x * sqrt(1.0 - x * x) + asin(x)) / M_PI;
320 pointer_accel_profile_linear(struct motion_filter *filter,
325 struct pointer_accelerator *accel_filter =
326 (struct pointer_accelerator *)filter;
329 const double max_accel = accel_filter->accel; /* unitless factor */
330 const double threshold = accel_filter->threshold; /* units/ms */
331 const double incline = accel_filter->incline;
333 s1 = min(1, speed_in * 5);
334 s2 = 1 + (speed_in - threshold) * incline;
336 return min(max_accel, s2 > 1 ? s2 : s1);