Commit eca2f8c9 authored by Peter Hutterer's avatar Peter Hutterer

touchpad: improve pointer jump detection

Previously, we had a hard threshold of 20mm per event frame. That is just
about achievable by really fast movements (in which case you don't care too
much about the jumps anyway because you've already hit the edge of the screen).

Sometimes pointer jumps have lower deltas that are achievable even on slower,
more likely motions. Analysis of finger motion has shown that while a delta
>7mm per event is possible, jumping _by_ 7mm between two events is unlikely
and indicates a pointer jump. So let's diff the most recent delta and the
current delta, if it increases by 7mm between two event frames let's say it's
a pointer jump and discard it.

Helps with but does not fully resolve:
#80
#36Signed-off-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
parent 02c9c240
Pipeline #3325 passed with stages
in 7 minutes and 54 seconds
......@@ -1440,8 +1440,9 @@ tp_detect_jumps(const struct tp_dispatch *tp, struct tp_touch *t)
{
struct device_coords delta;
struct phys_coords mm;
const int JUMP_THRESHOLD_MM = 20;
struct tp_history_point *last;
double distance;
bool is_jump = false;
/* We haven't seen pointer jumps on Wacom tablets yet, so exclude
* those.
......@@ -1449,8 +1450,10 @@ tp_detect_jumps(const struct tp_dispatch *tp, struct tp_touch *t)
if (tp->device->model_flags & EVDEV_MODEL_WACOM_TOUCHPAD)
return false;
if (t->history.count == 0)
if (t->history.count == 0) {
t->jumps.last_delta_mm = 0.0;
return false;
}
/* called before tp_motion_history_push, so offset 0 is the most
* recent coordinate */
......@@ -1459,7 +1462,17 @@ tp_detect_jumps(const struct tp_dispatch *tp, struct tp_touch *t)
delta.y = abs(t->point.y - last->point.y);
mm = evdev_device_unit_delta_to_mm(tp->device, &delta);
return hypot(mm.x, mm.y) > JUMP_THRESHOLD_MM;
distance = hypot(mm.x, mm.y);
/* Cursor jump if:
* - current single-event delta is >20mm, or
* - we increased the delta by over 7mm within a frame.
*/
is_jump = distance > 20.0 ||
(distance - t->jumps.last_delta_mm) > 7;
t->jumps.last_delta_mm = distance;
return is_jump;
}
static void
......
......@@ -176,6 +176,10 @@ struct tp_touch {
unsigned int count;
} history;
struct {
double last_delta_mm;
} jumps;
struct {
struct device_coords center;
uint8_t x_motion_history;
......
......@@ -5540,6 +5540,8 @@ START_TEST(touchpad_jump_finger_motion)
litest_touch_move_to(dev, 0, 20, 30, 90, 30, 10, 0);
litest_drain_events(li);
/* this test uses a specific test device to trigger a >20mm jump to
* test jumps. These numbers may not work on any other device */
litest_disable_log_handler(li);
litest_touch_move_to(dev, 0, 90, 30, 20, 80, 1, 0);
litest_assert_empty_queue(li);
......@@ -5566,6 +5568,46 @@ START_TEST(touchpad_jump_finger_motion)
}
END_TEST
START_TEST(touchpad_jump_delta)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
litest_touch_down(dev, 0, 20, 30);
litest_touch_move_to(dev, 0, 20, 30, 90, 30, 10, 0);
litest_drain_events(li);
/* this test uses a specific test device to trigger a >7mm but <20mm
* jump to test the delta jumps. These numbers may not work on any
* other device */
litest_disable_log_handler(li);
litest_touch_move_to(dev, 0, 90, 30, 90, 80, 1, 0);
litest_assert_empty_queue(li);
litest_restore_log_handler(li);
litest_touch_move_to(dev, 0, 90, 80, 91, 81, 10, 0);
litest_touch_up(dev, 0);
/* expect lots of little events, no big jump */
libinput_dispatch(li);
event = libinput_get_event(li);
do {
double dx, dy;
ptrev = litest_is_motion_event(event);
dx = libinput_event_pointer_get_dx(ptrev);
dy = libinput_event_pointer_get_dy(ptrev);
ck_assert_int_lt(abs((int)dx), 20);
ck_assert_int_lt(abs((int)dy), 20);
libinput_event_destroy(event);
event = libinput_get_event(li);
} while (event != NULL);
}
END_TEST
START_TEST(touchpad_disabled_on_mouse)
{
struct litest_device *dev = litest_current_device();
......@@ -6749,6 +6791,7 @@ TEST_COLLECTION(touchpad)
litest_add("touchpad:time", touchpad_time_usec, LITEST_TOUCHPAD, LITEST_ANY);
litest_add_for_device("touchpad:jumps", touchpad_jump_finger_motion, LITEST_SYNAPTICS_CLICKPAD_X220);
litest_add_for_device("touchpad:jumps", touchpad_jump_delta, LITEST_SYNAPTICS_CLICKPAD_X220);
litest_add_for_device("touchpad:sendevents", touchpad_disabled_on_mouse, LITEST_SYNAPTICS_CLICKPAD_X220);
litest_add_for_device("touchpad:sendevents", touchpad_disabled_on_mouse_suspend_mouse, LITEST_SYNAPTICS_CLICKPAD_X220);
......
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