touchpad: fix multitaps with more than one finger while dragging is enabled
authorsatrmb <10471-satrmb_true-email-is-private_contact-via-web@gitlab.freedesktop.org>
Wed, 8 Jul 2020 11:32:43 +0000 (13:32 +0200)
committerPeter Hutterer <peter.hutterer@who-t.net>
Fri, 25 Sep 2020 06:01:28 +0000 (06:01 +0000)
Also permits any number of fingers in the tap that terminates drag-lock.

Signed-off-by: satrmb <10471-satrmb@users.noreply.gitlab.freedesktop.org>
src/evdev-mt-touchpad-tap.c
src/evdev-mt-touchpad.h

index ad5b610f5eb150d8e9b5f1069333b0f0e0cc6f13..3f50263a5a59b9cca1004ec6abeacba0ab09d82c 100644 (file)
@@ -79,9 +79,18 @@ tap_state_to_str(enum tp_tap_state state)
        CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP);
        CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP);
        CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP);
+       CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2);
+       CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2);
+       CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2);
+       CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE);
+       CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE);
+       CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE);
        CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_TAP);
        CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_TAP);
        CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_TAP);
+       CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_TAP_2);
+       CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_TAP_2);
+       CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_TAP_2);
        CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_2);
        CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_2);
        CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_2);
@@ -338,6 +347,8 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp,
                log_tap_bug(tp, t, event);
                break;
        case TAP_EVENT_PALM:
+               log_tap_bug(tp, t, event);
+               break;
        case TAP_EVENT_PALM_UP:
                break;
        }
@@ -713,12 +724,14 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
        switch (event) {
        case TAP_EVENT_TOUCH: {
                enum tp_tap_state dest[3] = {
-                       TAP_STATE_1FGTAP_DRAGGING_2,
-                       TAP_STATE_2FGTAP_DRAGGING_2,
-                       TAP_STATE_3FGTAP_DRAGGING_2,
+                       TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2,
+                       TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2,
+                       TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2,
                };
                assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
                tp->tap.state = dest[nfingers_tapped - 1];
+               tp->tap.saved_press_time = time;
+               tp_tap_set_timer(tp, time);
                break;
        }
        case TAP_EVENT_RELEASE:
@@ -769,6 +782,139 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
        }
 }
 
+static void
+tp_tap_dragging_or_doubletap_2_handle_event(struct tp_dispatch *tp,
+                                           struct tp_touch *t,
+                                           enum tap_event event, uint64_t time,
+                                           int nfingers_tapped)
+{
+       switch (event) {
+       case TAP_EVENT_TOUCH:
+               tp_tap_notify(tp,
+                             tp->tap.saved_release_time,
+                             nfingers_tapped,
+                             LIBINPUT_BUTTON_STATE_RELEASED);
+               tp->tap.state = TAP_STATE_TOUCH_3;
+               tp->tap.saved_press_time = time;
+               tp_tap_set_timer(tp, time);
+               break;
+       case TAP_EVENT_RELEASE: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE,
+                       TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE,
+                       TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               /* We are overwriting saved_release_time, but if this is indeed
+                  a multitap with two fingers, then we will need its previous
+                  value for the click release event we withheld just in case
+                  this is still a drag. */
+               tp->tap.saved_multitap_release_time = tp->tap.saved_release_time;
+               tp->tap.saved_release_time = time;
+               tp_tap_set_timer(tp, time);
+               break;
+       }
+       case TAP_EVENT_MOTION:
+       case TAP_EVENT_TIMEOUT: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_2,
+                       TAP_STATE_2FGTAP_DRAGGING_2,
+                       TAP_STATE_3FGTAP_DRAGGING_2,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               break;
+       }
+       case TAP_EVENT_BUTTON:
+               tp->tap.state = TAP_STATE_DEAD;
+               tp_tap_notify(tp,
+                             tp->tap.saved_release_time,
+                             nfingers_tapped,
+                             LIBINPUT_BUTTON_STATE_RELEASED);
+               break;
+       case TAP_EVENT_THUMB:
+               break;
+       case TAP_EVENT_PALM: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP,
+                       TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP,
+                       TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               break;
+       }
+       case TAP_EVENT_PALM_UP:
+               break;
+       }
+}
+
+static void
+tp_tap_dragging_or_doubletap_2_release_handle_event(struct tp_dispatch *tp,
+                                                   struct tp_touch *t,
+                                                   enum tap_event event,
+                                                   uint64_t time,
+                                                   int nfingers_tapped)
+{
+       switch (event) {
+       case TAP_EVENT_TOUCH: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_2,
+                       TAP_STATE_2FGTAP_DRAGGING_2,
+                       TAP_STATE_3FGTAP_DRAGGING_2,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               break;
+       }
+       case TAP_EVENT_RELEASE:
+               tp->tap.state = TAP_STATE_2FGTAP_TAPPED;
+               tp_tap_notify(tp,
+                             tp->tap.saved_multitap_release_time,
+                             nfingers_tapped,
+                             LIBINPUT_BUTTON_STATE_RELEASED);
+               tp_tap_notify(tp,
+                             tp->tap.saved_press_time,
+                             2,
+                             LIBINPUT_BUTTON_STATE_PRESSED);
+               tp_tap_set_timer(tp, time);
+               break;
+       case TAP_EVENT_MOTION:
+       case TAP_EVENT_TIMEOUT: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING,
+                       TAP_STATE_2FGTAP_DRAGGING,
+                       TAP_STATE_3FGTAP_DRAGGING,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               break;
+       }
+       case TAP_EVENT_BUTTON:
+               tp->tap.state = TAP_STATE_DEAD;
+               tp_tap_notify(tp,
+                             tp->tap.saved_release_time,
+                             nfingers_tapped,
+                             LIBINPUT_BUTTON_STATE_RELEASED);
+               break;
+       case TAP_EVENT_THUMB:
+               break;
+       case TAP_EVENT_PALM:
+               tp->tap.state = TAP_STATE_1FGTAP_TAPPED;
+               tp_tap_notify(tp,
+                             tp->tap.saved_release_time,
+                             nfingers_tapped,
+                             LIBINPUT_BUTTON_STATE_RELEASED);
+               tp_tap_notify(tp,
+                             tp->tap.saved_press_time,
+                             1,
+                             LIBINPUT_BUTTON_STATE_PRESSED);
+       case TAP_EVENT_PALM_UP:
+               break;
+       }
+}
+
 static void
 tp_tap_dragging_handle_event(struct tp_dispatch *tp,
                             struct tp_touch *t,
@@ -851,6 +997,7 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
        }
        case TAP_EVENT_RELEASE:
        case TAP_EVENT_MOTION:
+               log_tap_bug(tp, t, event);
                break;
        case TAP_EVENT_TIMEOUT:
                tp->tap.state = TAP_STATE_IDLE;
@@ -868,6 +1015,7 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
                break;
        case TAP_EVENT_THUMB:
        case TAP_EVENT_PALM:
+               log_tap_bug(tp, t, event);
                break;
        case TAP_EVENT_PALM_UP:
                break;
@@ -876,20 +1024,21 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
 
 static void
 tp_tap_dragging_tap_handle_event(struct tp_dispatch *tp,
-                                 struct tp_touch *t,
-                                 enum tap_event event, uint64_t time,
-                                 int nfingers_tapped)
+                                struct tp_touch *t,
+                                enum tap_event event, uint64_t time,
+                                int nfingers_tapped)
 {
 
        switch (event) {
        case TAP_EVENT_TOUCH: {
                enum tp_tap_state dest[3] = {
-                       TAP_STATE_1FGTAP_DRAGGING_2,
-                       TAP_STATE_2FGTAP_DRAGGING_2,
-                       TAP_STATE_3FGTAP_DRAGGING_2,
+                       TAP_STATE_1FGTAP_DRAGGING_OR_TAP_2,
+                       TAP_STATE_2FGTAP_DRAGGING_OR_TAP_2,
+                       TAP_STATE_3FGTAP_DRAGGING_OR_TAP_2,
                };
                assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
                tp->tap.state = dest[nfingers_tapped - 1];
+               tp_tap_set_timer(tp, time);
                break;
        }
        case TAP_EVENT_RELEASE:
@@ -919,12 +1068,76 @@ tp_tap_dragging_tap_handle_event(struct tp_dispatch *tp,
                break;
        case TAP_EVENT_THUMB:
                break;
-       case TAP_EVENT_PALM:
+       case TAP_EVENT_PALM: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_WAIT,
+                       TAP_STATE_2FGTAP_DRAGGING_WAIT,
+                       TAP_STATE_3FGTAP_DRAGGING_WAIT,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               break;
+       }
+       case TAP_EVENT_PALM_UP:
+               break;
+       }
+}
+
+static void
+tp_tap_dragging_tap_2_handle_event(struct tp_dispatch *tp,
+                                  struct tp_touch *t,
+                                  enum tap_event event, uint64_t time,
+                                  int nfingers_tapped)
+{
+
+       switch (event) {
+       case TAP_EVENT_TOUCH:
                tp_tap_notify(tp,
-                             tp->tap.saved_release_time,
+                             time,
+                             nfingers_tapped,
+                             LIBINPUT_BUTTON_STATE_RELEASED);
+               tp_tap_clear_timer(tp);
+               tp_tap_move_to_dead(tp, t);
+               break;
+       case TAP_EVENT_RELEASE: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_OR_TAP,
+                       TAP_STATE_2FGTAP_DRAGGING_OR_TAP,
+                       TAP_STATE_3FGTAP_DRAGGING_OR_TAP,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               tp_tap_set_timer(tp, time);
+               break;
+       }
+       case TAP_EVENT_MOTION:
+       case TAP_EVENT_TIMEOUT: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_2,
+                       TAP_STATE_2FGTAP_DRAGGING_2,
+                       TAP_STATE_3FGTAP_DRAGGING_2,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
+               break;
+       }
+       case TAP_EVENT_BUTTON:
+               tp->tap.state = TAP_STATE_DEAD;
+               tp_tap_notify(tp,
+                             time,
                              nfingers_tapped,
                              LIBINPUT_BUTTON_STATE_RELEASED);
-               tp->tap.state = TAP_STATE_IDLE;
+               break;
+       case TAP_EVENT_THUMB:
+               break;
+       case TAP_EVENT_PALM: {
+               enum tp_tap_state dest[3] = {
+                       TAP_STATE_1FGTAP_DRAGGING_OR_TAP,
+                       TAP_STATE_2FGTAP_DRAGGING_OR_TAP,
+                       TAP_STATE_3FGTAP_DRAGGING_OR_TAP,
+               };
+               assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
+               tp->tap.state = dest[nfingers_tapped - 1];
                break;
        }
        case TAP_EVENT_PALM_UP:
@@ -972,9 +1185,9 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp,
                break;
        case TAP_EVENT_PALM: {
                enum tp_tap_state dest[3] = {
-                       TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP,
-                       TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP,
-                       TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP,
+                       TAP_STATE_1FGTAP_DRAGGING,
+                       TAP_STATE_2FGTAP_DRAGGING,
+                       TAP_STATE_3FGTAP_DRAGGING,
                };
                assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
                tp->tap.state = dest[nfingers_tapped - 1];
@@ -1074,6 +1287,33 @@ tp_tap_handle_event(struct tp_dispatch *tp,
                tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time,
                                                          3);
                break;
+       case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2:
+               tp_tap_dragging_or_doubletap_2_handle_event(tp, t, event, time,
+                                                           1);
+               break;
+       case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2:
+               tp_tap_dragging_or_doubletap_2_handle_event(tp, t, event, time,
+                                                           2);
+               break;
+       case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2:
+               tp_tap_dragging_or_doubletap_2_handle_event(tp, t, event, time,
+                                                           3);
+               break;
+       case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE:
+               tp_tap_dragging_or_doubletap_2_release_handle_event(tp, t,
+                                                                   event, time,
+                                                                   1);
+               break;
+       case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE:
+               tp_tap_dragging_or_doubletap_2_release_handle_event(tp, t,
+                                                                   event, time,
+                                                                   2);
+               break;
+       case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE:
+               tp_tap_dragging_or_doubletap_2_release_handle_event(tp, t,
+                                                                   event, time,
+                                                                   3);
+               break;
        case TAP_STATE_1FGTAP_DRAGGING:
                tp_tap_dragging_handle_event(tp, t, event, time, 1);
                break;
@@ -1101,6 +1341,15 @@ tp_tap_handle_event(struct tp_dispatch *tp,
        case TAP_STATE_3FGTAP_DRAGGING_OR_TAP:
                tp_tap_dragging_tap_handle_event(tp, t, event, time, 3);
                break;
+       case TAP_STATE_1FGTAP_DRAGGING_OR_TAP_2:
+               tp_tap_dragging_tap_2_handle_event(tp, t, event, time, 1);
+               break;
+       case TAP_STATE_2FGTAP_DRAGGING_OR_TAP_2:
+               tp_tap_dragging_tap_2_handle_event(tp, t, event, time, 2);
+               break;
+       case TAP_STATE_3FGTAP_DRAGGING_OR_TAP_2:
+               tp_tap_dragging_tap_2_handle_event(tp, t, event, time, 3);
+               break;
        case TAP_STATE_1FGTAP_DRAGGING_2:
                tp_tap_dragging2_handle_event(tp, t, event, time, 1);
                break;
@@ -1278,9 +1527,18 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
        case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP:
        case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP:
        case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP:
+       case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2:
+       case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2:
+       case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2:
+       case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE:
+       case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE:
+       case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE:
        case TAP_STATE_1FGTAP_DRAGGING_OR_TAP:
        case TAP_STATE_2FGTAP_DRAGGING_OR_TAP:
        case TAP_STATE_3FGTAP_DRAGGING_OR_TAP:
+       case TAP_STATE_1FGTAP_DRAGGING_OR_TAP_2:
+       case TAP_STATE_2FGTAP_DRAGGING_OR_TAP_2:
+       case TAP_STATE_3FGTAP_DRAGGING_OR_TAP_2:
        case TAP_STATE_TOUCH_2:
        case TAP_STATE_TOUCH_3:
                filter_motion = 1;
@@ -1621,6 +1879,9 @@ tp_tap_dragging(const struct tp_dispatch *tp)
        case TAP_STATE_1FGTAP_DRAGGING_OR_TAP:
        case TAP_STATE_2FGTAP_DRAGGING_OR_TAP:
        case TAP_STATE_3FGTAP_DRAGGING_OR_TAP:
+       case TAP_STATE_1FGTAP_DRAGGING_OR_TAP_2:
+       case TAP_STATE_2FGTAP_DRAGGING_OR_TAP_2:
+       case TAP_STATE_3FGTAP_DRAGGING_OR_TAP_2:
                return true;
        default:
                return false;
index 6e1e1e3af29db76c5babc36db70a56b87ff39443..15c1e55aabaed05d30b0a523e2e969c932d3b2b5 100644 (file)
@@ -119,9 +119,18 @@ enum tp_tap_state {
        TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP,
        TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP,
        TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP,
+       TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2,
+       TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2,
+       TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2,
+       TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE,
+       TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE,
+       TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP_2_RELEASE,
        TAP_STATE_1FGTAP_DRAGGING_OR_TAP,
        TAP_STATE_2FGTAP_DRAGGING_OR_TAP,
        TAP_STATE_3FGTAP_DRAGGING_OR_TAP,
+       TAP_STATE_1FGTAP_DRAGGING_OR_TAP_2,
+       TAP_STATE_2FGTAP_DRAGGING_OR_TAP_2,
+       TAP_STATE_3FGTAP_DRAGGING_OR_TAP_2,
        TAP_STATE_1FGTAP_DRAGGING,
        TAP_STATE_2FGTAP_DRAGGING,
        TAP_STATE_3FGTAP_DRAGGING,
@@ -421,7 +430,8 @@ struct tp_dispatch {
                enum tp_tap_state state;
                uint32_t buttons_pressed;
                uint64_t saved_press_time,
-                        saved_release_time;
+                        saved_release_time,
+                        saved_multitap_release_time;
 
                enum libinput_config_tap_button_map map;
                enum libinput_config_tap_button_map want_map;