From 626a0af4ec1c970aaf781fdac0bf4c7a9a2a58e1 Mon Sep 17 00:00:00 2001 From: abc def <24701-abcdef@users.noreply.gitlab.freedesktop.org> Date: Thu, 6 Jan 2022 13:22:42 +0100 Subject: [PATCH] TFD: add debounce state for touch count decrease Don't allow motion events within a certain interval from a touch count decrease (to 1 finger) to finish the drag. This should make even very quick drags remain in drag-lock instead of being unintentionally finished by the last finger. Signed-off-by: Temp Name --- src/evdev-mt-touchpad-tfd.c | 93 ++++++++++++++++++++++++++++++++++--- src/evdev-mt-touchpad.h | 13 ++++-- 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/evdev-mt-touchpad-tfd.c b/src/evdev-mt-touchpad-tfd.c index c12bc27b..49c576bd 100644 --- a/src/evdev-mt-touchpad-tfd.c +++ b/src/evdev-mt-touchpad-tfd.c @@ -44,6 +44,7 @@ tfd_state_to_str(enum tp_tfd_state state) CASE_RETURN_STRING(TFD_STATE_IDLE); CASE_RETURN_STRING(TFD_STATE_POSSIBLE_DRAG); CASE_RETURN_STRING(TFD_STATE_DRAG); + CASE_RETURN_STRING(TFD_STATE_POSSIBLE_ZERO_FINGERS); CASE_RETURN_STRING(TFD_STATE_AWAIT_RESUME); CASE_RETURN_STRING(TFD_STATE_POSSIBLE_RESUME); } @@ -275,6 +276,8 @@ tp_tfd_possible_drag_handle_event(struct tp_dispatch *tp, } break; case TFD_EVENT_MOTION: + /* this event must ensure it fires upon cursor movement -- alternatively, if + impossible, TODO: cursor should be pinned in this state to ensure this */ switch (nfingers_down) { default: log_tfd_bug(tp, event, nfingers_down); @@ -303,6 +306,12 @@ tp_tfd_possible_drag_handle_event(struct tp_dispatch *tp, } } + + /* TODO: Future improvement: When one finger moves considerably + faster than the others, don't average their deltas for cursor + position updates -- use the fastest finger only */ + + static void tp_tfd_drag_handle_event(struct tp_dispatch *tp, struct tp_touch *t, @@ -315,10 +324,7 @@ tp_tfd_drag_handle_event(struct tp_dispatch *tp, case TFD_EVENT_TOUCH_COUNT_DECREASE: switch (nfingers_down) { case 0: - case 1: tp_tfd_pin_fingers(tp); - /* removing all, or all but one, fingers gives you ~0.7 seconds to - place three fingers back on the touchpad before the drag ends */ tp_tfd_set_await_resume_timer(tp, time); tp->tfd.state = TFD_STATE_AWAIT_RESUME; @@ -327,15 +333,18 @@ tp_tfd_drag_handle_event(struct tp_dispatch *tp, // tp_tfd_set_await_more_fingers_timer(tp, time); // tp->tfd.state = TFD_STATE_POSSIBLE_RESUME; + break; + case 1: + tp_tfd_pin_fingers(tp); + tp_tfd_set_await_resume_timer(tp, time); + tp_tfd_set_await_more_fingers_timer(tp, time); + tp->tfd.state = TFD_STATE_POSSIBLE_ZERO_FINGERS; break; default: break; } break; case TFD_EVENT_MOTION: - /* TODO: Future improvement: When one finger moves considerably - faster than the others, don't average their deltas for cursor - position updates -- use the fastest finger only */ break; case TFD_EVENT_RESUME_TIMEOUT: case TFD_EVENT_TIMEOUT: @@ -352,6 +361,73 @@ tp_tfd_drag_handle_event(struct tp_dispatch *tp, } } + +/* Waiting for zero fingers. Drag has decreased to 1 finger, but it might be +a transitory phase towards 0 fingers. Allow a small amount of time for that +before allowing one finger to break out of the drag in the AWAIT state. Makes it +harder to end very fast, brief drags. */ +static void +tp_tfd_possible_zero_fingers_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tfd_event event, uint64_t time, + int nfingers_down) +{ + switch (event) { + case TFD_EVENT_TOUCH_COUNT_DECREASE: + switch (nfingers_down) { + case 0: + tp_tfd_clear_timer(tp); + tp->tfd.state = TFD_STATE_AWAIT_RESUME; + break; + default: + log_tfd_bug(tp, event, nfingers_down); + break; + } + break; + case TFD_EVENT_MOTION: + break; + case TFD_EVENT_RESUME_TIMEOUT: + /* this shouldn't have time to happen */ + log_tfd_bug(tp, event, nfingers_down); + tp->tfd.state = TFD_STATE_IDLE; + tp_tfd_clear_timer(tp); + tp_tfd_unpin_fingers(tp); + break; + case TFD_EVENT_TOUCH_COUNT_INCREASE: + /* an increase forces immediate evaluation as if the timer had fired */ + tp_tfd_clear_timer(tp); + /* fallthrough */ + case TFD_EVENT_TIMEOUT: + /* time to (most probably) transition to the AWAIT state with 0 or 1 fingers */ + switch (nfingers_down) { + case 0: + case 1: + case 2: + tp->tfd.state = TFD_STATE_AWAIT_RESUME; + break; + case 3: + tp_tfd_set_await_more_fingers_timer(tp, time); + tp->tfd.state = TFD_STATE_POSSIBLE_RESUME; + break; + default: + tp_tfd_unpin_fingers(tp); + tp->tfd.state = TFD_STATE_IDLE; + tp_tfd_clear_resume_timer(tp); + tp_tfd_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + break; + } + break; + case TFD_EVENT_TAP: + case TFD_EVENT_BUTTON: + tp_tfd_unpin_fingers(tp); + tp->tfd.state = TFD_STATE_IDLE; + tp_tfd_clear_resume_timer(tp); + tp_tfd_clear_timer(tp); + tp_tfd_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + break; + } +} + /* Drag-lock; After leaving 3 finger dragging there's a small time window where you can resume the drag with 3 fingers. */ static void @@ -621,6 +697,10 @@ tp_tfd_handle_event(struct tp_dispatch *tp, tp_tfd_drag_handle_event(tp, t, event, time, nfingers_down); break; + case TFD_STATE_POSSIBLE_ZERO_FINGERS: + tp_tfd_possible_zero_fingers_handle_event(tp, t, event, time, nfingers_down); + break; + case TFD_STATE_AWAIT_RESUME: tp_tfd_await_resume_handle_event(tp, t, event, time, nfingers_down); break; @@ -816,6 +896,7 @@ void tp_tfd_handle_tap(struct tp_dispatch *tp, uint64_t time) { switch (tp->tfd.state) { + case TFD_STATE_POSSIBLE_ZERO_FINGERS: case TFD_STATE_AWAIT_RESUME: case TFD_STATE_POSSIBLE_RESUME: tp_tfd_handle_event(tp, NULL, TFD_EVENT_TAP, time, tp->tfd.finger_count); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index b6807ccb..ddcbe2e3 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -136,15 +136,20 @@ enum tp_tap_state { enum tp_tfd_state { + /* [debounce] = brief states anticipating a further increase/decrease in finger + count, preventing unintended drops on account of motion events */ + /* waiting for 3 fingers */ TFD_STATE_IDLE, - /* 3 fingers down, possible 4+ f gesture */ + /* 3 fingers touching, possible 4+ f gesture */ TFD_STATE_POSSIBLE_DRAG, - /* 3 fingers down and button press has been output */ + /* 3 fingers touching and button press has been output */ TFD_STATE_DRAG, - /* drag-lock; waiting for drag continuation */ + /* [debounce] drag-lock; 1 finger touching, possibly going to 0 fingers */ + TFD_STATE_POSSIBLE_ZERO_FINGERS, + /* drag-lock; waiting for 3 finger drag continuation */ TFD_STATE_AWAIT_RESUME, - /* disambiguate between drag continuation and a possible 4+ gesture */ + /* [debounce] disambiguate between drag continuation and a possible 4+ gesture */ TFD_STATE_POSSIBLE_RESUME, };