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>
This commit is contained in:
satrmb 2020-08-02 15:28:22 +02:00
parent 71ad1768e0
commit 484ccb0fb3
3 changed files with 28 additions and 55 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 168 KiB

View file

@ -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

View file

@ -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 */