diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg index 318ff7bb..45b90d4d 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 >threshold
Viewer does not support full SVG 1.1
\ No newline at end of file +nonoyes(this section exists for [n] = 1, [n] = 2, and [n] = 3)(this section exists for [m] = 1, [m] = 2, and [m] = 3),for a total of 9 times due to combination with [n]yesyesyesnononoyesnoyesyesyesnononononoyesyesnonoyesnonoyesyesyesyesyesyesyes
IDLE
IDLE
firstfinger downTOUCH_TOUCHTOUCHsecondfinger downTOUCH_TOUCHTOUCH_2thirdfinger downTOUCH_TOUCHTOUCH_3TOUCH_2_RELEASEyeseitherfinger upyesremainingfinger upanyfinger upTOUCH_3_RELEASEeitherfinger upTOUCH_3_RELEASE_2yesremainingfinger upTOUCH_IDLEyesTOUCH_IDLETOUCH_IDLEyesTOUCH_IDLETOUCH_IDLEpalmTOUCH_DEADeitherfinger palmTOUCH_DEADyesanyfinger palmTOUCH_DEADyeseitherfinger palmTOUCH_DEADyesremainingfinger palmTOUCH_DEADyesremainingfinger palmTOUCH_DEAD2-finger tap3-finger tapyesfinger 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 taptimeouttimeouthold-and-tap enabled?HOLD3-finger tapnohold-and-tap enabled?timeouthold-and-tap enabled?3-finger tapTOUCH_2_HOLDTOUCH_3_HOLDtimeouthold-and-tap enabled?timeoutyesnohold-and-tap enabled?timeouthold-and-tap enabled?palmfinger 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 >thresholdhold-and-tap enabled?move >thresholdhold-and-tap enabled?move >thresholdhold-and-tap enabled?3-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 down1-finger tap2-finger tap
[m] = 1
[m] = 1
yes
[m] = 2
[m] = 2
3-finger tap
[m] = 3
[m] = 3
no[n] == [m]?button [m]pressbutton [m]releaseset tap stateto DEADfinger downTOUCH_TOUCHyeshold-and-tap enabled?TOUCH_DEADnoyesnothat fingerTOUCH_TOUCH?nothat fingerTOUCH_TOUCH?that fingerTOUCH_TOUCH?nothat fingerTOUCH_TOUCH?that fingerTOUCH_TOUCH?nothat fingerTOUCH_TOUCH?TOUCH_IDLETOUCH_IDLETOUCH_IDLEyesthat fingerTOUCH_TOUCH?nothat fingerTOUCH_TOUCH?TOUCH_IDLEthat fingerTOUCH_TOUCH?nothat fingerTOUCH_TOUCH?TOUCH_IDLEthat fingerTOUCH_TOUCH?nothat fingerTOUCH_TOUCH?TOUCH_IDLEthumbyesnodrag state== IDLE?yesnon-palmfinger count== 1?TOUCH_DEADthumbTOUCH_DEADnonodrag state== IDLE?drag state== IDLE?drag state== IDLE?nohold-and-tap enabled?3-finger tapnohold-and-tap enabled?nohold-and-tap enabled?finger downTOUCH_TOUCHnohold-and-tap enabled?3-finger tapfinger downTOUCH_TOUCHhold-and-tap enabled?finger downTOUCH_TOUCHnohold-and-tap enabled?3-finger tapall fingersexcept the new oneTOUCH_DEADall 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 f6d9290b..c819127d 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -204,11 +204,12 @@ tp_tap_clear_timer(struct tp_dispatch *tp) } static void -tp_tap_kill_all_touches(struct tp_dispatch *tp) +tp_tap_kill_all_touches(struct tp_dispatch *tp, + struct tp_touch *except) { struct tp_touch *t; tp_for_each_touch(tp, t) { - if (t->tap.state == TAP_TOUCH_STATE_TOUCH) + if (t != except && t->tap.state == TAP_TOUCH_STATE_TOUCH) t->tap.state = TAP_TOUCH_STATE_DEAD; } } @@ -238,7 +239,9 @@ tp_drag_idle_handle_event(struct tp_dispatch *tp, tp->tap.saved_press_time, 1, LIBINPUT_BUTTON_STATE_PRESSED); - if (tp->tap.drag_enabled) { + /* taps may end with fingers remaining down, + * those should not start a drag */ + if (tp->tap.drag_enabled && tp->tap.nfingers_down == 0) { tp->tap.drag_state = DRAG_STATE_1FGTAP_TAPPED; tp_tap_set_drag_timer(tp, time, 1); } else { @@ -253,7 +256,7 @@ tp_drag_idle_handle_event(struct tp_dispatch *tp, tp->tap.saved_press_time, 2, LIBINPUT_BUTTON_STATE_PRESSED); - if (tp->tap.drag_enabled) { + if (tp->tap.drag_enabled && tp->tap.nfingers_down == 0) { tp->tap.drag_state = DRAG_STATE_2FGTAP_TAPPED; tp_tap_set_drag_timer(tp, time, 2); } else { @@ -268,8 +271,6 @@ tp_drag_idle_handle_event(struct tp_dispatch *tp, tp->tap.saved_press_time, 3, LIBINPUT_BUTTON_STATE_PRESSED); - /* three-finger taps may end with fingers remaining down, - * see gitlab#499; those should not start a drag */ if (tp->tap.drag_enabled && tp->tap.nfingers_down == 0) { tp->tap.drag_state = DRAG_STATE_3FGTAP_TAPPED; tp_tap_set_drag_timer(tp, time, 3); @@ -479,9 +480,46 @@ tp_drag_dragging_handle_event(struct tp_dispatch *tp, } break; case TAP_EVENT_1FGTAP: + if (!tp->tap.hold_tap_enabled) + log_drag_bug(tp, t, event); + else if (nfingers_tapped != 1) { + tp_tap_notify(tp, + tp->tap.saved_press_time, + 1, + LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); + } + break; case TAP_EVENT_2FGTAP: + if (!tp->tap.hold_tap_enabled) + log_drag_bug(tp, t, event); + else if (nfingers_tapped != 2) { + tp_tap_notify(tp, + tp->tap.saved_press_time, + 2, + LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 2, + LIBINPUT_BUTTON_STATE_RELEASED); + } + break; case TAP_EVENT_3FGTAP: - log_drag_bug(tp, t, event); + if (!tp->tap.hold_tap_enabled) + log_drag_bug(tp, t, event); + else if (nfingers_tapped != 3) { + tp_tap_notify(tp, + tp->tap.saved_press_time, + 3, + LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 3, + LIBINPUT_BUTTON_STATE_RELEASED); + } break; } } @@ -733,6 +771,7 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: + log_tap_bug(tp, t, event); break; case TAP_EVENT_MOTION: log_tap_bug(tp, t, event); @@ -749,7 +788,7 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, log_tap_bug(tp, t, event); break; case TAP_EVENT_PALM: - tp->tap.state = TAP_STATE_IDLE; + log_tap_bug(tp, t, event); break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -772,15 +811,21 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: - tp->tap.saved_release_time = time; - tp_drag_handle_event(tp, t, TAP_EVENT_1FGTAP, time); - tp->tap.state = TAP_STATE_IDLE; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp->tap.saved_release_time = time; + tp_drag_handle_event(tp, t, TAP_EVENT_1FGTAP, time); + if (tp->tap.nfingers_down == 0) + tp->tap.state = TAP_STATE_IDLE; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_MOTION: tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: - if (tp->tap.drag_state == DRAG_STATE_IDLE) + if (!tp->tap.hold_tap_enabled && + tp->tap.drag_state == DRAG_STATE_IDLE) tp->tap.state = TAP_STATE_HOLD; else tp->tap.state = TAP_STATE_DEAD; @@ -793,14 +838,20 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, log_tap_bug(tp, t, event); break; case TAP_EVENT_THUMB: - if (tp->tap.drag_state == DRAG_STATE_IDLE) { + if (tp->tap.drag_state == DRAG_STATE_IDLE && + tp->tap.nfingers_down == 1) { tp->tap.state = TAP_STATE_IDLE; t->tap.is_thumb = true; tp->tap.nfingers_down--; } break; case TAP_EVENT_PALM: - tp->tap.state = TAP_STATE_IDLE; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + if (tp->tap.nfingers_down == 0) + tp->tap.state = TAP_STATE_IDLE; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -865,15 +916,18 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: - tp->tap.state = TAP_STATE_TOUCH_2_RELEASE; - tp->tap.saved_release_time = time; - tp_tap_set_timer(tp, time); + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp->tap.state = TAP_STATE_TOUCH_2_RELEASE; + tp->tap.saved_release_time = time; + tp_tap_set_timer(tp, time); + } break; case TAP_EVENT_MOTION: tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: - if (tp->tap.drag_state == DRAG_STATE_IDLE) + if (!tp->tap.hold_tap_enabled && + tp->tap.drag_state == DRAG_STATE_IDLE) tp->tap.state = TAP_STATE_TOUCH_2_HOLD; else tp->tap.state = TAP_STATE_DEAD; @@ -888,7 +942,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, case TAP_EVENT_THUMB: break; case TAP_EVENT_PALM: - tp->tap.state = TAP_STATE_TOUCH; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) + tp->tap.state = TAP_STATE_TOUCH; break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -945,19 +1000,29 @@ tp_tap_touch2_release_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: - tp->tap.state = TAP_STATE_TOUCH_2; + if (tp->tap.hold_tap_enabled) { + tp_tap_kill_all_touches(tp, t); + tp->tap.state = TAP_STATE_TOUCH; + } else + 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; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp_drag_handle_event(tp, t, TAP_EVENT_2FGTAP, time); + if (tp->tap.nfingers_down == 0) + tp->tap.state = TAP_STATE_IDLE; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_MOTION: tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: - if (tp->tap.drag_state == DRAG_STATE_IDLE) + if (!tp->tap.hold_tap_enabled && + tp->tap.drag_state == DRAG_STATE_IDLE) tp->tap.state = TAP_STATE_HOLD; else tp->tap.state = TAP_STATE_DEAD; @@ -971,15 +1036,21 @@ tp_tap_touch2_release_handle_event(struct tp_dispatch *tp, case TAP_EVENT_THUMB: break; case TAP_EVENT_PALM: - /* There's only one saved press time and it's overwritten by - * the last touch down. So in the case of finger down, palm - * down, finger up, palm detected, we use the - * palm touch's press time here instead of the finger's press - * time. The tap timer also gets reset on palm detection. - * Let's wait and see if that's an issue. - */ - tp_drag_handle_event(tp, t, TAP_EVENT_1FGTAP, time); - tp->tap.state = TAP_STATE_IDLE; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + /* There's only one saved press time and it's + * overwritten by the last touch down. So in the case + * of finger down, palm down, finger up, palm detected, + * we use the palm touch's press time here instead of + * the finger's press time. The tap timer also gets + * reset on palm detection. Let's wait and see if that's + * an issue. + */ + tp_drag_handle_event(tp, t, TAP_EVENT_1FGTAP, time); + if (tp->tap.nfingers_down == 0) + tp->tap.state = TAP_STATE_IDLE; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -1002,21 +1073,24 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, * out of DRAGGING_OR_DOUBLETAP or DRAGLOCK_CONTINUE */ tp_drag_handle_event(tp, t, TAP_EVENT_MOTION, time); break; + case TAP_EVENT_RELEASE: + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp->tap.state = TAP_STATE_TOUCH_3_RELEASE; + tp->tap.saved_release_time = time; + tp_tap_set_timer(tp, time); + } + break; case TAP_EVENT_MOTION: tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: - if (tp->tap.drag_state == DRAG_STATE_IDLE) + if (!tp->tap.hold_tap_enabled && + tp->tap.drag_state == DRAG_STATE_IDLE) tp->tap.state = TAP_STATE_TOUCH_3_HOLD; else tp->tap.state = TAP_STATE_DEAD; tp_gesture_tap_timeout(tp, time); break; - case TAP_EVENT_RELEASE: - tp->tap.state = TAP_STATE_TOUCH_3_RELEASE; - tp->tap.saved_release_time = time; - tp_tap_set_timer(tp, time); - break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_BUTTON; break; @@ -1026,7 +1100,8 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, case TAP_EVENT_THUMB: break; case TAP_EVENT_PALM: - tp->tap.state = TAP_STATE_TOUCH_2; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) + tp->tap.state = TAP_STATE_TOUCH_2; break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -1081,28 +1156,41 @@ tp_tap_touch3_release_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); - tp->tap.state = TAP_STATE_TOUCH_3; + if (tp->tap.hold_tap_enabled) { + tp_tap_kill_all_touches(tp, t); + tp->tap.state = TAP_STATE_TOUCH; + } else { + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + tp->tap.state = TAP_STATE_TOUCH_3; + } tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: - tp->tap.state = TAP_STATE_TOUCH_3_RELEASE_2; - tp_tap_set_timer(tp, time); + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp->tap.state = TAP_STATE_TOUCH_3_RELEASE_2; + tp_tap_set_timer(tp, time); + } break; case TAP_EVENT_MOTION: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (!tp->tap.hold_tap_enabled) + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); - if (tp->tap.drag_state == DRAG_STATE_IDLE) - tp->tap.state = TAP_STATE_TOUCH_2_HOLD; - else + if (tp->tap.hold_tap_enabled) tp->tap.state = TAP_STATE_DEAD; + else { + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (tp->tap.drag_state == DRAG_STATE_IDLE) + tp->tap.state = TAP_STATE_TOUCH_2_HOLD; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_BUTTON: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (!tp->tap.hold_tap_enabled) + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); tp->tap.state = TAP_STATE_BUTTON; break; case TAP_EVENT_BUTTON_UP: @@ -1111,7 +1199,8 @@ tp_tap_touch3_release_handle_event(struct tp_dispatch *tp, case TAP_EVENT_THUMB: break; case TAP_EVENT_PALM: - tp->tap.state = TAP_STATE_TOUCH_2_RELEASE; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) + tp->tap.state = TAP_STATE_TOUCH_2_RELEASE; break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -1129,28 +1218,44 @@ tp_tap_touch3_release2_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); - tp->tap.state = TAP_STATE_TOUCH_2; + if (tp->tap.hold_tap_enabled) { + tp_tap_kill_all_touches(tp, t); + tp->tap.state = TAP_STATE_TOUCH; + } else { + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + 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_3FGTAP, time); - tp->tap.state = TAP_STATE_IDLE; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (tp->tap.nfingers_down == 0) + tp->tap.state = TAP_STATE_IDLE; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_MOTION: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (!tp->tap.hold_tap_enabled) + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_TIMEOUT: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); - if (tp->tap.drag_state == DRAG_STATE_IDLE) - tp->tap.state = TAP_STATE_HOLD; - else + if (tp->tap.hold_tap_enabled) tp->tap.state = TAP_STATE_DEAD; + else { + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (tp->tap.drag_state == DRAG_STATE_IDLE) + tp->tap.state = TAP_STATE_HOLD; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_BUTTON: - tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); + if (!tp->tap.hold_tap_enabled) + tp_drag_handle_event(tp, t, TAP_EVENT_3FGTAP, time); tp->tap.state = TAP_STATE_BUTTON; break; case TAP_EVENT_BUTTON_UP: @@ -1159,8 +1264,13 @@ tp_tap_touch3_release2_handle_event(struct tp_dispatch *tp, case TAP_EVENT_THUMB: break; case TAP_EVENT_PALM: - tp_drag_handle_event(tp, t, TAP_EVENT_2FGTAP, time); - tp->tap.state = TAP_STATE_IDLE; + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp_drag_handle_event(tp, t, TAP_EVENT_2FGTAP, time); + if (tp->tap.nfingers_down == 0) + tp->tap.state = TAP_STATE_IDLE; + else + tp->tap.state = TAP_STATE_DEAD; + } break; case TAP_EVENT_1FGTAP: case TAP_EVENT_2FGTAP: @@ -1211,11 +1321,17 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp, { switch (event) { + case TAP_EVENT_TOUCH: + if (tp->tap.hold_tap_enabled) { + tp->tap.state = TAP_STATE_TOUCH; + tp->tap.saved_press_time = time; + tp_tap_set_timer(tp, time); + } + break; case TAP_EVENT_RELEASE: if (tp->tap.nfingers_down == 0) tp->tap.state = TAP_STATE_IDLE; break; - case TAP_EVENT_TOUCH: case TAP_EVENT_MOTION: case TAP_EVENT_TIMEOUT: break; @@ -1318,7 +1434,7 @@ tp_tap_handle_event(struct tp_dispatch *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); + tp_tap_kill_all_touches(tp, NULL); } static bool @@ -1394,12 +1510,12 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) if (t->palm.state != PALM_NONE) { assert(!t->tap.is_palm); t->tap.is_palm = true; - t->tap.state = TAP_TOUCH_STATE_DEAD; if (t->state != TOUCH_BEGIN) { assert(tp->tap.nfingers_down > 0); tp->tap.nfingers_down--; tp_tap_handle_event(tp, t, TAP_EVENT_PALM, time); } + t->tap.state = TAP_TOUCH_STATE_DEAD; } else if (t->state == TOUCH_BEGIN) { /* The simple version: if a touch is a thumb on * begin we ignore it. All other thumb touches @@ -1428,8 +1544,10 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) /* Any touch exceeding the threshold turns all * touches into DEAD */ - tp_tap_kill_all_touches(tp); - tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); + if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { + tp_tap_kill_all_touches(tp, NULL); + tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); + } } } @@ -1466,7 +1584,14 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) } assert(tp->tap.nfingers_down <= tp->nfingers_down); - if (tp->nfingers_down == 0) + if (tp->nfingers_down == 0 || + tp->tap.state == TAP_STATE_IDLE || + tp->tap.drag_state == DRAG_STATE_1FGTAP_TAPPED || + tp->tap.drag_state == DRAG_STATE_2FGTAP_TAPPED || + tp->tap.drag_state == DRAG_STATE_3FGTAP_TAPPED || + tp->tap.drag_state == DRAG_STATE_1FGTAP_DRAGLOCK_WAIT || + tp->tap.drag_state == DRAG_STATE_2FGTAP_DRAGLOCK_WAIT || + tp->tap.drag_state == DRAG_STATE_3FGTAP_DRAGLOCK_WAIT) assert(tp->tap.nfingers_down == 0); return filter_motion;