mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-03-21 11:00:39 +01:00
touchpad: add support for fast swipe when 3fg drag is enabled
This adds a movement threshold (5mm) and a timeout (80ms) to the 3fg drag gesture. On 3fg down with 3fg drag enabled we immediately send a GESTURE_SWIPE event. After the timeout expires we check the movement of the fingers - if it is below the threshold cancel the swipe and hold a button down (i.e. a 3fg drag). Otherwise, continue with this being a swipe. This allows for swipe gestures to be used while 3fg drag is enabled. Above applies the same way for 4fg with 4fg drag enabled. Thresholds selected using the "yeah, that seems about alright" method, intentionally quite low because we assume that users that enable 3fg drag prefer 3fg dragging over swipe. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1410>
This commit is contained in:
parent
5b7b8f1bb2
commit
fe1d44637f
5 changed files with 358 additions and 37 deletions
|
|
@ -38,9 +38,11 @@ enum gesture_cancelled {
|
|||
#define DEFAULT_GESTURE_SWITCH_TIMEOUT usec_from_millis(100)
|
||||
#define DEFAULT_GESTURE_SWIPE_TIMEOUT usec_from_millis(150)
|
||||
#define DEFAULT_GESTURE_PINCH_TIMEOUT usec_from_millis(300)
|
||||
#define DRAG_3FG_OR_SWIPE_TIMEOUT usec_from_millis(80)
|
||||
|
||||
#define HOLD_AND_MOTION_THRESHOLD 0.5 /* mm */
|
||||
#define PINCH_DISAMBIGUATION_MOVE_THRESHOLD 1.5 /* mm */
|
||||
#define DRAG_3FG_OR_SWIPE_MOVE_THRESHOLD 5 /* mm */
|
||||
|
||||
enum gesture_event {
|
||||
GESTURE_EVENT_RESET,
|
||||
|
|
@ -55,7 +57,8 @@ enum gesture_event {
|
|||
GESTURE_EVENT_SCROLL_START,
|
||||
GESTURE_EVENT_SWIPE_START,
|
||||
GESTURE_EVENT_PINCH_START,
|
||||
GESTURE_EVENT_3FG_DRAG_START,
|
||||
GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START,
|
||||
GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT,
|
||||
GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT,
|
||||
};
|
||||
|
||||
|
|
@ -83,6 +86,8 @@ gesture_state_to_str(enum tp_gesture_state state)
|
|||
CASE_RETURN_STRING(GESTURE_STATE_PINCH);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_SWIPE_START);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_SWIPE);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG_OR_SWIPE_START);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG_OR_SWIPE);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG_START);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG_RELEASED);
|
||||
|
|
@ -106,7 +111,8 @@ gesture_event_to_str(enum gesture_event event)
|
|||
CASE_RETURN_STRING(GESTURE_EVENT_SCROLL_START);
|
||||
CASE_RETURN_STRING(GESTURE_EVENT_SWIPE_START);
|
||||
CASE_RETURN_STRING(GESTURE_EVENT_PINCH_START);
|
||||
CASE_RETURN_STRING(GESTURE_EVENT_3FG_DRAG_START);
|
||||
CASE_RETURN_STRING(GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START);
|
||||
CASE_RETURN_STRING(GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT);
|
||||
CASE_RETURN_STRING(GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT);
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -549,7 +555,7 @@ tp_gesture_handle_event_on_state_none(struct tp_dispatch *tp,
|
|||
*/
|
||||
if (!tp->tap.enabled &&
|
||||
tp->drag_3fg.nfingers == tp->gesture.finger_count) {
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_OR_SWIPE_START;
|
||||
} else {
|
||||
tp_gesture_set_hold_timer(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_UNKNOWN;
|
||||
|
|
@ -568,13 +574,21 @@ tp_gesture_handle_event_on_state_none(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_set_3fg_drag_3fg_or_swipe_timer(struct tp_dispatch *tp, usec_t time)
|
||||
{
|
||||
libinput_timer_set(&tp->gesture.drag_3fg_or_swipe_timer,
|
||||
usec_add(time, DRAG_3FG_OR_SWIPE_TIMEOUT));
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_unknown(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
|
|
@ -615,12 +629,13 @@ tp_gesture_handle_event_on_state_unknown(struct tp_dispatch *tp,
|
|||
tp_gesture_init_pinch(tp);
|
||||
tp->gesture.state = GESTURE_STATE_PINCH_START;
|
||||
break;
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_OR_SWIPE_START;
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -671,13 +686,15 @@ tp_gesture_handle_event_on_state_hold(struct tp_dispatch *tp,
|
|||
tp_gesture_init_pinch(tp);
|
||||
tp->gesture.state = GESTURE_STATE_PINCH_START;
|
||||
break;
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
tp_gesture_cancel(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_OR_SWIPE_START;
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_TIMEOUT:
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -718,7 +735,8 @@ tp_gesture_handle_event_on_state_hold_and_motion(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -764,7 +782,8 @@ tp_gesture_handle_event_on_state_pointer_motion(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -797,7 +816,8 @@ tp_gesture_handle_event_on_state_scroll_start(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_POINTER_MOTION_START:
|
||||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -832,7 +852,8 @@ tp_gesture_handle_event_on_state_scroll(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_POINTER_MOTION_START:
|
||||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -860,7 +881,8 @@ tp_gesture_handle_event_on_state_pinch_start(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -899,7 +921,8 @@ tp_gesture_handle_event_on_state_pinch(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -928,7 +951,8 @@ tp_gesture_handle_event_on_state_swipe_start(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -966,13 +990,101 @@ tp_gesture_handle_event_on_state_swipe(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_3fg_drag_or_swipe_start(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
usec_t time)
|
||||
{
|
||||
switch (event) {
|
||||
case GESTURE_EVENT_RESET:
|
||||
case GESTURE_EVENT_END:
|
||||
case GESTURE_EVENT_CANCEL:
|
||||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
tp->gesture.state = GESTURE_STATE_NONE;
|
||||
break;
|
||||
case GESTURE_EVENT_FINGER_SWITCH_TIMEOUT:
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
case GESTURE_EVENT_HOLD_TIMEOUT:
|
||||
case GESTURE_EVENT_POINTER_MOTION_START:
|
||||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_3fg_drag_or_swipe(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
usec_t time)
|
||||
{
|
||||
struct tp_touch *first = tp->gesture.touches[0],
|
||||
*second = tp->gesture.touches[1];
|
||||
struct phys_coords first_moved, second_moved;
|
||||
double first_mm, second_mm;
|
||||
|
||||
switch (event) {
|
||||
case GESTURE_EVENT_RESET:
|
||||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
tp->gesture.state = GESTURE_STATE_NONE;
|
||||
break;
|
||||
case GESTURE_EVENT_END:
|
||||
case GESTURE_EVENT_CANCEL: {
|
||||
bool cancelled = event == GESTURE_EVENT_CANCEL;
|
||||
gesture_notify_swipe_end(&tp->device->base,
|
||||
time,
|
||||
tp->gesture.finger_count,
|
||||
cancelled);
|
||||
tp->gesture.state = GESTURE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
case GESTURE_EVENT_FINGER_SWITCH_TIMEOUT:
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
case GESTURE_EVENT_HOLD_TIMEOUT:
|
||||
case GESTURE_EVENT_POINTER_MOTION_START:
|
||||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_or_swipe_timer);
|
||||
|
||||
first_moved = tp_gesture_mm_moved(tp, first);
|
||||
second_moved = tp_gesture_mm_moved(tp, second);
|
||||
first_mm = hypot(first_moved.x, first_moved.y);
|
||||
second_mm = hypot(second_moved.x, second_moved.y);
|
||||
if ((first_mm + second_mm) / 2.0 >= DRAG_3FG_OR_SWIPE_MOVE_THRESHOLD) {
|
||||
tp->gesture.state = GESTURE_STATE_SWIPE;
|
||||
} else {
|
||||
/* Cancel the swipe */
|
||||
tp_gesture_cancel(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_3fg_drag_start(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
|
|
@ -995,7 +1107,8 @@ tp_gesture_handle_event_on_state_3fg_drag_start(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -1050,7 +1163,8 @@ tp_gesture_handle_event_on_state_3fg_drag(struct tp_dispatch *tp,
|
|||
case GESTURE_EVENT_SCROLL_START:
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
|
|
@ -1110,10 +1224,13 @@ tp_gesture_handle_event_on_state_3fg_drag_released(struct tp_dispatch *tp,
|
|||
break;
|
||||
case GESTURE_EVENT_SWIPE_START:
|
||||
case GESTURE_EVENT_PINCH_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_START:
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_timer);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG;
|
||||
break;
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1158,6 +1275,14 @@ tp_gesture_handle_event(struct tp_dispatch *tp, enum gesture_event event, usec_t
|
|||
case GESTURE_STATE_SWIPE:
|
||||
tp_gesture_handle_event_on_state_swipe(tp, event, time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE_START:
|
||||
tp_gesture_handle_event_on_state_3fg_drag_or_swipe_start(tp,
|
||||
event,
|
||||
time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE:
|
||||
tp_gesture_handle_event_on_state_3fg_drag_or_swipe(tp, event, time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
tp_gesture_handle_event_on_state_3fg_drag_start(tp, event, time);
|
||||
break;
|
||||
|
|
@ -1208,6 +1333,14 @@ tp_gesture_3fg_drag_timeout(usec_t now, void *data)
|
|||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT, now);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_3fg_drag_or_swipe_timeout(usec_t now, void *data)
|
||||
{
|
||||
struct tp_dispatch *tp = data;
|
||||
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_OR_SWIPE_TIMEOUT, now);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, usec_t time)
|
||||
{
|
||||
|
|
@ -1250,7 +1383,9 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, usec_t time)
|
|||
if (tp->gesture.enabled && tp->gesture.finger_count > 2 &&
|
||||
tp->gesture.finger_count > tp->num_slots) {
|
||||
if (tp->drag_3fg.nfingers == tp->gesture.finger_count)
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_START, time);
|
||||
tp_gesture_handle_event(tp,
|
||||
GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START,
|
||||
time);
|
||||
else
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SWIPE_START, time);
|
||||
return;
|
||||
|
|
@ -1280,7 +1415,9 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, usec_t time)
|
|||
if (tp->gesture.finger_count == 2)
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SCROLL_START, time);
|
||||
else if (tp->drag_3fg.nfingers == tp->gesture.finger_count)
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_START, time);
|
||||
tp_gesture_handle_event(tp,
|
||||
GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START,
|
||||
time);
|
||||
else
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SWIPE_START, time);
|
||||
|
||||
|
|
@ -1288,10 +1425,12 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, usec_t time)
|
|||
}
|
||||
|
||||
/* If 3fg dragging touches are within a 60x10mm box, start
|
||||
* dragging immediately */
|
||||
* dragging (or swiping) immediately */
|
||||
if (tp->gesture.finger_count == tp->drag_3fg.nfingers && distance_mm.x < 60.0 &&
|
||||
distance_mm.y < 10.0) {
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_START, time);
|
||||
tp_gesture_handle_event(tp,
|
||||
GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START,
|
||||
time);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1369,7 +1508,9 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, usec_t time)
|
|||
}
|
||||
|
||||
if (tp->drag_3fg.nfingers == tp->gesture.finger_count) {
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_START, time);
|
||||
tp_gesture_handle_event(tp,
|
||||
GESTURE_EVENT_3FG_DRAG_OR_SWIPE_START,
|
||||
time);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1724,11 +1865,45 @@ tp_gesture_handle_state_3fg_drag_released(struct tp_dispatch *tp,
|
|||
tp_gesture_detect_motion_gestures(tp, time);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state_3fg_drag_or_swipe(struct tp_dispatch *tp, usec_t time)
|
||||
{
|
||||
struct device_float_coords raw;
|
||||
struct normalized_coords delta, unaccel;
|
||||
|
||||
raw = tp_get_average_touches_delta(tp);
|
||||
delta = tp_filter_motion(tp, &raw, time);
|
||||
|
||||
if (!normalized_is_zero(delta) || !device_float_is_zero(raw)) {
|
||||
unaccel = tp_filter_motion_unaccelerated(tp, &raw, time);
|
||||
gesture_notify_swipe(&tp->device->base,
|
||||
time,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
|
||||
tp->gesture.finger_count,
|
||||
&delta,
|
||||
&unaccel);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state_3fg_drag_or_swipe_start(struct tp_dispatch *tp, usec_t time)
|
||||
{
|
||||
const struct normalized_coords zero = { 0.0, 0.0 };
|
||||
gesture_notify_swipe(&tp->device->base,
|
||||
time,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN,
|
||||
tp->gesture.finger_count,
|
||||
&zero,
|
||||
&zero);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_OR_SWIPE;
|
||||
tp_gesture_set_3fg_drag_3fg_or_swipe_timer(tp, time);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state(struct tp_dispatch *tp, usec_t time, bool ignore_motion)
|
||||
{
|
||||
enum tp_gesture_state oldstate = tp->gesture.state;
|
||||
enum tp_gesture_state transitions[16] = { 0 };
|
||||
enum tp_gesture_state transitions[18] = { 0 };
|
||||
enum tp_gesture_state *transition_state = transitions;
|
||||
|
||||
#define REMEMBER_TRANSITION(_ts, _state) { \
|
||||
|
|
@ -1796,6 +1971,14 @@ tp_gesture_handle_state(struct tp_dispatch *tp, usec_t time, bool ignore_motion)
|
|||
tp_gesture_handle_state_3fg_drag_released(tp, time, ignore_motion);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
if (tp->gesture.state == GESTURE_STATE_3FG_DRAG_OR_SWIPE) {
|
||||
tp_gesture_handle_state_3fg_drag_or_swipe(tp, time);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
if (tp->gesture.state == GESTURE_STATE_3FG_DRAG_OR_SWIPE_START) {
|
||||
tp_gesture_handle_state_3fg_drag_or_swipe_start(tp, time);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
|
||||
#undef REMEMBER_TRANSITION
|
||||
|
||||
|
|
@ -1893,6 +2076,7 @@ tp_gesture_end(struct tp_dispatch *tp, usec_t time, enum gesture_cancelled cance
|
|||
case GESTURE_STATE_PINCH_START:
|
||||
case GESTURE_STATE_SWIPE_START:
|
||||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE_START:
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_RESET, time);
|
||||
break;
|
||||
case GESTURE_STATE_HOLD:
|
||||
|
|
@ -1903,6 +2087,7 @@ tp_gesture_end(struct tp_dispatch *tp, usec_t time, enum gesture_cancelled cance
|
|||
case GESTURE_STATE_SWIPE:
|
||||
case GESTURE_STATE_3FG_DRAG:
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE:
|
||||
switch (cancelled) {
|
||||
case CANCEL_GESTURE:
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_CANCEL, time);
|
||||
|
|
@ -1947,6 +2132,11 @@ tp_gesture_cancel_motion_gestures(struct tp_dispatch *tp, usec_t time)
|
|||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE:
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE_START:
|
||||
evdev_log_debug(tp->device, "Cancelling motion gestures\n");
|
||||
tp_gesture_cancel(tp, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1988,6 +2178,8 @@ tp_gesture_debounce_finger_changes(struct tp_dispatch *tp)
|
|||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
case GESTURE_STATE_3FG_DRAG:
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE:
|
||||
case GESTURE_STATE_3FG_DRAG_OR_SWIPE_START:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2230,6 +2422,15 @@ tp_init_gesture(struct tp_dispatch *tp)
|
|||
timer_name,
|
||||
tp_gesture_3fg_drag_timeout,
|
||||
tp);
|
||||
snprintf(timer_name,
|
||||
sizeof(timer_name),
|
||||
"%s drag_or_swipe",
|
||||
evdev_device_get_sysname(tp->device));
|
||||
libinput_timer_init(&tp->gesture.drag_3fg_or_swipe_timer,
|
||||
tp_libinput_context(tp),
|
||||
timer_name,
|
||||
tp_gesture_3fg_drag_or_swipe_timeout,
|
||||
tp);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2238,4 +2439,5 @@ tp_remove_gesture(struct tp_dispatch *tp)
|
|||
libinput_timer_cancel(&tp->gesture.finger_count_switch_timer);
|
||||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_timer);
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_or_swipe_timer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1975,6 +1975,7 @@ tp_interface_destroy(struct evdev_dispatch *dispatch)
|
|||
libinput_timer_destroy(&tp->gesture.finger_count_switch_timer);
|
||||
libinput_timer_destroy(&tp->gesture.hold_timer);
|
||||
libinput_timer_destroy(&tp->gesture.drag_3fg_timer);
|
||||
libinput_timer_destroy(&tp->gesture.drag_3fg_or_swipe_timer);
|
||||
free(tp->touches);
|
||||
free(tp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ enum tp_gesture_state {
|
|||
GESTURE_STATE_PINCH,
|
||||
GESTURE_STATE_SWIPE_START,
|
||||
GESTURE_STATE_SWIPE,
|
||||
GESTURE_STATE_3FG_DRAG_OR_SWIPE_START,
|
||||
GESTURE_STATE_3FG_DRAG_OR_SWIPE,
|
||||
GESTURE_STATE_3FG_DRAG_START,
|
||||
GESTURE_STATE_3FG_DRAG,
|
||||
GESTURE_STATE_3FG_DRAG_RELEASED,
|
||||
|
|
@ -371,6 +373,8 @@ struct tp_dispatch {
|
|||
|
||||
struct libinput_timer drag_3fg_timer;
|
||||
usec_t drag_3fg_release_time;
|
||||
|
||||
struct libinput_timer drag_3fg_or_swipe_timer;
|
||||
} gesture;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -1371,6 +1371,7 @@ _litest_timeout(struct libinput *li, const char *func, int lineno, int millis);
|
|||
#define litest_timeout_tablet_proxout(li_) litest_timeout(li_, 170)
|
||||
#define litest_timeout_touch_arbitration(li_) litest_timeout(li_, 100)
|
||||
#define litest_timeout_hysteresis(li_) litest_timeout(li_, 90)
|
||||
#define litest_timeout_3fg_drag_or_swipe(li_) litest_timeout(li_, 90)
|
||||
#define litest_timeout_3fg_drag(li_) litest_timeout(li_, 800)
|
||||
#define litest_timeout_eraser_button(li_) litest_timeout(li_, 50)
|
||||
|
||||
|
|
|
|||
|
|
@ -1587,6 +1587,18 @@ START_TEST(gestures_hold_and_motion_after_timeout)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
drain_cancelled_swipe_gesture(struct libinput *li)
|
||||
{
|
||||
litest_drain_events_of_type(li,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE);
|
||||
|
||||
_destroy_(libinput_event) *end = libinput_get_event(li);
|
||||
auto gev = litest_is_gesture_event(end, LIBINPUT_EVENT_GESTURE_SWIPE_END, -1);
|
||||
litest_assert(libinput_event_gesture_get_cancelled(gev));
|
||||
}
|
||||
|
||||
START_TEST(gestures_3fg_drag)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -1626,21 +1638,25 @@ START_TEST(gestures_3fg_drag)
|
|||
litest_assert_empty_queue(li);
|
||||
} else {
|
||||
litest_checkpoint(
|
||||
"Expecting immediate button press as tapping is disabled");
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
"Expecting immediate swipe begin tapping is disabled");
|
||||
litest_assert_gesture_event(li,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN,
|
||||
finger_count);
|
||||
}
|
||||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
for (uint32_t i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
if (i ==
|
||||
0) /* Wait after the first movement to escape the swipe */
|
||||
litest_timeout_3fg_drag_or_swipe(li);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
|
||||
if (tap_enabled) {
|
||||
litest_checkpoint("Expecting late button press as tapping is enabled");
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
}
|
||||
drain_cancelled_swipe_gesture(li);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
|
|
@ -1688,10 +1704,15 @@ START_TEST(gestures_3fg_drag_lock_resume_3fg_motion)
|
|||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
for (uint32_t i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
if (i ==
|
||||
0) /* Wait after the first movement to escape the swipe */
|
||||
litest_timeout_3fg_drag_or_swipe(li);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
drain_cancelled_swipe_gesture(li);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
|
|
@ -1777,10 +1798,15 @@ START_TEST(gestures_3fg_drag_lock_resume_3fg_release_no_motion)
|
|||
litest_dispatch(li);
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
for (uint32_t i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
if (i ==
|
||||
0) /* Wait after the first movement to escape the swipe */
|
||||
litest_timeout_3fg_drag_or_swipe(li);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
drain_cancelled_swipe_gesture(li);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
|
|
@ -1870,10 +1896,15 @@ START_TEST(gestures_3fg_drag_lock_resume_1fg_motion)
|
|||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
for (uint32_t i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
if (i ==
|
||||
0) /* Wait after the first movement to escape the swipe */
|
||||
litest_timeout_3fg_drag_or_swipe(li);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
drain_cancelled_swipe_gesture(li);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
|
|
@ -1943,10 +1974,15 @@ START_TEST(gestures_3fg_drag_lock_resume_2fg_scroll)
|
|||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
for (uint32_t i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
if (i ==
|
||||
0) /* Wait after the first movement to escape the swipe */
|
||||
litest_timeout_3fg_drag_or_swipe(li);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
drain_cancelled_swipe_gesture(li);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
|
|
@ -2012,14 +2048,19 @@ START_TEST(gestures_3fg_drag_lock_resume_1fg_tap)
|
|||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (int i = 0; i < finger_count; i++)
|
||||
for (int i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
if (i ==
|
||||
0) /* Wait after the first movement to escape the swipe */
|
||||
litest_timeout_3fg_drag_or_swipe(li);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
litest_drain_events_of_type(li,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
-1);
|
||||
drain_cancelled_swipe_gesture(li);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
|
|
@ -2054,6 +2095,72 @@ START_TEST(gestures_3fg_drag_lock_resume_1fg_tap)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag_fast_swipe)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
uint32_t finger_count = litest_test_param_get_u32(test_env->params, "fingers");
|
||||
bool tap_enabled = litest_test_param_get_bool(test_env->params, "tap-enabled");
|
||||
|
||||
if (litest_slot_count(dev) < 3)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
if (libinput_device_config_3fg_drag_get_finger_count(dev->libinput_device) <
|
||||
(int)finger_count)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
litest_enable_3fg_drag(dev->libinput_device, finger_count);
|
||||
if (tap_enabled)
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
else
|
||||
litest_disable_tap(dev->libinput_device);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
double y = 30.0;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_down(dev, i, 10 + i, y);
|
||||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (uint32_t i = 0; i < finger_count; i++) {
|
||||
litest_touch_move(dev, i, 10 + i, y);
|
||||
}
|
||||
litest_dispatch(li);
|
||||
}
|
||||
|
||||
litest_drain_events_of_type(li,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
|
||||
auto begin = libinput_get_event(li);
|
||||
litest_is_gesture_event(begin,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN,
|
||||
finger_count);
|
||||
libinput_event_destroy(begin);
|
||||
|
||||
struct libinput_event *update;
|
||||
while ((update = libinput_get_event(li))) {
|
||||
litest_is_gesture_event(update,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
|
||||
finger_count);
|
||||
libinput_event_destroy(update);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
|
||||
auto end = libinput_get_event(li);
|
||||
auto gev = litest_is_gesture_event(end,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_END,
|
||||
finger_count);
|
||||
litest_assert(!libinput_event_gesture_get_cancelled(gev));
|
||||
libinput_event_destroy(end);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_COLLECTION(gestures)
|
||||
{
|
||||
/* clang-format off */
|
||||
|
|
@ -2136,6 +2243,12 @@ TEST_COLLECTION(gestures)
|
|||
litest_add_parametrized(gestures_3fg_drag_lock_resume_1fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
}
|
||||
|
||||
litest_with_parameters(params,
|
||||
"fingers", 'u', 2, 3, 4,
|
||||
"tap-enabled", 'b') {
|
||||
litest_add_parametrized(gestures_3fg_drag_fast_swipe, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
}
|
||||
|
||||
/* Timing-sensitive test, valgrind is too slow */
|
||||
if (!RUNNING_ON_VALGRIND)
|
||||
litest_add(gestures_swipe_3fg_unaccel, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue