Commit 7d0e1875 authored by Peter Hutterer's avatar Peter Hutterer

touchpad: make tp_detect_jumps() time-independent

This function expected distances per-frame, not per-time which gives us
different behaviors depending on the hardware scanout rate. Fix this by
normalizing to a 12ms frame rate which reflects the touchpad I measured all
the existing thresholds on.

This is a bit of a problem for the test suite which doesn't use proper
intervals and the change to do so is rather invasive. So for now we set the
interval for test devices to whatever the time delta is so we can test the
jumps without having to worry about intervals.

Fixes #121Signed-off-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
parent 50837e6f
Pipeline #3821 passed with stages
in 7 minutes and 9 seconds
......@@ -1442,13 +1442,19 @@ tp_need_motion_history_reset(struct tp_dispatch *tp)
}
static bool
tp_detect_jumps(const struct tp_dispatch *tp, struct tp_touch *t)
tp_detect_jumps(const struct tp_dispatch *tp,
struct tp_touch *t,
uint64_t time)
{
struct device_coords delta;
struct phys_coords mm;
struct tp_history_point *last;
double distance;
double abs_distance, rel_distance;
bool is_jump = false;
uint64_t tdelta;
/* Reference interval from the touchpad the various thresholds
* were measured from */
unsigned int reference_interval = ms2us(12);
/* We haven't seen pointer jumps on Wacom tablets yet, so exclude
* those.
......@@ -1464,19 +1470,35 @@ tp_detect_jumps(const struct tp_dispatch *tp, struct tp_touch *t)
/* called before tp_motion_history_push, so offset 0 is the most
* recent coordinate */
last = tp_motion_history_offset(t, 0);
tdelta = time - last->time;
/* For test devices we always force the time delta to 12, at least
until the test suite actually does proper intervals. */
if (tp->device->model_flags & EVDEV_MODEL_TEST_DEVICE)
reference_interval = tdelta;
/* If the last frame is more than 25ms ago, we have irregular
* frames, who knows what's a pointer jump here and what's
* legitimate movement.... */
if (tdelta > 2 * reference_interval || tdelta == 0)
return false;
/* We historically expected ~12ms frame intervals, so the numbers
below are normalized to that (and that's also where the
measured data came from) */
delta.x = abs(t->point.x - last->point.x);
delta.y = abs(t->point.y - last->point.y);
mm = evdev_device_unit_delta_to_mm(tp->device, &delta);
distance = hypot(mm.x, mm.y);
abs_distance = hypot(mm.x, mm.y) * reference_interval/tdelta;
rel_distance = abs_distance - t->jumps.last_delta_mm;
/* Cursor jump if:
* - current single-event delta is >20mm, or
* - we increased the delta by over 7mm within a frame.
* - we increased the delta by over 7mm within a 12ms frame.
* (12ms simply because that's what I measured)
*/
is_jump = distance > 20.0 ||
(distance - t->jumps.last_delta_mm) > 7;
t->jumps.last_delta_mm = distance;
is_jump = abs_distance > 20.0 || rel_distance > 7;
t->jumps.last_delta_mm = abs_distance;
return is_jump;
}
......@@ -1582,7 +1604,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
continue;
}
if (tp_detect_jumps(tp, t)) {
if (tp_detect_jumps(tp, t, time)) {
if (!tp->semi_mt)
evdev_log_bug_kernel(tp->device,
"Touch jump detected and discarded.\n"
......
......@@ -1355,6 +1355,12 @@ evdev_read_model_flags(struct evdev_device *device)
model_flags |= EVDEV_MODEL_LENOVO_X220_TOUCHPAD_FW81;
}
if (parse_udev_flag(device, device->udev_device,
"LIBINPUT_TEST_DEVICE")) {
evdev_log_debug(device, "is a test device\n");
model_flags |= EVDEV_MODEL_TEST_DEVICE;
}
return model_flags;
}
......
......@@ -110,6 +110,7 @@ enum evdev_device_model {
EVDEV_MODEL_WACOM_TOUCHPAD = (1 << 7),
EVDEV_MODEL_ALPS_TOUCHPAD = (1 << 8),
EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD = (1 << 9),
EVDEV_MODEL_TEST_DEVICE = (1 << 10),
EVDEV_MODEL_BOUNCING_KEYS = (1 << 11),
EVDEV_MODEL_LENOVO_X220_TOUCHPAD_FW81 = (1 << 12),
EVDEV_MODEL_LENOVO_CARBON_X1_6TH = (1 << 13),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment