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 #121

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2018-08-27 12:35:27 +10:00
parent 50837e6ff2
commit 7d0e187570
3 changed files with 38 additions and 9 deletions

View file

@ -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"

View file

@ -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;
}

View file

@ -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),