static double calculate_velocity(struct pointer_accelerator *accel, uint32_t time) { struct pointer_tracker *tracker; double velocity; double result = 0.0; double initial_velocity; double velocity_diff; unsigned int offset; unsigned int dir = tracker_by_offset(accel, 0)->dir; /* Find first velocity */ for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) { tracker = tracker_by_offset(accel, offset); if (time <= tracker->time) continue; result = initial_velocity = calculate_tracker_velocity(tracker, time); if (initial_velocity > 0.0) break; } /* Find least recent vector within a timelimit, maximum velocity diff * and direction threshold. */ for (; offset < NUM_POINTER_TRACKERS; offset++) { tracker = tracker_by_offset(accel, offset); /* Stop if too far away in time */ if (time - tracker->time > MOTION_TIMEOUT || tracker->time > time) break; /* Stop if direction changed */ dir &= tracker->dir; if (dir == 0) break; velocity = calculate_tracker_velocity(tracker, time); /* Stop if velocity differs too much from initial */ velocity_diff = fabs(initial_velocity - velocity); if (velocity_diff > MAX_VELOCITY_DIFF) break; result = velocity; } return result; }
/** * Calculate the velocity based on the tracker data. Velocity is averaged * across multiple historical values, provided those values aren't "too * different" to our current one. That includes either being too far in the * past, moving into a different direction or having too much of a velocity * change between events. */ static double calculate_velocity(struct pointer_accelerator *accel, uint64_t time) { struct pointer_tracker *tracker; double velocity; double result = 0.0; double initial_velocity = 0.0; double velocity_diff; unsigned int offset; unsigned int dir = tracker_by_offset(accel, 0)->dir; /* Find least recent vector within a timelimit, maximum velocity diff * and direction threshold. */ for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) { tracker = tracker_by_offset(accel, offset); /* Bug: time running backwards */ if (tracker->time > time) break; /* Stop if too far away in time */ if (time - tracker->time > MOTION_TIMEOUT) { if (offset == 1) result = calculate_velocity_after_timeout(accel, tracker); break; } velocity = calculate_tracker_velocity(accel, tracker, time); /* Stop if direction changed */ dir &= tracker->dir; if (dir == 0) { /* First movement after dirchange - velocity is that * of the last movement */ if (offset == 1) result = velocity; break; } if (initial_velocity == 0.0) { result = initial_velocity = velocity; } else { /* Stop if velocity differs too much from initial */ velocity_diff = fabs(initial_velocity - velocity); if (velocity_diff > MAX_VELOCITY_DIFF) break; result = velocity; } } return result; /* units/us */ }
static inline double calculate_velocity_after_timeout(struct pointer_tracker *tracker) { /* First movement after timeout needs special handling. * * When we trigger the timeout, the last event is too far in the * past to use it for velocity calculation across multiple tracker * values. * * Use the motion timeout itself to calculate the speed rather than * the last tracker time. This errs on the side of being too fast * for really slow movements but provides much more useful initial * movement in normal use-cases (pause, move, pause, move) */ return calculate_tracker_velocity(tracker, tracker->time + MOTION_TIMEOUT); }