touchpad: make tp_detect_jumps() time-independent
authorPeter Hutterer <peter.hutterer@who-t.net>
Mon, 27 Aug 2018 02:35:27 +0000 (12:35 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 30 Aug 2018 22:47:57 +0000 (08:47 +1000)
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>
src/evdev-mt-touchpad.c
src/evdev.c
src/evdev.h

index 53e3c22..200ce83 100644 (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"
index 9395578..c3c43b7 100644 (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;
 }
 
index 81d9a5f..2c72a88 100644 (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),