From 484ccb0fb3060e94468eb392942bf55c2151c213 Mon Sep 17 00:00:00 2001 From: satrmb <10471-satrmb_true-email-is-private_contact-via-web@gitlab.freedesktop.org> Date: Sun, 2 Aug 2020 15:28:22 +0200 Subject: [PATCH] touchpad: make sure all touches are DEAD iff they cannot tap anymore This includes all touches in tap states IDLE (which have to be thumbs or palms), DEAD, and BUTTON. The states HOLD, TOUCH_2_HOLD, and TOUCH_3_HOLD are specifically not included because touches may become part of a tap again by adding another finger and releasing them together before the tap times out once more. Also clean up some timer clearing that has become redundant, and permit a new touch in TOUCH_2_RELEASE to directly go to TOUCH_2 instead of TOUCH_2_HOLD, requiring another release + re-touch cycle via HOLD. Signed-off-by: satrmb <10471-satrmb@users.noreply.gitlab.freedesktop.org> --- doc/touchpad-tap-state-machine.svg | 2 +- src/evdev-mt-touchpad-tap.c | 78 ++++++++++-------------------- src/evdev-mt-touchpad.h | 3 +- 3 files changed, 28 insertions(+), 55 deletions(-) diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg index 4d6f64e6..318ff7bb 100644 --- a/doc/touchpad-tap-state-machine.svg +++ b/doc/touchpad-tap-state-machine.svg @@ -1,3 +1,3 @@ -no(this section exists for [n] = 1, [n] = 2, and [n] = 3)nonoyesyesyes
IDLE
IDLE
firstfinger downTOUCH_TOUCHTOUCHsecondfinger downTOUCH_TOUCHTOUCH_2thirdfinger downTOUCH_TOUCHTOUCH_3TOUCH_2_RELEASEeitherfinger upremainingfinger upanyfinger upTOUCH_3_RELEASEeitherfinger upTOUCH_3_RELEASE_2remainingfinger upTOUCH_IDLETOUCH_IDLETOUCH_IDLETOUCH_IDLETOUCH_IDLEpalmTOUCH_DEADeitherfinger palmTOUCH_DEADanyfinger palmTOUCH_DEADeitherfinger palmTOUCH_DEADremainingfinger palmTOUCH_DEADremainingfinger palmTOUCH_DEAD2-finger tap3-finger tapfinger upTOUCH_IDLE1-finger tapfourthfinger down
IDLE
IDLE
TAPPEDyes2-finger tappalmfinger upbutton [n]pressbutton [n]releaseDRAGGING_OR_DOUBLETAPfinger downtap-and-dragtimeouttimeoutmove >thresholdDRAGGINGpalmfinger upnoyesdrag-lockenabled?DRAGLOCK_WAITDRAGLOCK_CONTINUEfinger uppalmtimeoutmove >thresholddrag-locktimeout1-finger tapyesnonon-palmfinger count== 0?finger down1-finger taptimeouttimeoutHOLD3-finger taptimeout3-finger tapTOUCH_2_HOLDTOUCH_3_HOLDtimeouttimeoutyestimeoutpalmfinger upTOUCH_DEADTOUCH_IDLEeitherfinger palmeitherfinger upTOUCH_DEADTOUCH_IDLEanyfinger palmanyfinger upTOUCH_DEADTOUCH_IDLETOUCH_DEADDEADBUTTONclickpadbuttonreleaseall fingersTOUCH_DEADnoyesnon-palmfinger count== 0?clickpadbuttonpressanyfinger upTOUCH_IDLEanyfinger palmmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >threshold3-finger tapclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpress1-finger tap3-finger tapbutton [n]releaseBUTTONclickpadbuttonreleaseclickpadbuttonpressbutton [n]releaseclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressbutton [n]press
[n] = 1
[n] = 1
[n] = 1
[n] = 1
[n] = 2
[n] = 2
[n] = 3
[n] = 3
notap-and-dragenabled?move >thresholdyesnonon-palmfinger count== 0?nonon-palmfinger count== 0?secondfinger downsecondfinger downset tap stateto DEADfinger downTOUCH_DEADthumbyesdrag state== IDLE?TOUCH_DEADthumbTOUCH_DEADnodrag state== IDLE?drag state== IDLE?drag state== IDLE?3-finger tapfinger downTOUCH_TOUCH3-finger tapfinger downTOUCH_TOUCHfinger downTOUCH_TOUCH3-finger tapall fingersTOUCH_DEADfourthfinger downTOUCH_DEADto draggingstate machine:move >thresholdnoyesdrag state== IDLE?to draggingstate machine:move >threshold
Viewer does not support full SVG 1.1
\ No newline at end of file +no(this section exists for [n] = 1, [n] = 2, and [n] = 3)nonoyesyesyes
IDLE
IDLE
firstfinger downTOUCH_TOUCHTOUCHsecondfinger downTOUCH_TOUCHTOUCH_2thirdfinger downTOUCH_TOUCHTOUCH_3TOUCH_2_RELEASEeitherfinger upremainingfinger upanyfinger upTOUCH_3_RELEASEeitherfinger upTOUCH_3_RELEASE_2remainingfinger upTOUCH_IDLETOUCH_IDLETOUCH_IDLETOUCH_IDLETOUCH_IDLEpalmTOUCH_DEADeitherfinger palmTOUCH_DEADanyfinger palmTOUCH_DEADeitherfinger palmTOUCH_DEADremainingfinger palmTOUCH_DEADremainingfinger palmTOUCH_DEAD2-finger tap3-finger tapfinger upTOUCH_IDLE1-finger tapfourthfinger down
IDLE
IDLE
TAPPEDyes2-finger tappalmfinger upbutton [n]pressbutton [n]releaseDRAGGING_OR_DOUBLETAPfinger downtap-and-dragtimeouttimeoutmove >thresholdDRAGGINGpalmfinger upnoyesdrag-lockenabled?DRAGLOCK_WAITDRAGLOCK_CONTINUEfinger uppalmtimeoutmove >thresholddrag-locktimeout1-finger tapyesnonon-palmfinger count== 0?finger down1-finger taptimeouttimeoutHOLD3-finger taptimeout3-finger tapTOUCH_2_HOLDTOUCH_3_HOLDtimeouttimeoutyestimeoutpalmfinger upTOUCH_DEADTOUCH_IDLEeitherfinger palmeitherfinger upTOUCH_DEADTOUCH_IDLEanyfinger palmanyfinger upTOUCH_DEADTOUCH_IDLETOUCH_DEADDEADBUTTONclickpadbuttonreleaseall fingersTOUCH_DEADnoyesnon-palmfinger count== 0?clickpadbuttonpressanyfinger upTOUCH_IDLEanyfinger palmmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >thresholdmove >threshold3-finger tapclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpress1-finger tap3-finger tapbutton [n]releaseBUTTONclickpadbuttonreleaseclickpadbuttonpressbutton [n]releaseclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressclickpadbuttonpressbutton [n]press
[n] = 1
[n] = 1
[n] = 1
[n] = 1
[n] = 2
[n] = 2
[n] = 3
[n] = 3
notap-and-dragenabled?move >thresholdyesnonon-palmfinger count== 0?nonon-palmfinger count== 0?secondfinger downsecondfinger downset tap stateto DEADfinger downTOUCH_DEADthumbyesdrag state== IDLE?TOUCH_DEADthumbTOUCH_DEADnodrag state== IDLE?drag state== IDLE?drag state== IDLE?3-finger tapfinger downTOUCH_TOUCH3-finger tapfinger downTOUCH_TOUCHfinger downTOUCH_TOUCH3-finger tapall fingersTOUCH_DEADfourthfinger downTOUCH_DEADto draggingstate machine:move >threshold
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 0db0c626..19913a56 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -204,11 +204,13 @@ tp_tap_clear_timer(struct tp_dispatch *tp) } static void -tp_tap_move_to_dead(struct tp_dispatch *tp, struct tp_touch *t) +tp_tap_kill_all_touches(struct tp_dispatch *tp) { - tp->tap.state = TAP_STATE_DEAD; - t->tap.state = TAP_TOUCH_STATE_DEAD; - tp_tap_clear_timer(tp); + struct tp_touch *t; + tp_for_each_touch(tp, t) { + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) + t->tap.state = TAP_TOUCH_STATE_DEAD; + } } static void @@ -552,7 +554,7 @@ tp_drag_draglock_continue_handle_event(struct tp_dispatch *tp, /* ignore taps with more than one finger, they shall * only end drag-lock instead of emitting button events * or starting a new drag */ - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; } case TAP_EVENT_RELEASE: { @@ -709,9 +711,6 @@ tp_drag_handle_event(struct tp_dispatch *tp, break; } - if (tp->tap.drag_state == DRAG_STATE_BUTTON) - tp_tap_clear_timer(tp); - if (current != tp->tap.drag_state) evdev_log_debug(tp->device, "drag: touch %d (%s), drag state %s → %s → %s\n", @@ -778,14 +777,13 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_IDLE; break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: if (tp->tap.drag_state == DRAG_STATE_IDLE) tp->tap.state = TAP_STATE_HOLD; else tp->tap.state = TAP_STATE_DEAD; - tp_tap_clear_timer(tp); tp_gesture_tap_timeout(tp, time); break; case TAP_EVENT_BUTTON: @@ -799,8 +797,6 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_IDLE; t->tap.is_thumb = true; tp->tap.nfingers_down--; - t->tap.state = TAP_TOUCH_STATE_DEAD; - tp_tap_clear_timer(tp); } break; case TAP_EVENT_PALM: @@ -830,7 +826,7 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_IDLE; break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: break; @@ -844,7 +840,6 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_IDLE; t->tap.is_thumb = true; tp->tap.nfingers_down--; - t->tap.state = TAP_TOUCH_STATE_DEAD; break; case TAP_EVENT_PALM: tp->tap.state = TAP_STATE_IDLE; @@ -875,7 +870,7 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, tp_tap_set_timer(tp, time); break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: if (tp->tap.drag_state == DRAG_STATE_IDLE) @@ -919,7 +914,7 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_HOLD; break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: break; @@ -950,24 +945,16 @@ tp_tap_touch2_release_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: - if (tp->tap.drag_state == DRAG_STATE_IDLE) - tp->tap.state = TAP_STATE_TOUCH_2_HOLD; - else { - /* this cannot be a tap anymore, get the dragging - * state machine out of DRAGGING_OR_DOUBLETAP or - * DRAGLOCK_CONTINUE */ - tp_drag_handle_event(tp, t, TAP_EVENT_MOTION, time); - tp->tap.state = TAP_STATE_DEAD; - } - t->tap.state = TAP_TOUCH_STATE_DEAD; - tp_tap_clear_timer(tp); + tp->tap.state = TAP_STATE_TOUCH_2; + tp->tap.saved_press_time = time; + tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: tp_drag_handle_event(tp, t, TAP_EVENT_2FGTAP, time); tp->tap.state = TAP_STATE_IDLE; break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: if (tp->tap.drag_state == DRAG_STATE_IDLE) @@ -1011,20 +998,18 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DEAD; - tp_tap_clear_timer(tp); /* this cannot be a tap anymore, get the dragging state machine * out of DRAGGING_OR_DOUBLETAP or DRAGLOCK_CONTINUE */ tp_drag_handle_event(tp, t, TAP_EVENT_MOTION, time); break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: if (tp->tap.drag_state == DRAG_STATE_IDLE) tp->tap.state = TAP_STATE_TOUCH_3_HOLD; else tp->tap.state = TAP_STATE_DEAD; - tp_tap_clear_timer(tp); tp_gesture_tap_timeout(tp, time); break; case TAP_EVENT_RELEASE: @@ -1065,7 +1050,7 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_TOUCH_2_HOLD; break; case TAP_EVENT_MOTION: - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: break; @@ -1107,7 +1092,7 @@ tp_tap_touch3_release_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_MOTION: tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); @@ -1155,7 +1140,7 @@ tp_tap_touch3_release2_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_MOTION: tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); - tp_tap_move_to_dead(tp, t); + tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); @@ -1329,6 +1314,11 @@ tp_tap_handle_event(struct tp_dispatch *tp, tp->tap.drag_state == DRAG_STATE_3FGTAP_DRAGGING || tp->tap.drag_state == DRAG_STATE_BUTTON)) tp_tap_clear_timer(tp); + + if ((tp->tap.state == TAP_STATE_IDLE || + tp->tap.state == TAP_STATE_BUTTON || + tp->tap.state == TAP_STATE_DEAD)) + tp_tap_kill_all_touches(tp); } static bool @@ -1389,10 +1379,6 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) if (!t->dirty || t->state == TOUCH_NONE) continue; - if (tp->buttons.is_clickpad && - tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) - t->tap.state = TAP_TOUCH_STATE_DEAD; - /* If a touch was considered thumb for tapping once, we * ignore it for the rest of lifetime */ if (t->tap.is_thumb) @@ -1439,15 +1425,10 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) tp_tap_handle_event(tp, t, TAP_EVENT_THUMB, time); } else if (tp->tap.state != TAP_STATE_IDLE && tp_tap_exceeds_motion_threshold(tp, t)) { - struct tp_touch *tmp; /* Any touch exceeding the threshold turns all * touches into DEAD */ - tp_for_each_touch(tp, tmp) { - if (tmp->tap.state == TAP_TOUCH_STATE_TOUCH) - tmp->tap.state = TAP_TOUCH_STATE_DEAD; - } - + tp_tap_kill_all_touches(tp); tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); } } @@ -1512,17 +1493,8 @@ static void tp_tap_handle_timeout(uint64_t time, void *data) { struct tp_dispatch *tp = data; - struct tp_touch *t; tp_tap_handle_event(tp, NULL, TAP_EVENT_TIMEOUT, time); - - tp_for_each_touch(tp, t) { - if (t->state == TOUCH_NONE || - t->tap.state == TAP_TOUCH_STATE_IDLE) - continue; - - t->tap.state = TAP_TOUCH_STATE_DEAD; - } } static void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index d9d75867..e88ccfed 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -140,7 +140,8 @@ enum tp_drag_state { enum tp_tap_touch_state { TAP_TOUCH_STATE_IDLE = 16, /**< not in touch */ TAP_TOUCH_STATE_TOUCH, /**< touching, may tap */ - TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ + TAP_TOUCH_STATE_DEAD, /**< exceeded motion, + or clickpad button pressed */ }; /* For edge scrolling, so we only care about right and bottom */