From ba062a61a97d965d65673cbc493ab121c4720bc5 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Tue, 19 Jan 2016 15:10:21 +0100 Subject: [PATCH 01/25] gitignore: ignore compile script generated by automake >= 1.14 Signed-off-by: Peter Hutterer --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8893a5fe..ba5d0f53 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ Makefile Makefile.in aclocal.m4 autom4te.cache/ +compile config.guess config.h config.h.in From 82335b0ab91db7965cd25f1a7e1666f27f9f47cd Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 20 Jan 2016 12:56:08 +1000 Subject: [PATCH 02/25] test: fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit litest-selftest.c: In function ‘litest_ptr_eq_notrigger’: litest-selftest.c:172:10: warning: initialization makes integer from pointer without a cast [-Wint-conversion] int c = NULL; ^ litest-selftest.c:173:10: warning: initialization makes integer from pointer without a cast [-Wint-conversion] int d = NULL; ^ Signed-off-by: Peter Hutterer --- test/litest-selftest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/litest-selftest.c b/test/litest-selftest.c index 5016514d..47d5ef13 100644 --- a/test/litest-selftest.c +++ b/test/litest-selftest.c @@ -169,8 +169,8 @@ START_TEST(litest_ptr_eq_notrigger) int v = 10; int *a = &v; int *b = &v; - int c = NULL; - int d = NULL; + int *c = NULL; + int *d = NULL; litest_assert_ptr_eq(a, b); litest_assert_ptr_eq(c, d); From 99287a5245b0050c65ecd802525a07b82e25c04f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 10:30:46 +1000 Subject: [PATCH 03/25] gestures: split direction check out into a helper function Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 80aa89ff..064797fe 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -263,6 +263,22 @@ tp_gesture_twofinger_handle_state_none(struct tp_dispatch *tp, uint64_t time) return GESTURE_2FG_STATE_UNKNOWN; } +static inline int +tp_gesture_same_directions(int dir1, int dir2) +{ + /* + * In some cases (semi-mt touchpads) we may seen one finger move + * e.g. N/NE and the other W/NW so we not only check for overlapping + * directions, but also for neighboring bits being set. + * The ((dira & 0x80) && (dirb & 0x01)) checks are to check for bit 0 + * and 7 being set as they also represent neighboring directions. + */ + return ((dir1 | (dir1 >> 1)) & dir2) || + ((dir2 | (dir2 >> 1)) & dir1) || + ((dir1 & 0x80) && (dir2 & 0x01)) || + ((dir2 & 0x80) && (dir1 & 0x01)); +} + static enum tp_gesture_2fg_state tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) { @@ -282,19 +298,8 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) if (dir1 == UNDEFINED_DIRECTION || dir2 == UNDEFINED_DIRECTION) return GESTURE_2FG_STATE_UNKNOWN; - /* - * If both touches are moving in the same direction assume scroll. - * - * In some cases (semi-mt touchpads) We may seen one finger move - * e.g. N/NE and the other W/NW so we not only check for overlapping - * directions, but also for neighboring bits being set. - * The ((dira & 0x80) && (dirb & 0x01)) checks are to check for bit 0 - * and 7 being set as they also represent neighboring directions. - */ - if (((dir1 | (dir1 >> 1)) & dir2) || - ((dir2 | (dir2 >> 1)) & dir1) || - ((dir1 & 0x80) && (dir2 & 0x01)) || - ((dir2 & 0x80) && (dir1 & 0x01))) { + /* If both touches are moving in the same direction assume scroll */ + if (tp_gesture_same_directions(dir1, dir2)) { tp_gesture_set_scroll_buildup(tp); return GESTURE_2FG_STATE_SCROLL; } else if (tp->gesture.enabled) { From e510bef3f2566b82f0f7c1ad52d1ec4cb9768622 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 11:40:42 +1000 Subject: [PATCH 04/25] gestures: drop 2fg naming from the various states When adding 3+ finger gestures, there isn't much specific state left that's 2-finger only. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 90 ++++++++++++++++---------------- src/evdev-mt-touchpad.h | 12 ++--- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 064797fe..a7ef72f7 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -33,13 +33,13 @@ #define DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT ms2us(500) static inline const char* -gesture_state_to_str(enum tp_gesture_2fg_state state) +gesture_state_to_str(enum tp_gesture_state state) { switch (state) { - CASE_RETURN_STRING(GESTURE_2FG_STATE_NONE); - CASE_RETURN_STRING(GESTURE_2FG_STATE_UNKNOWN); - CASE_RETURN_STRING(GESTURE_2FG_STATE_SCROLL); - CASE_RETURN_STRING(GESTURE_2FG_STATE_PINCH); + CASE_RETURN_STRING(GESTURE_STATE_NONE); + CASE_RETURN_STRING(GESTURE_STATE_UNKNOWN); + CASE_RETURN_STRING(GESTURE_STATE_SCROLL); + CASE_RETURN_STRING(GESTURE_STATE_PINCH); } return NULL; } @@ -96,17 +96,17 @@ tp_gesture_start(struct tp_dispatch *tp, uint64_t time) switch (tp->gesture.finger_count) { case 2: - switch (tp->gesture.twofinger_state) { - case GESTURE_2FG_STATE_NONE: - case GESTURE_2FG_STATE_UNKNOWN: + switch (tp->gesture.state) { + case GESTURE_STATE_NONE: + case GESTURE_STATE_UNKNOWN: log_bug_libinput(libinput, "%s in unknown gesture mode\n", __func__); break; - case GESTURE_2FG_STATE_SCROLL: + case GESTURE_STATE_SCROLL: /* NOP */ break; - case GESTURE_2FG_STATE_PINCH: + case GESTURE_STATE_PINCH: gesture_notify_pinch(&tp->device->base, time, LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, &zero, &zero, 1.0, 0.0); @@ -245,13 +245,13 @@ tp_gesture_set_scroll_buildup(struct tp_dispatch *tp) tp->device->scroll.buildup = tp_normalize_delta(tp, average); } -static enum tp_gesture_2fg_state +static enum tp_gesture_state tp_gesture_twofinger_handle_state_none(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *first, *second; if (tp_gesture_get_active_touches(tp, tp->gesture.touches, 2) != 2) - return GESTURE_2FG_STATE_NONE; + return GESTURE_STATE_NONE; first = tp->gesture.touches[0]; second = tp->gesture.touches[1]; @@ -260,7 +260,7 @@ tp_gesture_twofinger_handle_state_none(struct tp_dispatch *tp, uint64_t time) first->gesture.initial = first->point; second->gesture.initial = second->point; - return GESTURE_2FG_STATE_UNKNOWN; + return GESTURE_STATE_UNKNOWN; } static inline int @@ -279,7 +279,7 @@ tp_gesture_same_directions(int dir1, int dir2) ((dir2 & 0x80) && (dir1 & 0x01)); } -static enum tp_gesture_2fg_state +static enum tp_gesture_state tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *first = tp->gesture.touches[0], @@ -289,44 +289,44 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) /* if fingers stay unmoving for a while, assume (slow) scroll */ if (time > (tp->gesture.initial_time + DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT)) { tp_gesture_set_scroll_buildup(tp); - return GESTURE_2FG_STATE_SCROLL; + return GESTURE_STATE_SCROLL; } /* Else wait for both fingers to have moved */ dir1 = tp_gesture_get_direction(tp, first); dir2 = tp_gesture_get_direction(tp, second); if (dir1 == UNDEFINED_DIRECTION || dir2 == UNDEFINED_DIRECTION) - return GESTURE_2FG_STATE_UNKNOWN; + return GESTURE_STATE_UNKNOWN; /* If both touches are moving in the same direction assume scroll */ if (tp_gesture_same_directions(dir1, dir2)) { tp_gesture_set_scroll_buildup(tp); - return GESTURE_2FG_STATE_SCROLL; + return GESTURE_STATE_SCROLL; } else if (tp->gesture.enabled) { tp_gesture_get_pinch_info(tp, &tp->gesture.initial_distance, &tp->gesture.angle, &tp->gesture.center); tp->gesture.prev_scale = 1.0; - return GESTURE_2FG_STATE_PINCH; + return GESTURE_STATE_PINCH; } - return GESTURE_2FG_STATE_UNKNOWN; + return GESTURE_STATE_UNKNOWN; } -static enum tp_gesture_2fg_state +static enum tp_gesture_state tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) { struct normalized_coords delta; if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_2FG) - return GESTURE_2FG_STATE_SCROLL; + return GESTURE_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; + return GESTURE_STATE_SCROLL; delta = tp_get_delta(&tp->touches[0]); } else { @@ -337,7 +337,7 @@ tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) delta = tp_filter_motion_unaccelerated(tp, &delta, time); if (normalized_is_zero(delta)) - return GESTURE_2FG_STATE_SCROLL; + return GESTURE_STATE_SCROLL; tp_gesture_start(tp, time); evdev_post_scroll(tp->device, @@ -345,10 +345,10 @@ tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) LIBINPUT_POINTER_AXIS_SOURCE_FINGER, &delta); - return GESTURE_2FG_STATE_SCROLL; + return GESTURE_STATE_SCROLL; } -static enum tp_gesture_2fg_state +static enum tp_gesture_state tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) { double angle, angle_delta, distance, scale; @@ -373,7 +373,7 @@ tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) if (normalized_is_zero(delta) && normalized_is_zero(unaccel) && scale == tp->gesture.prev_scale && angle_delta == 0.0) - return GESTURE_2FG_STATE_PINCH; + return GESTURE_STATE_PINCH; tp_gesture_start(tp, time); gesture_notify_pinch(&tp->device->base, time, @@ -382,34 +382,34 @@ tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) tp->gesture.prev_scale = scale; - return GESTURE_2FG_STATE_PINCH; + return GESTURE_STATE_PINCH; } static void tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time) { - enum tp_gesture_2fg_state oldstate = tp->gesture.twofinger_state; + enum tp_gesture_state oldstate = tp->gesture.state; - if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_NONE) - tp->gesture.twofinger_state = + if (tp->gesture.state == GESTURE_STATE_NONE) + tp->gesture.state = tp_gesture_twofinger_handle_state_none(tp, time); - if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_UNKNOWN) - tp->gesture.twofinger_state = + if (tp->gesture.state == GESTURE_STATE_UNKNOWN) + tp->gesture.state = tp_gesture_twofinger_handle_state_unknown(tp, time); - if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_SCROLL) - tp->gesture.twofinger_state = + if (tp->gesture.state == GESTURE_STATE_SCROLL) + tp->gesture.state = tp_gesture_twofinger_handle_state_scroll(tp, time); - if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_PINCH) - tp->gesture.twofinger_state = + if (tp->gesture.state == GESTURE_STATE_PINCH) + tp->gesture.state = tp_gesture_twofinger_handle_state_pinch(tp, time); log_debug(tp_libinput_context(tp), "gesture state: %s → %s\n", gesture_state_to_str(oldstate), - gesture_state_to_str(tp->gesture.twofinger_state)); + gesture_state_to_str(tp->gesture.state)); } static void @@ -475,26 +475,26 @@ static void tp_gesture_end(struct tp_dispatch *tp, uint64_t time, bool cancelled) { struct libinput *libinput = tp->device->base.seat->libinput; - enum tp_gesture_2fg_state twofinger_state = tp->gesture.twofinger_state; + enum tp_gesture_state state = tp->gesture.state; - tp->gesture.twofinger_state = GESTURE_2FG_STATE_NONE; + tp->gesture.state = GESTURE_STATE_NONE; if (!tp->gesture.started) return; switch (tp->gesture.finger_count) { case 2: - switch (twofinger_state) { - case GESTURE_2FG_STATE_NONE: - case GESTURE_2FG_STATE_UNKNOWN: + switch (state) { + case GESTURE_STATE_NONE: + case GESTURE_STATE_UNKNOWN: log_bug_libinput(libinput, "%s in unknown gesture mode\n", __func__); break; - case GESTURE_2FG_STATE_SCROLL: + case GESTURE_STATE_SCROLL: tp_gesture_stop_twofinger_scroll(tp, time); break; - case GESTURE_2FG_STATE_PINCH: + case GESTURE_STATE_PINCH: gesture_notify_pinch_end(&tp->device->base, time, tp->gesture.prev_scale, cancelled); @@ -578,7 +578,7 @@ tp_init_gesture(struct tp_dispatch *tp) else tp->gesture.enabled = true; - tp->gesture.twofinger_state = GESTURE_2FG_STATE_NONE; + tp->gesture.state = GESTURE_STATE_NONE; libinput_timer_init(&tp->gesture.finger_count_switch_timer, tp->device->base.seat->libinput, diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index f42fb02d..9cc11ac0 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -130,11 +130,11 @@ enum tp_edge_scroll_touch_state { EDGE_SCROLL_TOUCH_STATE_AREA, }; -enum tp_gesture_2fg_state { - GESTURE_2FG_STATE_NONE, - GESTURE_2FG_STATE_UNKNOWN, - GESTURE_2FG_STATE_SCROLL, - GESTURE_2FG_STATE_PINCH, +enum tp_gesture_state { + GESTURE_STATE_NONE, + GESTURE_STATE_UNKNOWN, + GESTURE_STATE_SCROLL, + GESTURE_STATE_PINCH, }; enum tp_thumb_state { @@ -252,7 +252,7 @@ struct tp_dispatch { unsigned int finger_count; unsigned int finger_count_pending; struct libinput_timer finger_count_switch_timer; - enum tp_gesture_2fg_state twofinger_state; + enum tp_gesture_state state; struct tp_touch *touches[2]; uint64_t initial_time; double initial_distance; From c96d11e531bece3487eaff01be9709ace8dbad0f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 13:04:58 +1000 Subject: [PATCH 05/25] touchpad: constify a couple of helper functions Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 27 ++++++++++++++++++--------- src/evdev-mt-touchpad-edge-scroll.c | 5 +++-- src/evdev-mt-touchpad-gestures.c | 2 +- src/evdev-mt-touchpad-tap.c | 2 +- src/evdev-mt-touchpad.c | 4 ++-- src/evdev-mt-touchpad.h | 19 +++++++++++-------- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 8822e08c..82c99c76 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -78,47 +78,54 @@ button_event_to_str(enum button_event event) { } static inline bool -is_inside_bottom_button_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_bottom_button_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return t->point.y >= tp->buttons.bottom_area.top_edge; } static inline bool -is_inside_bottom_right_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_bottom_right_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return is_inside_bottom_button_area(tp, t) && t->point.x > tp->buttons.bottom_area.rightbutton_left_edge; } static inline bool -is_inside_bottom_left_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_bottom_left_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return is_inside_bottom_button_area(tp, t) && !is_inside_bottom_right_area(tp, t); } static inline bool -is_inside_top_button_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_top_button_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return t->point.y <= tp->buttons.top_area.bottom_edge; } static inline bool -is_inside_top_right_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_top_right_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return is_inside_top_button_area(tp, t) && t->point.x > tp->buttons.top_area.rightbutton_left_edge; } static inline bool -is_inside_top_left_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_top_left_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return is_inside_top_button_area(tp, t) && t->point.x < tp->buttons.top_area.leftbutton_right_edge; } static inline bool -is_inside_top_middle_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_top_middle_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return is_inside_top_button_area(tp, t) && t->point.x >= tp->buttons.top_area.leftbutton_right_edge && @@ -1042,13 +1049,15 @@ tp_post_button_events(struct tp_dispatch *tp, uint64_t time) } int -tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t) +tp_button_touch_active(const struct tp_dispatch *tp, + const struct tp_touch *t) { return t->button.state == BUTTON_STATE_AREA; } bool -tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t) +tp_button_is_inside_softbutton_area(const struct tp_dispatch *tp, + const struct tp_touch *t) { return is_inside_top_button_area(tp, t) || is_inside_bottom_button_area(tp, t); diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index b572a9fb..fcc05121 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -73,7 +73,7 @@ edge_event_to_str(enum scroll_event event) } uint32_t -tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *t) +tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t) { uint32_t edge = EDGE_NONE; @@ -455,7 +455,8 @@ tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time) } int -tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t) +tp_edge_scroll_touch_active(const struct tp_dispatch *tp, + const struct tp_touch *t) { return t->scroll.edge_state == EDGE_SCROLL_TOUCH_STATE_AREA; } diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index a7ef72f7..fc51c547 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -148,7 +148,7 @@ tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) } static unsigned int -tp_gesture_get_active_touches(struct tp_dispatch *tp, +tp_gesture_get_active_touches(const struct tp_dispatch *tp, struct tp_touch **touches, unsigned int count) { diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index dda528a8..a4c38a81 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -1022,7 +1022,7 @@ tp_tap_resume(struct tp_dispatch *tp, uint64_t time) } bool -tp_tap_dragging(struct tp_dispatch *tp) +tp_tap_dragging(const struct tp_dispatch *tp) { switch (tp->tap.state) { case TAP_STATE_DRAGGING: diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index d78a54b0..b2461fd0 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -510,7 +510,7 @@ tp_pin_fingers(struct tp_dispatch *tp) } int -tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) +tp_touch_active(const struct tp_dispatch *tp, const struct tp_touch *t) { return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) && t->palm.state == PALM_NONE && @@ -521,7 +521,7 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) } bool -tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t) +tp_palm_tap_is_palm(const struct tp_dispatch *tp, const struct tp_touch *t) { if (t->state != TOUCH_BEGIN) return false; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 9cc11ac0..690feb55 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -358,7 +358,7 @@ struct tp_dispatch { for (unsigned int _i = 0; _i < (_tp)->ntouches && (_t = &(_tp)->touches[_i]); _i++) static inline struct libinput* -tp_libinput_context(struct tp_dispatch *tp) +tp_libinput_context(const struct tp_dispatch *tp) { return tp->device->base.seat->libinput; } @@ -402,7 +402,7 @@ tp_filter_motion_unaccelerated(struct tp_dispatch *tp, uint64_t time); int -tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t); +tp_touch_active(const struct tp_dispatch *tp, const struct tp_touch *t); int tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time); @@ -440,10 +440,12 @@ int tp_button_handle_state(struct tp_dispatch *tp, uint64_t time); int -tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t); +tp_button_touch_active(const struct tp_dispatch *tp, + const struct tp_touch *t); bool -tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t); +tp_button_is_inside_softbutton_area(const struct tp_dispatch *tp, + const struct tp_touch *t); void tp_release_all_taps(struct tp_dispatch *tp, @@ -456,7 +458,7 @@ void tp_tap_resume(struct tp_dispatch *tp, uint64_t time); bool -tp_tap_dragging(struct tp_dispatch *tp); +tp_tap_dragging(const struct tp_dispatch *tp); int tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device); @@ -474,10 +476,11 @@ void tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time); int -tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t); +tp_edge_scroll_touch_active(const struct tp_dispatch *tp, + const struct tp_touch *t); uint32_t -tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *t); +tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t); int tp_init_gesture(struct tp_dispatch *tp); @@ -501,6 +504,6 @@ void tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time); bool -tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t); +tp_palm_tap_is_palm(const struct tp_dispatch *tp, const struct tp_touch *t); #endif From 585deda799a8c9cf93125aa18fa17f54d795e81b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 13:57:03 +1000 Subject: [PATCH 06/25] gestures: pass the finger count into pinch events Prep work for multifinger pinch gestures Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 3 +++ src/libinput-private.h | 2 ++ src/libinput.c | 8 +++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index fc51c547..c676caac 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -109,6 +109,7 @@ tp_gesture_start(struct tp_dispatch *tp, uint64_t time) case GESTURE_STATE_PINCH: gesture_notify_pinch(&tp->device->base, time, LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + tp->gesture.finger_count, &zero, &zero, 1.0, 0.0); break; } @@ -378,6 +379,7 @@ tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) tp_gesture_start(tp, time); gesture_notify_pinch(&tp->device->base, time, LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + tp->gesture.finger_count, &delta, &unaccel, scale, angle_delta); tp->gesture.prev_scale = scale; @@ -496,6 +498,7 @@ tp_gesture_end(struct tp_dispatch *tp, uint64_t time, bool cancelled) break; case GESTURE_STATE_PINCH: gesture_notify_pinch_end(&tp->device->base, time, + tp->gesture.finger_count, tp->gesture.prev_scale, cancelled); break; diff --git a/src/libinput-private.h b/src/libinput-private.h index e146c260..efffe35c 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -429,6 +429,7 @@ void gesture_notify_pinch(struct libinput_device *device, uint64_t time, enum libinput_event_type type, + int finger_count, const struct normalized_coords *delta, const struct normalized_coords *unaccel, double scale, @@ -437,6 +438,7 @@ gesture_notify_pinch(struct libinput_device *device, void gesture_notify_pinch_end(struct libinput_device *device, uint64_t time, + int finger_count, double scale, int cancelled); diff --git a/src/libinput.c b/src/libinput.c index 24f2b693..756edfad 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1673,25 +1673,27 @@ void gesture_notify_pinch(struct libinput_device *device, uint64_t time, enum libinput_event_type type, + int finger_count, const struct normalized_coords *delta, const struct normalized_coords *unaccel, double scale, double angle) { - gesture_notify(device, time, type, 2, 0, delta, unaccel, - scale, angle); + gesture_notify(device, time, type, finger_count, 0, + delta, unaccel, scale, angle); } void gesture_notify_pinch_end(struct libinput_device *device, uint64_t time, + int finger_count, double scale, int cancelled) { const struct normalized_coords zero = { 0.0, 0.0 }; gesture_notify(device, time, LIBINPUT_EVENT_GESTURE_PINCH_END, - 2, cancelled, &zero, &zero, scale, 0.0); + finger_count, cancelled, &zero, &zero, scale, 0.0); } static void From 02ca5556b4e11821be837b6a6fd002663b1fd716 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 14:27:04 +1000 Subject: [PATCH 07/25] test: remove leftover debug_trace statement Signed-off-by: Peter Hutterer --- test/gestures.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/gestures.c b/test/gestures.c index 9fc73b97..39be36c5 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -110,7 +110,6 @@ START_TEST(gestures_swipe_3fg) dx = libinput_event_gesture_get_dx(gevent); dy = libinput_event_gesture_get_dy(gevent); - debug_trace("delta: %.2f/%.2f\n", dx, dy); if (dir_x == 0.0) ck_assert(dx == 0.0); else if (dir_x < 0.0) From f8d4c87e1369e1085ac98c826a748fac2523659d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 14:33:26 +1000 Subject: [PATCH 08/25] test: remove a wait loop from the usec gesture test We know we (should) have events when we get here. Signed-off-by: Peter Hutterer --- test/gestures.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/gestures.c b/test/gestures.c index 39be36c5..71c8fd3a 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -375,8 +375,7 @@ START_TEST(gestures_time_usec) 0, 30, 4, 2); - litest_wait_for_event(li); - + libinput_dispatch(li); event = libinput_get_event(li); gevent = litest_is_gesture_event(event, LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, From ff2ee2c681b3e8d4b176c30ad3fafbf1c5c69d6d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 14:39:52 +1000 Subject: [PATCH 09/25] test: run pinch gesture tests for 2-slot touchpads Some of the 2-slot touchpads don't do gestures though (e.g. semi-mt) so skip those. And change the movement granularity for the pinch and spread tests so we stay under one degree angle for lower-resolution touchpads too. Signed-off-by: Peter Hutterer --- test/gestures.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/test/gestures.c b/test/gestures.c index 71c8fd3a..eb2ad816 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -179,7 +179,9 @@ START_TEST(gestures_pinch) { -30, 30 }, }; - if (libevdev_get_num_slots(dev->evdev) < 3) + if (libevdev_get_num_slots(dev->evdev) < 2 || + !libinput_device_has_capability(dev->libinput_device, + LIBINPUT_DEVICE_CAP_GESTURE)) return; dir_x = cardinals[cardinal][0]; @@ -194,13 +196,13 @@ START_TEST(gestures_pinch) for (i = 0; i < 8; i++) { litest_push_event_frame(dev); if (dir_x > 0.0) - dir_x -= 3; + dir_x -= 2; else if (dir_x < 0.0) - dir_x += 3; + dir_x += 2; if (dir_y > 0.0) - dir_y -= 3; + dir_y -= 2; else if (dir_y < 0.0) - dir_y += 3; + dir_y += 2; litest_touch_move(dev, 0, 50 + dir_x, @@ -268,17 +270,19 @@ START_TEST(gestures_spread) double scale, oldscale; double angle; int cardinals[8][2] = { - { 0, 1 }, - { 1, 1 }, - { 1, 0 }, - { 1, -1 }, - { 0, -1 }, - { -1, -1 }, - { -1, 0 }, - { -1, 1 }, + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, }; - if (libevdev_get_num_slots(dev->evdev) < 3) + if (libevdev_get_num_slots(dev->evdev) < 2 || + !libinput_device_has_capability(dev->libinput_device, + LIBINPUT_DEVICE_CAP_GESTURE)) return; dir_x = cardinals[cardinal][0]; From 7d5c35ccd06713d59082b464c7cc579dd2e7c269 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 15:49:02 +1000 Subject: [PATCH 10/25] touchpad: check fake finger count for validity Setting TRIPLETAP unsets DOUBLETAP, etc. This doesn't usually happen with kernel devices, but every once in a while I get this wrong in a test and spend hours debugging the code... Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index b2461fd0..e4821c08 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -140,6 +140,14 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot) static inline unsigned int tp_fake_finger_count(struct tp_dispatch *tp) { + /* Only one of BTN_TOOL_DOUBLETAP/TRIPLETAP/... may be set at any + * time */ + if (__builtin_popcount( + tp->fake_touches & ~(FAKE_FINGER_OVERFLOW|0x1)) > 1) + log_bug_kernel(tp->device->base.seat->libinput, + "Invalid fake finger state %#x\n", + tp->fake_touches); + if (tp->fake_touches & FAKE_FINGER_OVERFLOW) return FAKE_FINGER_OVERFLOW; else /* don't count BTN_TOUCH */ From 1280d638a243009ef2fda90acc16c6ae9d99e585 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 8 Jan 2016 11:06:49 +1000 Subject: [PATCH 11/25] test: rearrange fingers for gesture tests Prep work for the coming patch, arrange the fingers horizontally rather than vertically. Signed-off-by: Peter Hutterer --- test/gestures.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/gestures.c b/test/gestures.c index eb2ad816..c21a4117 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -82,13 +82,13 @@ START_TEST(gestures_swipe_3fg) litest_drain_events(li); litest_touch_down(dev, 0, 40, 40); - litest_touch_down(dev, 1, 40, 50); - litest_touch_down(dev, 2, 40, 60); + litest_touch_down(dev, 1, 50, 40); + litest_touch_down(dev, 2, 60, 40); libinput_dispatch(li); litest_touch_move_three_touches(dev, 40, 40, - 40, 50, - 40, 60, + 50, 40, + 60, 40, dir_x, dir_y, 10, 2); libinput_dispatch(li); @@ -369,13 +369,13 @@ START_TEST(gestures_time_usec) litest_drain_events(li); litest_touch_down(dev, 0, 40, 40); - litest_touch_down(dev, 1, 40, 50); - litest_touch_down(dev, 2, 40, 60); + litest_touch_down(dev, 1, 50, 40); + litest_touch_down(dev, 2, 60, 40); libinput_dispatch(li); litest_touch_move_three_touches(dev, 40, 40, - 40, 50, - 40, 60, + 50, 40, + 60, 40, 0, 30, 4, 2); From d9e1b2603e1c36e262f88c80c7321491656c7836 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 8 Jan 2016 13:45:42 +1000 Subject: [PATCH 12/25] test: change semi-mt 2fg scroll test to use two-finger movement As we implement more gestures, we will drop two-finger scrolling performed by only a single finger movement. Signed-off-by: Peter Hutterer --- test/touchpad.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/touchpad.c b/test/touchpad.c index dab2781e..63b1cb77 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -289,11 +289,11 @@ START_TEST(touchpad_2fg_scroll_semi_mt) litest_touch_down(dev, 0, 20, 20); litest_touch_down(dev, 1, 30, 20); libinput_dispatch(li); - litest_touch_move_to(dev, 1, 30, 20, 30, 70, 10, 5); - - litest_assert_empty_queue(li); - - litest_touch_move_to(dev, 0, 20, 20, 20, 70, 10, 5); + litest_touch_move_two_touches(dev, + 20, 20, + 30, 20, + 30, 40, + 10, 1); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); } From 8234814fe89ab5f945cca1fe7f5012c8c40ba11a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 11:37:20 +1000 Subject: [PATCH 13/25] gestures: add support for three-finger pinch gestures https://bugs.freedesktop.org/show_bug.cgi?id=92834 Signed-off-by: Peter Hutterer --- doc/gestures.dox | 16 ++ doc/svg/pinch-gestures-softbuttons.svg | 365 +++++++++++++++++++++++++ src/evdev-mt-touchpad-gestures.c | 203 ++++++++------ src/evdev-mt-touchpad.h | 1 + 4 files changed, 504 insertions(+), 81 deletions(-) create mode 100644 doc/svg/pinch-gestures-softbuttons.svg diff --git a/doc/gestures.dox b/doc/gestures.dox index 02ef09ab..8632b8e6 100644 --- a/doc/gestures.dox +++ b/doc/gestures.dox @@ -88,4 +88,20 @@ thus suggesting a window movement. libinput only has knowledge of the finger coordinates (and even then only in device coordinates, not in screen coordinates) and thus cannot differentiate the two. +@section gestures_softbuttons Gestures with enabled software buttons + +If the touchpad device is a @ref touchpads_buttons_clickpads "Clickpad", it +is recommended that a caller switches to @ref clickfinger. +Usually fingers placed in a @ref software_buttons "software button area" is not +considered for gestures, resulting in some gestures to be interpreted as +pointer motion or two-finger scroll events. + +@image html pinch-gestures-softbuttons.svg "Interference of software buttons and pinch gestures" + +In the example above, the software button area is highlighted in red. The +user executes a three-finger pinch gesture, with the thumb remaining in the +software button area. libinput ignores fingers within the software button +areas, the movement of the remaining fingers is thus interpreted as a +two-finger scroll motion. + */ diff --git a/doc/svg/pinch-gestures-softbuttons.svg b/doc/svg/pinch-gestures-softbuttons.svg new file mode 100644 index 00000000..959cb4f4 --- /dev/null +++ b/doc/svg/pinch-gestures-softbuttons.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index c676caac..e7b75ac2 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -40,6 +40,7 @@ gesture_state_to_str(enum tp_gesture_state state) CASE_RETURN_STRING(GESTURE_STATE_UNKNOWN); CASE_RETURN_STRING(GESTURE_STATE_SCROLL); CASE_RETURN_STRING(GESTURE_STATE_PINCH); + CASE_RETURN_STRING(GESTURE_STATE_SWIPE); } return NULL; } @@ -94,34 +95,30 @@ tp_gesture_start(struct tp_dispatch *tp, uint64_t time) if (tp->gesture.started) return; - switch (tp->gesture.finger_count) { - case 2: - switch (tp->gesture.state) { - case GESTURE_STATE_NONE: - case GESTURE_STATE_UNKNOWN: - log_bug_libinput(libinput, - "%s in unknown gesture mode\n", - __func__); - break; - case GESTURE_STATE_SCROLL: - /* NOP */ - break; - case GESTURE_STATE_PINCH: - gesture_notify_pinch(&tp->device->base, time, - LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, - tp->gesture.finger_count, - &zero, &zero, 1.0, 0.0); - break; - } + switch (tp->gesture.state) { + case GESTURE_STATE_NONE: + case GESTURE_STATE_UNKNOWN: + log_bug_libinput(libinput, + "%s in unknown gesture mode\n", + __func__); break; - case 3: - case 4: + case GESTURE_STATE_SCROLL: + /* NOP */ + break; + case GESTURE_STATE_PINCH: + gesture_notify_pinch(&tp->device->base, time, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + tp->gesture.finger_count, + &zero, &zero, 1.0, 0.0); + break; + case GESTURE_STATE_SWIPE: gesture_notify_swipe(&tp->device->base, time, LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, tp->gesture.finger_count, &zero, &zero); break; } + tp->gesture.started = true; } @@ -247,19 +244,54 @@ tp_gesture_set_scroll_buildup(struct tp_dispatch *tp) } static enum tp_gesture_state -tp_gesture_twofinger_handle_state_none(struct tp_dispatch *tp, uint64_t time) +tp_gesture_handle_state_none(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *first, *second; + struct tp_touch *touches[4]; + unsigned int ntouches; + unsigned int i; - if (tp_gesture_get_active_touches(tp, tp->gesture.touches, 2) != 2) + ntouches = tp_gesture_get_active_touches(tp, touches, 4); + if (ntouches < 2) return GESTURE_STATE_NONE; - first = tp->gesture.touches[0]; - second = tp->gesture.touches[1]; + first = touches[0]; + second = touches[1]; + + /* For 3+ finger gestures we cheat. A human hand's finger + * arrangement means that for a 3 or 4 finger swipe gesture, the + * fingers are roughly arranged in a horizontal line. + * They will all move in the same direction, so we can simply look + * at the left and right-most ones only. If we have fake touches, we + * just take the left/right-most real touch position, since the fake + * touch has the same location as one of those. + * + * For a 3 or 4 finger pinch gesture, 2 or 3 fingers are roughly in + * a horizontal line, with the thumb below and left (right-handed + * users) or right (left-handed users). Again, the row of non-thumb + * fingers moves identically so we can look at the left and + * right-most only and then treat it like a two-finger + * gesture. + */ + if (ntouches > 2) { + second = touches[0]; + + for (i = 1; i < ntouches && i < tp->num_slots; i++) { + if (touches[i]->point.x < first->point.x) + first = touches[i]; + else if (touches[i]->point.x > second->point.x) + second = touches[i]; + } + + if (first == second) + return GESTURE_STATE_NONE; + } tp->gesture.initial_time = time; first->gesture.initial = first->point; second->gesture.initial = second->point; + tp->gesture.touches[0] = first; + tp->gesture.touches[1] = second; return GESTURE_STATE_UNKNOWN; } @@ -281,14 +313,16 @@ tp_gesture_same_directions(int dir1, int dir2) } static enum tp_gesture_state -tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) +tp_gesture_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *first = tp->gesture.touches[0], *second = tp->gesture.touches[1]; int dir1, dir2; - /* if fingers stay unmoving for a while, assume (slow) scroll */ - if (time > (tp->gesture.initial_time + DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT)) { + /* for two-finger gestures, if the fingers stay unmoving for a + * while, assume (slow) scroll */ + if (tp->gesture.finger_count == 2 && + time > (tp->gesture.initial_time + DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT)) { tp_gesture_set_scroll_buildup(tp); return GESTURE_STATE_SCROLL; } @@ -299,10 +333,15 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) if (dir1 == UNDEFINED_DIRECTION || dir2 == UNDEFINED_DIRECTION) return GESTURE_STATE_UNKNOWN; - /* If both touches are moving in the same direction assume scroll */ + /* If both touches are moving in the same direction assume + * scroll or swipe */ if (tp_gesture_same_directions(dir1, dir2)) { - tp_gesture_set_scroll_buildup(tp); - return GESTURE_STATE_SCROLL; + if (tp->gesture.finger_count == 2) { + tp_gesture_set_scroll_buildup(tp); + return GESTURE_STATE_SCROLL; + } else if (tp->gesture.enabled) { + return GESTURE_STATE_SWIPE; + } } else if (tp->gesture.enabled) { tp_gesture_get_pinch_info(tp, &tp->gesture.initial_distance, @@ -316,7 +355,7 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) } static enum tp_gesture_state -tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) +tp_gesture_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) { struct normalized_coords delta; @@ -350,7 +389,26 @@ tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time) } static enum tp_gesture_state -tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) +tp_gesture_handle_state_swipe(struct tp_dispatch *tp, uint64_t time) +{ + struct normalized_coords delta, unaccel; + + unaccel = tp_get_average_touches_delta(tp); + delta = tp_filter_motion(tp, &unaccel, time); + + if (!normalized_is_zero(delta) || !normalized_is_zero(unaccel)) { + tp_gesture_start(tp, time); + gesture_notify_swipe(&tp->device->base, time, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + tp->gesture.finger_count, + &delta, &unaccel); + } + + return GESTURE_STATE_SWIPE; +} + +static enum tp_gesture_state +tp_gesture_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) { double angle, angle_delta, distance, scale; struct device_float_coords center, fdelta; @@ -388,25 +446,29 @@ tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time) } static void -tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time) +tp_gesture_post_gesture(struct tp_dispatch *tp, uint64_t time) { enum tp_gesture_state oldstate = tp->gesture.state; if (tp->gesture.state == GESTURE_STATE_NONE) tp->gesture.state = - tp_gesture_twofinger_handle_state_none(tp, time); + tp_gesture_handle_state_none(tp, time); if (tp->gesture.state == GESTURE_STATE_UNKNOWN) tp->gesture.state = - tp_gesture_twofinger_handle_state_unknown(tp, time); + tp_gesture_handle_state_unknown(tp, time); if (tp->gesture.state == GESTURE_STATE_SCROLL) tp->gesture.state = - tp_gesture_twofinger_handle_state_scroll(tp, time); + tp_gesture_handle_state_scroll(tp, time); + + if (tp->gesture.state == GESTURE_STATE_SWIPE) + tp->gesture.state = + tp_gesture_handle_state_swipe(tp, time); if (tp->gesture.state == GESTURE_STATE_PINCH) tp->gesture.state = - tp_gesture_twofinger_handle_state_pinch(tp, time); + tp_gesture_handle_state_pinch(tp, time); log_debug(tp_libinput_context(tp), "gesture state: %s → %s\n", @@ -414,23 +476,6 @@ tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time) gesture_state_to_str(tp->gesture.state)); } -static void -tp_gesture_post_swipe(struct tp_dispatch *tp, uint64_t time) -{ - struct normalized_coords delta, unaccel; - - unaccel = tp_get_average_touches_delta(tp); - delta = tp_filter_motion(tp, &unaccel, time); - - if (!normalized_is_zero(delta) || !normalized_is_zero(unaccel)) { - tp_gesture_start(tp, time); - gesture_notify_swipe(&tp->device->base, time, - LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, - tp->gesture.finger_count, - &delta, &unaccel); - } -} - void tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time) { @@ -453,11 +498,9 @@ tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time) tp_gesture_post_pointer_motion(tp, time); break; case 2: - tp_gesture_post_twofinger(tp, time); - break; case 3: case 4: - tp_gesture_post_swipe(tp, time); + tp_gesture_post_gesture(tp, time); break; } } @@ -484,32 +527,30 @@ tp_gesture_end(struct tp_dispatch *tp, uint64_t time, bool cancelled) if (!tp->gesture.started) return; - switch (tp->gesture.finger_count) { - case 2: - switch (state) { - case GESTURE_STATE_NONE: - case GESTURE_STATE_UNKNOWN: - log_bug_libinput(libinput, - "%s in unknown gesture mode\n", - __func__); - break; - case GESTURE_STATE_SCROLL: - tp_gesture_stop_twofinger_scroll(tp, time); - break; - case GESTURE_STATE_PINCH: - gesture_notify_pinch_end(&tp->device->base, time, - tp->gesture.finger_count, - tp->gesture.prev_scale, - cancelled); - break; - } + switch (state) { + case GESTURE_STATE_NONE: + case GESTURE_STATE_UNKNOWN: + log_bug_libinput(libinput, + "%s in unknown gesture mode\n", + __func__); break; - case 3: - case 4: - gesture_notify_swipe_end(&tp->device->base, time, - tp->gesture.finger_count, cancelled); + case GESTURE_STATE_SCROLL: + tp_gesture_stop_twofinger_scroll(tp, time); + break; + case GESTURE_STATE_PINCH: + gesture_notify_pinch_end(&tp->device->base, time, + tp->gesture.finger_count, + tp->gesture.prev_scale, + cancelled); + break; + case GESTURE_STATE_SWIPE: + gesture_notify_swipe_end(&tp->device->base, + time, + tp->gesture.finger_count, + cancelled); break; } + tp->gesture.started = false; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 690feb55..20456f52 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -135,6 +135,7 @@ enum tp_gesture_state { GESTURE_STATE_UNKNOWN, GESTURE_STATE_SCROLL, GESTURE_STATE_PINCH, + GESTURE_STATE_SWIPE, }; enum tp_thumb_state { From f129c09adb0b925404916663b437317b2bc4c37d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 7 Jan 2016 15:00:53 +1000 Subject: [PATCH 14/25] test: add more gesture tests Signed-off-by: Peter Hutterer --- test/gestures.c | 770 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 770 insertions(+) diff --git a/test/gestures.c b/test/gestures.c index c21a4117..141686b4 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -156,6 +156,345 @@ START_TEST(gestures_swipe_3fg) } END_TEST +START_TEST(gestures_swipe_3fg_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int cardinals[8][2] = { + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, + }; + + if (libevdev_get_num_slots(dev->evdev) > 2 || + !libinput_device_has_capability(dev->libinput_device, + LIBINPUT_DEVICE_CAP_GESTURE)) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 40, 40); + litest_touch_down(dev, 1, 50, 40); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + libinput_dispatch(li); + litest_touch_move_two_touches(dev, + 40, 40, + 50, 40, + dir_x, dir_y, + 10, 2); + libinput_dispatch(li); + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + 3); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + 3); + + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + if (dir_x == 0.0) + ck_assert(dx == 0.0); + else if (dir_x < 0.0) + ck_assert(dx < 0.0); + else if (dir_x > 0.0) + ck_assert(dx > 0.0); + + if (dir_y == 0.0) + ck_assert(dy == 0.0); + else if (dir_y < 0.0) + ck_assert(dy < 0.0); + else if (dir_y > 0.0) + ck_assert(dy > 0.0); + + dx = libinput_event_gesture_get_dx_unaccelerated(gevent); + dy = libinput_event_gesture_get_dy_unaccelerated(gevent); + if (dir_x == 0.0) + ck_assert(dx == 0.0); + else if (dir_x < 0.0) + ck_assert(dx < 0.0); + else if (dir_x > 0.0) + ck_assert(dx > 0.0); + + if (dir_y == 0.0) + ck_assert(dy == 0.0); + else if (dir_y < 0.0) + ck_assert(dy < 0.0); + else if (dir_y > 0.0) + ck_assert(dy > 0.0); + + libinput_event_destroy(event); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + 3); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + +START_TEST(gestures_swipe_4fg) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int cardinals[8][2] = { + { 0, 3 }, + { 3, 3 }, + { 3, 0 }, + { 3, -3 }, + { 0, -3 }, + { -3, -3 }, + { -3, 0 }, + { -3, 3 }, + }; + int i; + + if (libevdev_get_num_slots(dev->evdev) < 4) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 40, 40); + litest_touch_down(dev, 1, 50, 40); + litest_touch_down(dev, 2, 60, 40); + litest_touch_down(dev, 3, 70, 40); + libinput_dispatch(li); + + for (i = 0; i < 8; i++) { + litest_push_event_frame(dev); + + dir_x += cardinals[cardinal][0]; + dir_y += cardinals[cardinal][1]; + + litest_touch_move(dev, + 0, + 40 + dir_x, + 40 + dir_y); + litest_touch_move(dev, + 1, + 50 + dir_x, + 40 + dir_y); + litest_touch_move(dev, + 2, + 60 + dir_x, + 40 + dir_y); + litest_touch_move(dev, + 3, + 70 + dir_x, + 40 + dir_y); + litest_pop_event_frame(dev); + libinput_dispatch(li); + } + + libinput_dispatch(li); + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + 4); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + 4); + + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + if (dir_x == 0.0) + ck_assert(dx == 0.0); + else if (dir_x < 0.0) + ck_assert(dx < 0.0); + else if (dir_x > 0.0) + ck_assert(dx > 0.0); + + if (dir_y == 0.0) + ck_assert(dy == 0.0); + else if (dir_y < 0.0) + ck_assert(dy < 0.0); + else if (dir_y > 0.0) + ck_assert(dy > 0.0); + + dx = libinput_event_gesture_get_dx_unaccelerated(gevent); + dy = libinput_event_gesture_get_dy_unaccelerated(gevent); + if (dir_x == 0.0) + ck_assert(dx == 0.0); + else if (dir_x < 0.0) + ck_assert(dx < 0.0); + else if (dir_x > 0.0) + ck_assert(dx > 0.0); + + if (dir_y == 0.0) + ck_assert(dy == 0.0); + else if (dir_y < 0.0) + ck_assert(dy < 0.0); + else if (dir_y > 0.0) + ck_assert(dy > 0.0); + + libinput_event_destroy(event); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + litest_touch_up(dev, 2); + litest_touch_up(dev, 3); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + 4); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + +START_TEST(gestures_swipe_4fg_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int cardinals[8][2] = { + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, + }; + + if (libevdev_get_num_slots(dev->evdev) > 2 || + !libinput_device_has_capability(dev->libinput_device, + LIBINPUT_DEVICE_CAP_GESTURE)) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 40, 40); + litest_touch_down(dev, 1, 50, 40); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + libinput_dispatch(li); + litest_touch_move_two_touches(dev, + 40, 40, + 50, 40, + dir_x, dir_y, + 10, 2); + libinput_dispatch(li); + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + 4); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + 4); + + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + if (dir_x == 0.0) + ck_assert(dx == 0.0); + else if (dir_x < 0.0) + ck_assert(dx < 0.0); + else if (dir_x > 0.0) + ck_assert(dx > 0.0); + + if (dir_y == 0.0) + ck_assert(dy == 0.0); + else if (dir_y < 0.0) + ck_assert(dy < 0.0); + else if (dir_y > 0.0) + ck_assert(dy > 0.0); + + dx = libinput_event_gesture_get_dx_unaccelerated(gevent); + dy = libinput_event_gesture_get_dy_unaccelerated(gevent); + if (dir_x == 0.0) + ck_assert(dx == 0.0); + else if (dir_x < 0.0) + ck_assert(dx < 0.0); + else if (dir_x > 0.0) + ck_assert(dx > 0.0); + + if (dir_y == 0.0) + ck_assert(dy == 0.0); + else if (dir_y < 0.0) + ck_assert(dy < 0.0); + else if (dir_y > 0.0) + ck_assert(dy > 0.0); + + libinput_event_destroy(event); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + 4); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + START_TEST(gestures_pinch) { struct litest_device *dev = litest_current_device(); @@ -257,6 +596,430 @@ START_TEST(gestures_pinch) } END_TEST +START_TEST(gestures_pinch_3fg) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int i; + double scale, oldscale; + double angle; + int cardinals[8][2] = { + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, + }; + + if (libevdev_get_num_slots(dev->evdev) < 3) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50 + dir_x, 50 + dir_y); + litest_touch_down(dev, 1, 50 - dir_x, 50 - dir_y); + litest_touch_down(dev, 2, 51 - dir_x, 51 - dir_y); + libinput_dispatch(li); + + for (i = 0; i < 8; i++) { + litest_push_event_frame(dev); + if (dir_x > 0.0) + dir_x -= 2; + else if (dir_x < 0.0) + dir_x += 2; + if (dir_y > 0.0) + dir_y -= 2; + else if (dir_y < 0.0) + dir_y += 2; + litest_touch_move(dev, + 0, + 50 + dir_x, + 50 + dir_y); + litest_touch_move(dev, + 1, + 50 - dir_x, + 50 - dir_y); + litest_touch_move(dev, + 2, + 51 - dir_x, + 51 - dir_y); + litest_pop_event_frame(dev); + libinput_dispatch(li); + } + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + 3); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + scale = libinput_event_gesture_get_scale(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + ck_assert(scale == 1.0); + + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + 3); + + oldscale = scale; + scale = libinput_event_gesture_get_scale(gevent); + + ck_assert(scale < oldscale); + + angle = libinput_event_gesture_get_angle_delta(gevent); + ck_assert_double_le(fabs(angle), 1.0); + + libinput_event_destroy(event); + libinput_dispatch(li); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + litest_touch_up(dev, 2); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_END, + 3); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + +START_TEST(gestures_pinch_3fg_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int i; + double scale, oldscale; + double angle; + int cardinals[8][2] = { + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, + }; + + if (libevdev_get_num_slots(dev->evdev) > 2 || + !libinput_device_has_capability(dev->libinput_device, + LIBINPUT_DEVICE_CAP_GESTURE)) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50 + dir_x, 50 + dir_y); + litest_touch_down(dev, 1, 50 - dir_x, 50 - dir_y); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + for (i = 0; i < 8; i++) { + litest_push_event_frame(dev); + if (dir_x > 0.0) + dir_x -= 2; + else if (dir_x < 0.0) + dir_x += 2; + if (dir_y > 0.0) + dir_y -= 2; + else if (dir_y < 0.0) + dir_y += 2; + litest_touch_move(dev, + 0, + 50 + dir_x, + 50 + dir_y); + litest_touch_move(dev, + 1, + 50 - dir_x, + 50 - dir_y); + litest_pop_event_frame(dev); + libinput_dispatch(li); + } + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + 3); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + scale = libinput_event_gesture_get_scale(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + ck_assert(scale == 1.0); + + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + 3); + + oldscale = scale; + scale = libinput_event_gesture_get_scale(gevent); + + ck_assert(scale < oldscale); + + angle = libinput_event_gesture_get_angle_delta(gevent); + ck_assert_double_le(fabs(angle), 1.0); + + libinput_event_destroy(event); + libinput_dispatch(li); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_END, + 3); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + +START_TEST(gestures_pinch_4fg) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int i; + double scale, oldscale; + double angle; + int cardinals[8][2] = { + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, + }; + + if (libevdev_get_num_slots(dev->evdev) < 4) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50 + dir_x, 50 + dir_y); + litest_touch_down(dev, 1, 50 - dir_x, 50 - dir_y); + litest_touch_down(dev, 2, 51 - dir_x, 51 - dir_y); + litest_touch_down(dev, 3, 52 - dir_x, 52 - dir_y); + libinput_dispatch(li); + + for (i = 0; i < 8; i++) { + litest_push_event_frame(dev); + if (dir_x > 0.0) + dir_x -= 2; + else if (dir_x < 0.0) + dir_x += 2; + if (dir_y > 0.0) + dir_y -= 2; + else if (dir_y < 0.0) + dir_y += 2; + litest_touch_move(dev, + 0, + 50 + dir_x, + 50 + dir_y); + litest_touch_move(dev, + 1, + 50 - dir_x, + 50 - dir_y); + litest_touch_move(dev, + 2, + 51 - dir_x, + 51 - dir_y); + litest_touch_move(dev, + 3, + 52 - dir_x, + 52 - dir_y); + litest_pop_event_frame(dev); + libinput_dispatch(li); + } + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + 4); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + scale = libinput_event_gesture_get_scale(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + ck_assert(scale == 1.0); + + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + 4); + + oldscale = scale; + scale = libinput_event_gesture_get_scale(gevent); + + ck_assert(scale < oldscale); + + angle = libinput_event_gesture_get_angle_delta(gevent); + ck_assert_double_le(fabs(angle), 1.0); + + libinput_event_destroy(event); + libinput_dispatch(li); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + litest_touch_up(dev, 2); + litest_touch_up(dev, 3); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_END, + 4); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + +START_TEST(gestures_pinch_4fg_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + double dx, dy; + int cardinal = _i; /* ranged test */ + double dir_x, dir_y; + int i; + double scale, oldscale; + double angle; + int cardinals[8][2] = { + { 0, 30 }, + { 30, 30 }, + { 30, 0 }, + { 30, -30 }, + { 0, -30 }, + { -30, -30 }, + { -30, 0 }, + { -30, 30 }, + }; + + if (libevdev_get_num_slots(dev->evdev) > 2 || + !libinput_device_has_capability(dev->libinput_device, + LIBINPUT_DEVICE_CAP_GESTURE)) + return; + + dir_x = cardinals[cardinal][0]; + dir_y = cardinals[cardinal][1]; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50 + dir_x, 50 + dir_y); + litest_touch_down(dev, 1, 50 - dir_x, 50 - dir_y); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + for (i = 0; i < 8; i++) { + litest_push_event_frame(dev); + if (dir_x > 0.0) + dir_x -= 2; + else if (dir_x < 0.0) + dir_x += 2; + if (dir_y > 0.0) + dir_y -= 2; + else if (dir_y < 0.0) + dir_y += 2; + litest_touch_move(dev, + 0, + 50 + dir_x, + 50 + dir_y); + litest_touch_move(dev, + 1, + 50 - dir_x, + 50 - dir_y); + litest_pop_event_frame(dev); + libinput_dispatch(li); + } + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + 4); + dx = libinput_event_gesture_get_dx(gevent); + dy = libinput_event_gesture_get_dy(gevent); + scale = libinput_event_gesture_get_scale(gevent); + ck_assert(dx == 0.0); + ck_assert(dy == 0.0); + ck_assert(scale == 1.0); + + libinput_event_destroy(event); + + while ((event = libinput_get_event(li)) != NULL) { + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + 4); + + oldscale = scale; + scale = libinput_event_gesture_get_scale(gevent); + + ck_assert(scale < oldscale); + + angle = libinput_event_gesture_get_angle_delta(gevent); + ck_assert_double_le(fabs(angle), 1.0); + + libinput_event_destroy(event); + libinput_dispatch(li); + } + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(li); + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_PINCH_END, + 4); + ck_assert(!libinput_event_gesture_get_cancelled(gevent)); + libinput_event_destroy(event); +} +END_TEST + START_TEST(gestures_spread) { struct litest_device *dev = litest_current_device(); @@ -400,7 +1163,14 @@ litest_setup_tests(void) litest_add("gestures:cap", gestures_nocap, LITEST_ANY, LITEST_TOUCHPAD); litest_add_ranged("gestures:swipe", gestures_swipe_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:swipe", gestures_swipe_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:swipe", gestures_swipe_4fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:swipe", gestures_swipe_4fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); litest_add_ranged("gestures:pinch", gestures_pinch, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:pinch", gestures_pinch_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:pinch", gestures_pinch_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:pinch", gestures_pinch_4fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + litest_add_ranged("gestures:pinch", gestures_pinch_4fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); litest_add_ranged("gestures:pinch", gestures_spread, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); litest_add("gesture:time", gestures_time_usec, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); From 83f3dbd1806aedcf6f1785ffcd6bb058fdcb009b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 8 Jan 2016 11:30:08 +1000 Subject: [PATCH 15/25] gestures: if a finger is 20mm below the other one, assume a pinch gesture Pure movement detection is quite unreliable when trying 3-finger pinch gestures, and many gestures are misdetected as swipes. Before looking at the motion, look at the constellation of the fingers. If one finger is 20mm below the other one, assume they're in a pinch position. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index e7b75ac2..93581f4d 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -312,12 +312,24 @@ tp_gesture_same_directions(int dir1, int dir2) ((dir2 & 0x80) && (dir1 & 0x01)); } +static inline void +tp_gesture_init_pinch( struct tp_dispatch *tp) +{ + tp_gesture_get_pinch_info(tp, + &tp->gesture.initial_distance, + &tp->gesture.angle, + &tp->gesture.center); + tp->gesture.prev_scale = 1.0; +} + static enum tp_gesture_state tp_gesture_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *first = tp->gesture.touches[0], *second = tp->gesture.touches[1]; int dir1, dir2; + int yres = tp->device->abs.absinfo_y->resolution; + int vert_distance; /* for two-finger gestures, if the fingers stay unmoving for a * while, assume (slow) scroll */ @@ -327,6 +339,14 @@ tp_gesture_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) return GESTURE_STATE_SCROLL; } + /* Else check if one finger is > 20mm below the others */ + vert_distance = abs(first->point.y - second->point.y); + if (vert_distance > 20 * yres && + tp->gesture.enabled) { + tp_gesture_init_pinch(tp); + return GESTURE_STATE_PINCH; + } + /* Else wait for both fingers to have moved */ dir1 = tp_gesture_get_direction(tp, first); dir2 = tp_gesture_get_direction(tp, second); @@ -343,11 +363,7 @@ tp_gesture_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) return GESTURE_STATE_SWIPE; } } else if (tp->gesture.enabled) { - tp_gesture_get_pinch_info(tp, - &tp->gesture.initial_distance, - &tp->gesture.angle, - &tp->gesture.center); - tp->gesture.prev_scale = 1.0; + tp_gesture_init_pinch(tp); return GESTURE_STATE_PINCH; } From cab2c1640d4c35c25dd186c1fc2fc052af9dd17a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 8 Jan 2016 13:28:21 +1000 Subject: [PATCH 16/25] doc: explain the gesture ambiguity for 2-slot touchpads Not much we can do about this until we get SMBus/RMI4 in the kernel or better touchpads in general but this way we can at least point to some official explanation. Signed-off-by: Peter Hutterer --- doc/gestures.dox | 22 ++ doc/svg/gesture-2fg-ambiguity.svg | 496 ++++++++++++++++++++++++++++++ 2 files changed, 518 insertions(+) create mode 100644 doc/svg/gesture-2fg-ambiguity.svg diff --git a/doc/gestures.dox b/doc/gestures.dox index 8632b8e6..325c795b 100644 --- a/doc/gestures.dox +++ b/doc/gestures.dox @@ -104,4 +104,26 @@ software button area. libinput ignores fingers within the software button areas, the movement of the remaining fingers is thus interpreted as a two-finger scroll motion. +@section gestures_twofinger_touchpads Gestures on two-finger touchpads + +As of kernel 4.2, many @ref touchpads_touch_partial_mt provide only two +slots. This affects how gestures can be interpreted. Touchpads with only two +slots can identify two touches by position but can usually tell that there +is a third (or fourth) finger down on the touchpad - without providing +positional information for that finger. + +Touchpoints are assigned in sequential order and only the first two touch +points are trackable. For libinput this produces an ambiguity where it is +impossible to detect whether a gesture is a pinch gesture or a swipe gesture +whenever a user puts the index and middle finger down first. Since the third +finger does not have positional information, it's location cannot be +determined. + +@image html gesture-2fg-ambiguity.svg "Ambiguity of three-finger gestures on two-finger touchpads" + +The image above illustrates this ambiguity. The index and middle finger are +set down first, the data stream from both finger positions looks identical. +In this case, libinput assumes the fingers are in a horizontal arrangement +(the right image above) and use a swipe gesture. + */ diff --git a/doc/svg/gesture-2fg-ambiguity.svg b/doc/svg/gesture-2fg-ambiguity.svg new file mode 100644 index 00000000..e4996ca9 --- /dev/null +++ b/doc/svg/gesture-2fg-ambiguity.svg @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Touch 1 + + + Touch 2 + + From 14baf58e3746bc07c1c290fb673b5723d45eb077 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 18 Jan 2016 17:04:39 +1000 Subject: [PATCH 17/25] 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 18/25] 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 19/25] 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 20/25] 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; From 7f16a8818d3abc3fa1d2e3665c41d95332a5bce7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 22 Jan 2016 17:38:14 +1000 Subject: [PATCH 21/25] test: rename the tap tests suite name to "tap:..." Better than just having one single suite Signed-off-by: Peter Hutterer --- test/touchpad-tap.c | 96 ++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/test/touchpad-tap.c b/test/touchpad-tap.c index 4450ec35..764cbef5 100644 --- a/test/touchpad-tap.c +++ b/test/touchpad-tap.c @@ -1782,60 +1782,60 @@ litest_setup_tests(void) { struct range multitap_range = {3, 8}; - litest_add("touchpad:tap", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_1fg_doubletap, LITEST_TOUCHPAD, LITEST_ANY); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap_n_drag_tap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap_n_drag_move, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap_n_drag_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &multitap_range); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY, &multitap_range); - litest_add("touchpad:tap", touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_draglock, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_draglock_tap, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_draglock_timeout, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_2fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_2fg_tap_n_drag_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); - litest_add("touchpad:tap", touchpad_2fg_tap_n_drag_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_2fg_tap_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_2fg_tap_n_hold_first, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_2fg_tap_n_hold_second, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_2fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD); - litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_SINGLE_TOUCH|LITEST_CLICKPAD); + litest_add("tap:1fg", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:1fg", touchpad_1fg_doubletap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap_n_drag_tap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap_n_drag_move, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap_n_drag_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &multitap_range); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY, &multitap_range); + litest_add("tap:1fg", touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:1fg", touchpad_1fg_tap_n_drag_draglock, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:1fg", touchpad_1fg_tap_n_drag_draglock_tap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:1fg", touchpad_1fg_tap_n_drag_draglock_timeout, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:2fg", touchpad_2fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:2fg", touchpad_2fg_tap_n_drag_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); + litest_add("tap:2fg", touchpad_2fg_tap_n_drag_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:2fg", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:2fg", touchpad_2fg_tap_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:2fg", touchpad_2fg_tap_n_hold_first, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:2fg", touchpad_2fg_tap_n_hold_second, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:2fg", touchpad_2fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:2fg", touchpad_1fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("tap:2fg", touchpad_2fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_SINGLE_TOUCH|LITEST_CLICKPAD); - litest_add("touchpad:tap", touchpad_2fg_tap_click_apple, LITEST_APPLE_CLICKPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_no_2fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_no_2fg_tap_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_3fg_tap_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_3fg_tap_btntool_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_3fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_3fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_5fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); - litest_add("touchpad:tap", touchpad_5fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:2fg", touchpad_2fg_tap_click_apple, LITEST_APPLE_CLICKPAD, LITEST_ANY); + litest_add("tap:2fg", touchpad_no_2fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:2fg", touchpad_no_2fg_tap_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:2fg", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:2fg", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:3fg", touchpad_3fg_tap_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:3fg", touchpad_3fg_tap_btntool_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:3fg", touchpad_3fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:3fg", touchpad_3fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap:4fg", touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:4fg", touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:5fg", touchpad_5fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add("tap:5fg", touchpad_5fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); /* Real buttons don't interfere with tapping, so don't run those for pads with buttons */ - litest_add("touchpad:tap", touchpad_1fg_double_tap_click, LITEST_CLICKPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY); - litest_add_ranged("touchpad:tap", touchpad_1fg_multitap_n_drag_tap_click, LITEST_CLICKPAD, LITEST_ANY, &multitap_range); - litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_draglock_tap_click, LITEST_CLICKPAD, LITEST_ANY); + litest_add("tap:1fg", touchpad_1fg_double_tap_click, LITEST_CLICKPAD, LITEST_ANY); + litest_add("tap:1fg", touchpad_1fg_tap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY); + litest_add_ranged("tap:1fg", touchpad_1fg_multitap_n_drag_tap_click, LITEST_CLICKPAD, LITEST_ANY, &multitap_range); + litest_add("tap:1fg", touchpad_1fg_tap_n_drag_draglock_tap_click, LITEST_CLICKPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_tap_default_disabled, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_ANY); - litest_add("touchpad:tap", touchpad_tap_default_enabled, LITEST_TOUCHPAD, LITEST_BUTTON); - litest_add("touchpad:tap", touchpad_tap_invalid, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_tap_is_available, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_tap_is_not_available, LITEST_ANY, LITEST_TOUCHPAD); + litest_add("tap:config", touchpad_tap_default_disabled, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_ANY); + litest_add("tap:config", touchpad_tap_default_enabled, LITEST_TOUCHPAD, LITEST_BUTTON); + litest_add("tap:config", touchpad_tap_invalid, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:config", touchpad_tap_is_available, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:config", touchpad_tap_is_not_available, LITEST_ANY, LITEST_TOUCHPAD); - litest_add("touchpad:tap", clickpad_1fg_tap_click, LITEST_CLICKPAD, LITEST_ANY); - litest_add("touchpad:tap", clickpad_2fg_tap_click, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); + litest_add("tap:1fg", clickpad_1fg_tap_click, LITEST_CLICKPAD, LITEST_ANY); + litest_add("tap:2fg", clickpad_2fg_tap_click, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); - litest_add("touchpad:tap", touchpad_drag_lock_default_disabled, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:tap", touchpad_drag_lock_default_unavailable, LITEST_ANY, LITEST_TOUCHPAD); + litest_add("tap:draglock", touchpad_drag_lock_default_disabled, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("tap:draglock", touchpad_drag_lock_default_unavailable, LITEST_ANY, LITEST_TOUCHPAD); } From 25ab3d4615c6628eacddbb3705913a1a78a67ae1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 25 Jan 2016 08:21:12 +1000 Subject: [PATCH 22/25] touchpad: remove unused field multitap_last_time Unused since d92ae62dad53afd894a Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-tap.c | 1 - src/evdev-mt-touchpad.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index a4c38a81..5556ee94 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -561,7 +561,6 @@ tp_tap_multitap_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_MULTITAP_DOWN; - tp->tap.multitap_last_time = time; tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); tp_tap_set_timer(tp, time); break; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 174fed6a..8564a103 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -312,7 +312,6 @@ struct tp_dispatch { struct libinput_timer timer; enum tp_tap_state state; uint32_t buttons_pressed; - uint64_t multitap_last_time; bool drag_lock_enabled; } tap; From 05bec986819af2d06986e0f5cf2e5257e88c0cc9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 25 Jan 2016 10:15:58 +1000 Subject: [PATCH 23/25] touchpad: remove unused variable Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 6c489c36..5aa256fd 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -578,13 +578,10 @@ tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time) { unsigned int active_touches = 0; struct tp_touch *t; - int i = 0; tp_for_each_touch(tp, t) { if (tp_touch_active(tp, t)) active_touches++; - - i++; } if (active_touches != tp->gesture.finger_count) { From 71fcd387f716f46b553f6646561cd33f3ca2eb54 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 25 Jan 2016 10:50:02 +1000 Subject: [PATCH 24/25] gestures: jump straight to swipe for 3+ finger gestures on ST touchpads The first/second variables are only needed for pinch, so we can skip them here. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 5aa256fd..8fe0bb85 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -240,6 +240,13 @@ tp_gesture_handle_state_none(struct tp_dispatch *tp, uint64_t time) if (ntouches < 2) return GESTURE_STATE_NONE; + if (!tp->gesture.enabled) { + if (ntouches == 2) + return GESTURE_STATE_SCROLL; + else + return GESTURE_STATE_SWIPE; + } + first = touches[0]; second = touches[1]; @@ -271,8 +278,7 @@ tp_gesture_handle_state_none(struct tp_dispatch *tp, uint64_t time) if (first == second) return GESTURE_STATE_NONE; - } else if (!tp->gesture.enabled) - return GESTURE_STATE_SCROLL; + } tp->gesture.initial_time = time; first->gesture.initial = first->point; From b6f59d0e3b2e38abd0c79e36a5971dc7ea1e2b16 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 25 Jan 2016 11:19:58 +1000 Subject: [PATCH 25/25] gestures: average motion by active touches, not moved touches Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-gestures.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 8fe0bb85..dc8d6060 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -49,15 +49,19 @@ static struct normalized_coords tp_get_touches_delta(struct tp_dispatch *tp, bool average) { struct tp_touch *t; - unsigned int i, nchanged = 0; + unsigned int i, nactive = 0; struct normalized_coords normalized; struct normalized_coords delta = {0.0, 0.0}; for (i = 0; i < tp->num_slots; i++) { t = &tp->touches[i]; - if (tp_touch_active(tp, t) && t->dirty) { - nchanged++; + if (!tp_touch_active(tp, t)) + continue; + + nactive++; + + if (t->dirty) { normalized = tp_get_delta(t); delta.x += normalized.x; @@ -65,11 +69,11 @@ tp_get_touches_delta(struct tp_dispatch *tp, bool average) } } - if (!average || nchanged == 0) + if (!average || nactive == 0) return delta; - delta.x /= nchanged; - delta.y /= nchanged; + delta.x /= nactive; + delta.y /= nactive; return delta; }