From 14baf58e3746bc07c1c290fb673b5723d45eb077 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 18 Jan 2016 17:04:39 +1000 Subject: [PATCH 1/4] touchpad: don't try to unhover touches if nothing changed If the touch hasn't updated, the distance hasn't changed so there is no need to unhover. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 6f834fb1..62087fb0 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -743,6 +743,9 @@ tp_unhover_abs_distance(struct tp_dispatch *tp, uint64_t time) for (i = 0; i < tp->ntouches; i++) { t = tp_get_touch(tp, i); + if (!t->dirty) + continue; + if (t->state == TOUCH_HOVERING) { if (t->distance == 0) { /* avoid jumps when landing a finger */ From d19307f20d536cb7a5a402e0387a1aeb81ecec89 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 22 Jan 2016 11:36:40 +1000 Subject: [PATCH 2/4] test: when moving 2 fingers, move them in the same frame More accurate representation of what we actually want to do. Plus it avoids weird test case failures in semi-mt where we always pick the t/l and b/r touches for the bounding box. That is the proper behavior for semi-mt, but it's not for the tests where we expect simultaneous finger movement. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/litest.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/litest.c b/test/litest.c index cc348e9e..1551dc74 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1500,18 +1500,22 @@ litest_touch_move_two_touches(struct litest_device *d, int steps, int sleep_ms) { for (int i = 0; i < steps - 1; i++) { + litest_push_event_frame(d); litest_touch_move(d, 0, x0 + dx / steps * i, y0 + dy / steps * i); litest_touch_move(d, 1, x1 + dx / steps * i, y1 + dy / steps * i); + litest_pop_event_frame(d); if (sleep_ms) { libinput_dispatch(d->libinput); msleep(sleep_ms); } libinput_dispatch(d->libinput); } + litest_push_event_frame(d); litest_touch_move(d, 0, x0 + dx, y0 + dy); litest_touch_move(d, 1, x1 + dx, y1 + dy); + litest_pop_event_frame(d); } void From 342bc510164e89d7c9a742406fb98f9deabf5c8f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 19 Jan 2016 09:05:31 +1000 Subject: [PATCH 3/4] touchpad: disable MT for all semi-mt devices Synaptics, Elantech and Alps semi-mt devices all have issues with reporting correct MT data, even the bounding box which semi-mt devices are supposed to report is wrong. Synaptics devices have massive jumps with two fingers down. Elantech devices may open slots without coordinate data. Alps devices may send 0/0 coordinates as initial slot position. All these may be addressable with specific quirks, but the actual benefit is largely restricted to better palm detection (though even with quirks this is unlikely to work) and support for pinch gestures (again, lack of coordinates makes supporting those hard anyway). Elantech: https://bugs.freedesktop.org/show_bug.cgi?id=93583 Alps: https://bugzilla.redhat.com/show_bug.cgi?id=1295073 Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-gestures.c | 43 ++++++++------------------------ src/evdev-mt-touchpad.c | 21 ++++++++++------ test/gestures.c | 2 +- test/litest.h | 10 -------- test/touchpad-tap.c | 2 +- 5 files changed, 26 insertions(+), 52 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 80aa89ff..53a71495 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -184,18 +184,7 @@ tp_gesture_get_direction(struct tp_dispatch *tp, struct tp_touch *touch) { struct normalized_coords normalized; struct device_float_coords delta; - double move_threshold; - - /* - * Semi-mt touchpads have somewhat inaccurate coordinates when - * 2 fingers are down, so use a slightly larger threshold. - * Elantech semi-mt touchpads are accurate enough though. - */ - if (tp->semi_mt && - (tp->device->model_flags & EVDEV_MODEL_ELANTECH_TOUCHPAD) == 0) - move_threshold = TP_MM_TO_DPI_NORMALIZED(4); - else - move_threshold = TP_MM_TO_DPI_NORMALIZED(1); + double move_threshold = TP_MM_TO_DPI_NORMALIZED(1); delta = device_delta(touch->point, touch->gesture.initial); @@ -221,11 +210,7 @@ tp_gesture_get_pinch_info(struct tp_dispatch *tp, delta = device_delta(first->point, second->point); normalized = tp_normalize_delta(tp, delta); *distance = normalized_length(normalized); - - if (!tp->semi_mt) - *angle = atan2(normalized.y, normalized.x) * 180.0 / M_PI; - else - *angle = 0.0; + *angle = atan2(normalized.y, normalized.x) * 180.0 / M_PI; *center = device_average(first->point, second->point); } @@ -260,6 +245,9 @@ tp_gesture_twofinger_handle_state_none(struct tp_dispatch *tp, uint64_t time) first->gesture.initial = first->point; second->gesture.initial = second->point; + if (!tp->gesture.enabled) + return GESTURE_2FG_STATE_SCROLL; + return GESTURE_2FG_STATE_UNKNOWN; } @@ -297,7 +285,7 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) ((dir2 & 0x80) && (dir1 & 0x01))) { tp_gesture_set_scroll_buildup(tp); return GESTURE_2FG_STATE_SCROLL; - } else if (tp->gesture.enabled) { + } else { tp_gesture_get_pinch_info(tp, &tp->gesture.initial_distance, &tp->gesture.angle, @@ -317,16 +305,7 @@ tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_2FG) return GESTURE_2FG_STATE_SCROLL; - /* On some semi-mt models slot 0 is more accurate, so for semi-mt - * we only use slot 0. */ - if (tp->semi_mt) { - if (!tp->touches[0].dirty) - return GESTURE_2FG_STATE_SCROLL; - - delta = tp_get_delta(&tp->touches[0]); - } else { - delta = tp_get_average_touches_delta(tp); - } + delta = tp_get_average_touches_delta(tp); /* scroll is not accelerated */ delta = tp_filter_motion_unaccelerated(tp, &delta, time); @@ -568,10 +547,10 @@ tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time) int tp_init_gesture(struct tp_dispatch *tp) { - if (tp->device->model_flags & EVDEV_MODEL_JUMPING_SEMI_MT) - tp->gesture.enabled = false; - else - tp->gesture.enabled = true; + /* two-finger scrolling is always enabled, this flag just + * decides whether we detect pinch. semi-mt devices are too + * unreliable to do pinch gestures. */ + tp->gesture.enabled = !tp->semi_mt; tp->gesture.twofinger_state = GESTURE_2FG_STATE_NONE; diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 62087fb0..7f5bbf53 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1490,17 +1490,22 @@ tp_init_slots(struct tp_dispatch *tp, tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT); - /* This device has a terrible resolution when two fingers are down, + /* Semi-mt devices are not reliable for true multitouch data, so we + * simply pretend they're single touch touchpads with BTN_TOOL bits. + * Synaptics: + * Terrible resolution when two fingers are down, * causing scroll jumps. The single-touch emulation ABS_X/Y is * accurate but the ABS_MT_POSITION touchpoints report the bounding - * box and that causes jumps. So we simply pretend it's a single - * touch touchpad with the BTN_TOOL bits. - * See https://bugzilla.redhat.com/show_bug.cgi?id=1235175 for an - * explanation. + * box and that causes jumps. See https://bugzilla.redhat.com/1235175 + * Elantech: + * On three-finger taps/clicks, one slot doesn't get a coordinate + * assigned. See https://bugs.freedesktop.org/show_bug.cgi?id=93583 + * Alps: + * If three fingers are set down in the same frame, one slot has the + * coordinates 0/0 and may not get updated for several frames. + * See https://bugzilla.redhat.com/show_bug.cgi?id=1295073 */ - if (tp->semi_mt && - (device->model_flags & - (EVDEV_MODEL_JUMPING_SEMI_MT|EVDEV_MODEL_ELANTECH_TOUCHPAD))) { + if (tp->semi_mt) { tp->num_slots = 1; tp->slot = 0; tp->has_mt = false; diff --git a/test/gestures.c b/test/gestures.c index 9fc73b97..0fc3964d 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -34,7 +34,7 @@ START_TEST(gestures_cap) struct litest_device *dev = litest_current_device(); struct libinput_device *device = dev->libinput_device; - if (litest_is_synaptics_semi_mt(dev)) + if (libevdev_has_property(dev->evdev, INPUT_PROP_SEMI_MT)) ck_assert(!libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_GESTURE)); else diff --git a/test/litest.h b/test/litest.h index e74e923b..61b1b019 100644 --- a/test/litest.h +++ b/test/litest.h @@ -552,16 +552,6 @@ litest_enable_buttonareas(struct litest_device *dev) litest_assert_int_eq(status, expected); } -static inline int -litest_is_synaptics_semi_mt(struct litest_device *dev) -{ - struct libevdev *evdev = dev->evdev; - - return libevdev_has_property(evdev, INPUT_PROP_SEMI_MT) && - libevdev_get_id_vendor(evdev) == 0x2 && - libevdev_get_id_product(evdev) == 0x7; -} - static inline void litest_enable_drag_lock(struct libinput_device *device) { diff --git a/test/touchpad-tap.c b/test/touchpad-tap.c index 4450ec35..7a7e64ca 100644 --- a/test/touchpad-tap.c +++ b/test/touchpad-tap.c @@ -241,7 +241,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_2fg) int range = _i, ntaps; - if (litest_is_synaptics_semi_mt(dev)) + if (libevdev_has_property(dev->evdev, INPUT_PROP_SEMI_MT)) return; litest_enable_tap(dev->libinput_device); From 28205d6f29f9661d19a805640d98bdc61210c506 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 22 Jan 2016 10:08:56 +1000 Subject: [PATCH 4/4] touchpad: disable gestures for single-finger touchpads No point trying to detect pinch gestures if we only have one set of coordinates. This makes two-finger scrolling on ST touchpads more reactive. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-gestures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 53a71495..bec06931 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -550,7 +550,7 @@ tp_init_gesture(struct tp_dispatch *tp) /* two-finger scrolling is always enabled, this flag just * decides whether we detect pinch. semi-mt devices are too * unreliable to do pinch gestures. */ - tp->gesture.enabled = !tp->semi_mt; + tp->gesture.enabled = !tp->semi_mt && tp->num_slots > 1; tp->gesture.twofinger_state = GESTURE_2FG_STATE_NONE;