[PATCH libinput 1/2] filter: Add timestamp smoothing support

Hans de Goede hdegoede at redhat.com
Sun Jul 2 14:35:35 UTC 2017


Some devices, specifically some bluetooth touchpads generate quite
unreliable timestamps for their events. The problem seems to be that
(some of) these touchpads sample at aprox 90 Hz, but the bluetooth stack
only communicates about every 30 ms (*) and then sends mutiple HID input
reports in one batch.

This results in 2-4 packets / SYNs every 30 ms. With timestamps really
close together. The finger coordinate deltas in these packets change by
aprox. the same amount between each packet when moving a finger at
constant speed. But the time deltas are e.g. 28 ms, 1 ms, 1 ms resulting
in calculate_tracker_velocity returning vastly different speeds for the
1st and 2nd packet, which in turn results in very "jerky" mouse pointer
movement.

*) Maybe it is waiting for a transmit time slot or some such.

This commit adds support for a real simple timestamp smoothing algorithm,
intended *only* for use with touchpads. Since touchpads will send a
contineous stream of events at their sample rate when a finger is down,
this filter simply assumes that any events which are under
event_delta_smooth_threshold us apart are part of a smooth continuous
stream of events with each event being event_delta_smooth_value us apart.

Theoritically a very still finger may send the exact same coordinates
and pressure twice, but even if this happens that is not a problem because
a still finger generates coordinates changes below the hyst treshold so
we ignore it anyways.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 src/filter.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/filter.c b/src/filter.c
index 7c500f87..49d324eb 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -176,6 +176,10 @@ struct pointer_accelerator {
 	double accel;		/* unitless factor */
 	double incline;		/* incline of the function */
 
+	/* For smoothing timestamps from devices with unreliable timing */
+	uint64_t event_delta_smooth_threshold;
+	uint64_t event_delta_smooth_value;
+
 	int dpi;
 };
 
@@ -227,14 +231,21 @@ tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset)
 }
 
 static double
-calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time)
+calculate_tracker_velocity(struct pointer_accelerator *accel,
+			   struct pointer_tracker *tracker, uint64_t time)
 {
-	double tdelta = time - tracker->time + 1;
-	return hypot(tracker->delta.x, tracker->delta.y) / tdelta; /* units/us */
+	uint64_t tdelta = time - tracker->time + 1;
+
+	if (tdelta < accel->event_delta_smooth_threshold)
+		tdelta = accel->event_delta_smooth_value;
+
+	return hypot(tracker->delta.x, tracker->delta.y) /
+	       (double)tdelta; /* units/us */
 }
 
 static inline double
-calculate_velocity_after_timeout(struct pointer_tracker *tracker)
+calculate_velocity_after_timeout(struct pointer_accelerator *accel,
+				 struct pointer_tracker *tracker)
 {
 	/* First movement after timeout needs special handling.
 	 *
@@ -247,7 +258,7 @@ calculate_velocity_after_timeout(struct pointer_tracker *tracker)
 	 * for really slow movements but provides much more useful initial
 	 * movement in normal use-cases (pause, move, pause, move)
 	 */
-	return calculate_tracker_velocity(tracker,
+	return calculate_tracker_velocity(accel, tracker,
 					  tracker->time + MOTION_TIMEOUT);
 }
 
@@ -282,11 +293,11 @@ calculate_velocity(struct pointer_accelerator *accel, uint64_t time)
 		/* Stop if too far away in time */
 		if (time - tracker->time > MOTION_TIMEOUT) {
 			if (offset == 1)
-				result = calculate_velocity_after_timeout(tracker);
+				result = calculate_velocity_after_timeout(accel, tracker);
 			break;
 		}
 
-		velocity = calculate_tracker_velocity(tracker, time);
+		velocity = calculate_tracker_velocity(accel, tracker, time);
 
 		/* Stop if direction changed */
 		dir &= tracker->dir;
-- 
2.13.0



More information about the wayland-devel mailing list