mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-03 20:30:27 +01:00
touchpad: implement support for three-finger drag
Exposed via new configuration option this enables 3 and 4 finger dragging on touchpads. When enabled a 3/4 finger swipe gesture is actually a button down + motion + button up sequence. If tapping is disabled the drag starts immediately, if tapping is enabled the drag starts after the tap timeout/motion so we can distinguish between a tap and a drag. When fingers are released: - if two fingers remain -> keep dragging - if one finger remains -> release drag, switch to pointer motion When 3/4 fingers are set down immediately after releasing all fingers the drag continues, similar to the tap drag lock feature. This drag lock is not currently configurable. This matches the macos behavior for the same feature. Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1042>
This commit is contained in:
parent
ae86d8b1b6
commit
1d9e307e2b
16 changed files with 1199 additions and 5 deletions
|
|
@ -37,6 +37,19 @@ Tapping is usually available on touchpads and the touchpad part of external
|
|||
graphics tablets. Tapping is usually **not** available on touch screens,
|
||||
for those devices it is expected to be implemented by the toolkit.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Three-finger drag
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Three-finger drag allows emulates the mouse button down while three fingers
|
||||
are down on a touchpad without the need to press a physical button or use
|
||||
:ref:`tapndrag`. See :ref:`drag_3fg` for details on how this feature works.
|
||||
|
||||
Three-finger drag is usually available on touchpads and the touchpad part of
|
||||
external graphics tablets. Three-finger drag is usually **not** available on
|
||||
touch screens, for those devices it is expected to be implemented by the
|
||||
toolkit.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Send Events Mode
|
||||
------------------------------------------------------------------------------
|
||||
|
|
|
|||
40
doc/user/drag-3fg.rst
Normal file
40
doc/user/drag-3fg.rst
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
.. _drag_3fg:
|
||||
|
||||
==============================================================================
|
||||
Three-finger drag
|
||||
==============================================================================
|
||||
|
||||
Three-finger drag is a feature available on touchpads that emulates logical
|
||||
button presses if three fingers are moving on the touchpad.
|
||||
|
||||
Three-finger drag is independent from :ref:`tapping` though some specific
|
||||
behaviors may change when both features are enabled. For example, with
|
||||
tapping *disabled* a three-finger gesture will virtually always be a three-finger
|
||||
drag. With tapping *enabled* a three finger gesture may be a three finger drag
|
||||
and a short delay is required to disambiguate between the two.
|
||||
|
||||
|
||||
The exact behavior of three-finger drag is implementation defined and may
|
||||
subtly change. As a general rule, the following constraints can be expected:
|
||||
|
||||
- three fingers down and movement trigger a button down and subsequent motion
|
||||
events (i.e. a drag)
|
||||
- releasing one finger while keeping two fingers down will keep the drag
|
||||
and *not* switch to :ref:`twofinger_scrolling`.
|
||||
- releasing two fingers while keeping one finger down will end the drag
|
||||
(and thus release the button) and switch to normal pointer motion
|
||||
- releasing all three fingers and putting three fingers back on the touchpad
|
||||
immediately will keep the drag (i.e. behave as if the fingers were
|
||||
never lifted)
|
||||
|
||||
- if tapping is enabled: a three finger tap immediately after a three-finger
|
||||
drag will *not* tap, the user needs to wait past the timeout to
|
||||
three-finger tap
|
||||
|
||||
- releasing all three fingers and putting one or two fingers back on
|
||||
the touchpad will end the drag (and thus release the button)
|
||||
and proceed with pointer motion or two-finger scrolling, if applicable
|
||||
|
||||
- if tapping is enabled: a one or two finger tap immediately after a
|
||||
three-finger drag will trigger a one or two finger tap. The user does
|
||||
not have to wait past the drag release timeout
|
||||
|
|
@ -22,6 +22,7 @@ to be useful.
|
|||
scrolling.rst
|
||||
t440-support.rst
|
||||
tapping.rst
|
||||
drag-3fg.rst
|
||||
tablet-support.rst
|
||||
switches.rst
|
||||
touchpad-pressure.rst
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ src_rst = files(
|
|||
'contributing.rst',
|
||||
'device-configuration-via-udev.rst',
|
||||
'device-quirks.rst',
|
||||
'drag-3fg.rst',
|
||||
'faqs.rst',
|
||||
'gestures.rst',
|
||||
'incorrectly-enabled-hires.rst',
|
||||
|
|
|
|||
|
|
@ -55,6 +55,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_RELEASE_TIMEOUT,
|
||||
};
|
||||
|
||||
/*****************************************
|
||||
|
|
@ -81,6 +83,9 @@ 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_START);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG);
|
||||
CASE_RETURN_STRING(GESTURE_STATE_3FG_DRAG_RELEASED);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -101,6 +106,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_RELEASE_TIMEOUT);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -313,6 +320,16 @@ tp_gesture_init_pinch(struct tp_dispatch *tp)
|
|||
tp->gesture.prev_scale = 1.0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_gesture_init_3fg_drag(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_gesture_stop_3fg_drag(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_set_scroll_buildup(struct tp_dispatch *tp)
|
||||
{
|
||||
|
|
@ -540,8 +557,16 @@ tp_gesture_handle_event_on_state_none(struct tp_dispatch *tp,
|
|||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
break;
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
tp_gesture_set_hold_timer(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_UNKNOWN;
|
||||
/* Note: this makes 3fg drag more responsive but disables
|
||||
* 3fg pinch/hold. Those are niche enough to not worry about
|
||||
* for now.
|
||||
*/
|
||||
if (!tp->tap.enabled && tp->drag_3fg.nfingers == tp->gesture.finger_count) {
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
} else {
|
||||
tp_gesture_set_hold_timer(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_TIMEOUT:
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
|
|
@ -556,6 +581,8 @@ 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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -600,8 +627,14 @@ 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:
|
||||
libinput_timer_cancel(&tp->gesture.hold_timer);
|
||||
tp_gesture_init_3fg_drag(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -649,9 +682,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:
|
||||
tp_gesture_cancel(tp, time);
|
||||
tp_gesture_init_3fg_drag(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_START;
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_TIMEOUT:
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -689,6 +728,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -732,6 +773,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -763,6 +806,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -796,6 +841,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -822,6 +869,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -858,6 +907,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -885,6 +936,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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
|
|
@ -921,11 +974,159 @@ 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_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_3fg_drag_start(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
uint64_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_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_set_3fg_drag_timer(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
tp->gesture.drag_3fg_release_time = time;
|
||||
libinput_timer_set(&tp->gesture.drag_3fg_timer, time + ms2us(700));
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_3fg_drag(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
uint64_t time)
|
||||
{
|
||||
switch(event) {
|
||||
case GESTURE_EVENT_RESET:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
case GESTURE_EVENT_CANCEL:
|
||||
/* If the gesture is cancelled we release the button immediately */
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
tp->gesture.drag_3fg_release_time,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->gesture.state = GESTURE_STATE_NONE;
|
||||
break;
|
||||
case GESTURE_EVENT_END:
|
||||
/* If the gesture ends we start the timer so we
|
||||
* can keep dragging */
|
||||
tp_gesture_set_3fg_drag_timer(tp, time);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG_RELEASED;
|
||||
break;
|
||||
case GESTURE_EVENT_FINGER_SWITCH_TIMEOUT:
|
||||
if (tp->gesture.finger_count_pending < 2) {
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
tp->gesture.drag_3fg_release_time,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->gesture.state = GESTURE_STATE_NONE;
|
||||
}
|
||||
break;
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
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_START:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event_on_state_3fg_drag_released(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
uint64_t time)
|
||||
{
|
||||
switch(event) {
|
||||
case GESTURE_EVENT_RESET:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
case GESTURE_EVENT_END:
|
||||
case GESTURE_EVENT_CANCEL:
|
||||
case GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT:
|
||||
tp_gesture_stop_3fg_drag(tp, time);
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_timer);
|
||||
libinput_timer_cancel(&tp->gesture.finger_count_switch_timer);
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
tp->gesture.drag_3fg_release_time,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->gesture.state = GESTURE_STATE_NONE;
|
||||
break;
|
||||
case GESTURE_EVENT_FINGER_SWITCH_TIMEOUT:
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
if (tp->gesture.finger_count_pending == tp->drag_3fg.nfingers) {
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_timer);
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG;
|
||||
}
|
||||
break;
|
||||
case GESTURE_EVENT_FINGER_DETECTED:
|
||||
break;
|
||||
case GESTURE_EVENT_POINTER_MOTION_START:
|
||||
tp_gesture_stop_3fg_drag(tp, time);
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_timer);
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
tp->gesture.drag_3fg_release_time,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->gesture.state = GESTURE_STATE_POINTER_MOTION;
|
||||
break;
|
||||
case GESTURE_EVENT_HOLD_AND_MOTION_START:
|
||||
case GESTURE_EVENT_HOLD_TIMEOUT:
|
||||
log_gesture_bug(tp, event);
|
||||
break;
|
||||
/* Anything that's detected as gesture in this state
|
||||
* will be continue the current 3fg drag gesture */
|
||||
case GESTURE_EVENT_SCROLL_START:
|
||||
libinput_timer_cancel(&tp->gesture.drag_3fg_timer);
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
tp->gesture.drag_3fg_release_time,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->gesture.state = GESTURE_STATE_SCROLL_START;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_event(struct tp_dispatch *tp,
|
||||
enum gesture_event event,
|
||||
|
|
@ -969,6 +1170,15 @@ tp_gesture_handle_event(struct tp_dispatch *tp,
|
|||
case GESTURE_STATE_SWIPE:
|
||||
tp_gesture_handle_event_on_state_swipe(tp, event, time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
tp_gesture_handle_event_on_state_3fg_drag_start(tp, event, time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG:
|
||||
tp_gesture_handle_event_on_state_3fg_drag(tp, event, time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
tp_gesture_handle_event_on_state_3fg_drag_released(tp, event, time);
|
||||
break;
|
||||
}
|
||||
|
||||
if (oldstate != tp->gesture.state) {
|
||||
|
|
@ -1002,6 +1212,14 @@ tp_gesture_tap_timeout(struct tp_dispatch *tp, uint64_t time)
|
|||
tp_gesture_handle_event(tp, GESTURE_EVENT_TAP_TIMEOUT, time);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_3fg_drag_timeout(uint64_t now, void *data)
|
||||
{
|
||||
struct tp_dispatch *tp = data;
|
||||
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_RELEASE_TIMEOUT, now);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
|
|
@ -1044,10 +1262,13 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, uint64_t time)
|
|||
}
|
||||
|
||||
/* If we have more fingers than slots, we don't know where the
|
||||
* fingers are. Default to swipe */
|
||||
* fingers are. Default to swipe/3fg drag */
|
||||
if (tp->gesture.enabled && tp->gesture.finger_count > 2 &&
|
||||
tp->gesture.finger_count > tp->num_slots) {
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SWIPE_START, time);
|
||||
if (tp->drag_3fg.nfingers == tp->gesture.finger_count)
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_START, time);
|
||||
else
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SWIPE_START, time);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1073,6 +1294,8 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, uint64_t time)
|
|||
time > (tp->gesture.initial_time + DEFAULT_GESTURE_SWIPE_TIMEOUT)) {
|
||||
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);
|
||||
else
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SWIPE_START, time);
|
||||
|
||||
|
|
@ -1154,6 +1377,11 @@ tp_gesture_detect_motion_gestures(struct tp_dispatch *tp, uint64_t time)
|
|||
return;
|
||||
}
|
||||
|
||||
if (tp->drag_3fg.nfingers == tp->gesture.finger_count) {
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_3FG_DRAG_START, time);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tp->gesture.enabled) {
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_SWIPE_START, time);
|
||||
return;
|
||||
|
|
@ -1468,6 +1696,40 @@ tp_gesture_handle_state_pinch(struct tp_dispatch *tp, uint64_t time)
|
|||
tp->gesture.prev_scale = scale;
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state_3fg_drag_start(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
time,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
/* FIXME: immediately send a motion event? */
|
||||
tp->gesture.state = GESTURE_STATE_3FG_DRAG;
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state_3fg_drag(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
if (!(tp->queued & TOUCHPAD_EVENT_MOTION))
|
||||
return;
|
||||
|
||||
struct device_float_coords raw = tp_get_average_touches_delta(tp);
|
||||
struct normalized_coords delta = tp_filter_motion(tp, &raw, time);
|
||||
|
||||
if (!normalized_is_zero(delta) || !device_float_is_zero(raw)) {
|
||||
if (tp->queued & TOUCHPAD_EVENT_MOTION)
|
||||
tp_gesture_post_pointer_motion(tp, time);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state_3fg_drag_released(struct tp_dispatch *tp,
|
||||
uint64_t time,
|
||||
bool ignore_motion)
|
||||
{
|
||||
tp_gesture_detect_motion_gestures(tp, time);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time,
|
||||
bool ignore_motion)
|
||||
|
|
@ -1529,6 +1791,18 @@ tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time,
|
|||
tp_gesture_handle_state_pinch_start(tp, time);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
if (tp->gesture.state == GESTURE_STATE_3FG_DRAG) {
|
||||
tp_gesture_handle_state_3fg_drag(tp, time);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
if (tp->gesture.state == GESTURE_STATE_3FG_DRAG_START) {
|
||||
tp_gesture_handle_state_3fg_drag_start(tp, time);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
if (tp->gesture.state == GESTURE_STATE_3FG_DRAG_RELEASED) {
|
||||
tp_gesture_handle_state_3fg_drag_released(tp, time, ignore_motion);
|
||||
REMEMBER_TRANSITION(transition_state, tp->gesture.state);
|
||||
}
|
||||
|
||||
#undef REMEMBER_TRANSITION
|
||||
|
||||
|
|
@ -1628,6 +1902,7 @@ tp_gesture_end(struct tp_dispatch *tp, uint64_t time, enum gesture_cancelled can
|
|||
case GESTURE_STATE_SCROLL_START:
|
||||
case GESTURE_STATE_PINCH_START:
|
||||
case GESTURE_STATE_SWIPE_START:
|
||||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_RESET, time);
|
||||
break;
|
||||
case GESTURE_STATE_HOLD:
|
||||
|
|
@ -1636,6 +1911,8 @@ tp_gesture_end(struct tp_dispatch *tp, uint64_t time, enum gesture_cancelled can
|
|||
case GESTURE_STATE_SCROLL:
|
||||
case GESTURE_STATE_PINCH:
|
||||
case GESTURE_STATE_SWIPE:
|
||||
case GESTURE_STATE_3FG_DRAG:
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
switch (cancelled) {
|
||||
case CANCEL_GESTURE:
|
||||
tp_gesture_handle_event(tp, GESTURE_EVENT_CANCEL, time);
|
||||
|
|
@ -1657,12 +1934,14 @@ tp_gesture_cancel(struct tp_dispatch *tp, uint64_t time)
|
|||
void
|
||||
tp_gesture_cancel_motion_gestures(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
|
||||
switch (tp->gesture.state) {
|
||||
case GESTURE_STATE_NONE:
|
||||
case GESTURE_STATE_UNKNOWN:
|
||||
case GESTURE_STATE_SCROLL_START:
|
||||
case GESTURE_STATE_PINCH_START:
|
||||
case GESTURE_STATE_SWIPE_START:
|
||||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
break;
|
||||
case GESTURE_STATE_HOLD:
|
||||
break;
|
||||
|
|
@ -1671,8 +1950,13 @@ tp_gesture_cancel_motion_gestures(struct tp_dispatch *tp, uint64_t time)
|
|||
case GESTURE_STATE_SCROLL:
|
||||
case GESTURE_STATE_PINCH:
|
||||
case GESTURE_STATE_SWIPE:
|
||||
evdev_log_debug(tp->device, "Cancelling motion gestures\n");
|
||||
tp_gesture_cancel(tp, time);
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG:
|
||||
break;
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1711,6 +1995,9 @@ tp_gesture_debounce_finger_changes(struct tp_dispatch *tp)
|
|||
case GESTURE_STATE_SCROLL:
|
||||
case GESTURE_STATE_PINCH:
|
||||
case GESTURE_STATE_SWIPE:
|
||||
case GESTURE_STATE_3FG_DRAG_START:
|
||||
case GESTURE_STATE_3FG_DRAG_RELEASED:
|
||||
case GESTURE_STATE_3FG_DRAG:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1751,7 +2038,7 @@ tp_gesture_update_finger_state(struct tp_dispatch *tp, uint64_t time)
|
|||
} else if (active_touches != tp->gesture.finger_count_pending) {
|
||||
tp->gesture.finger_count_pending = active_touches;
|
||||
libinput_timer_set(&tp->gesture.finger_count_switch_timer,
|
||||
time + DEFAULT_GESTURE_SWITCH_TIMEOUT);
|
||||
time + DEFAULT_GESTURE_SWITCH_TIMEOUT);
|
||||
}
|
||||
} else {
|
||||
tp->gesture.finger_count_pending = 0;
|
||||
|
|
@ -1800,6 +2087,94 @@ tp_gesture_get_hold_default(struct libinput_device *device)
|
|||
LIBINPUT_CONFIG_HOLD_DISABLED;
|
||||
}
|
||||
|
||||
static int
|
||||
tp_3fg_drag_count(struct libinput_device *device)
|
||||
{
|
||||
struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
|
||||
struct tp_dispatch *tp = tp_dispatch(dispatch);
|
||||
|
||||
/* If we can't to gestures we can't do 3fg drag */
|
||||
if (!tp_gesture_are_gestures_enabled(tp))
|
||||
return 0;
|
||||
|
||||
/* For now return the number of MT slots until we need to figure out
|
||||
* if we can implement this on a 2-finger BTN_TOOL_TRIPLETAP device */
|
||||
return tp->num_slots;
|
||||
}
|
||||
|
||||
static enum libinput_config_status
|
||||
tp_3fg_drag_set_enabled(struct libinput_device *device,
|
||||
enum libinput_config_3fg_drag_state enabled)
|
||||
{
|
||||
struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
|
||||
struct tp_dispatch *tp = tp_dispatch(dispatch);
|
||||
|
||||
if (tp_3fg_drag_count(device) < 3)
|
||||
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
|
||||
|
||||
switch (enabled) {
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_DISABLED:
|
||||
tp->drag_3fg.want_nfingers = 0;
|
||||
break;
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG:
|
||||
tp->drag_3fg.want_nfingers = 3;
|
||||
break;
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG:
|
||||
tp->drag_3fg.want_nfingers = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
tp_3fg_drag_apply_config(evdev_device(device));
|
||||
|
||||
return LIBINPUT_CONFIG_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static enum libinput_config_3fg_drag_state
|
||||
tp_3fg_drag_get_enabled(struct libinput_device *device)
|
||||
{
|
||||
struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
|
||||
struct tp_dispatch *tp = tp_dispatch(dispatch);
|
||||
|
||||
switch (tp->drag_3fg.want_nfingers) {
|
||||
case 3:
|
||||
return LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG;
|
||||
case 4:
|
||||
return LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG;
|
||||
}
|
||||
return LIBINPUT_CONFIG_3FG_DRAG_DISABLED;
|
||||
}
|
||||
|
||||
static enum libinput_config_3fg_drag_state
|
||||
tp_3fg_drag_default(struct tp_dispatch *tp)
|
||||
{
|
||||
return LIBINPUT_CONFIG_3FG_DRAG_DISABLED;
|
||||
}
|
||||
|
||||
static enum libinput_config_3fg_drag_state
|
||||
tp_3fg_drag_get_default_enabled(struct libinput_device *device)
|
||||
{
|
||||
struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
|
||||
struct tp_dispatch *tp = tp_dispatch(dispatch);
|
||||
|
||||
return tp_3fg_drag_default(tp);
|
||||
}
|
||||
|
||||
void
|
||||
tp_3fg_drag_apply_config(struct evdev_device *device)
|
||||
{
|
||||
struct tp_dispatch *tp = (struct tp_dispatch *)device->dispatch;
|
||||
|
||||
if (tp->drag_3fg.want_nfingers == tp->drag_3fg.nfingers)
|
||||
return;
|
||||
|
||||
if (tp->nfingers_down)
|
||||
return;
|
||||
|
||||
tp->drag_3fg.nfingers = tp->drag_3fg.want_nfingers;
|
||||
|
||||
evdev_log_debug(device, "touchpad-3fg-drag: drag is now for %zd fingers\n", tp->drag_3fg.nfingers);
|
||||
}
|
||||
|
||||
void
|
||||
tp_init_gesture(struct tp_dispatch *tp)
|
||||
{
|
||||
|
|
@ -1810,6 +2185,25 @@ tp_init_gesture(struct tp_dispatch *tp)
|
|||
tp->gesture.config.get_hold_default = tp_gesture_get_hold_default;
|
||||
tp->device->base.config.gesture = &tp->gesture.config;
|
||||
|
||||
tp->drag_3fg.config.count = tp_3fg_drag_count;
|
||||
tp->drag_3fg.config.set_enabled = tp_3fg_drag_set_enabled;
|
||||
tp->drag_3fg.config.get_enabled = tp_3fg_drag_get_enabled;
|
||||
tp->drag_3fg.config.get_default = tp_3fg_drag_get_default_enabled;
|
||||
tp->device->base.config.drag_3fg = &tp->drag_3fg.config;
|
||||
|
||||
switch (tp_3fg_drag_default(tp)) {
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_DISABLED:
|
||||
tp->drag_3fg.nfingers = 0;
|
||||
break;
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG:
|
||||
tp->drag_3fg.nfingers = 3;
|
||||
break;
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG:
|
||||
tp->drag_3fg.nfingers = 4;
|
||||
break;
|
||||
}
|
||||
tp->drag_3fg.want_nfingers = tp->drag_3fg.nfingers;
|
||||
|
||||
/* two-finger scrolling is always enabled, this flag just
|
||||
* decides whether we detect pinch. semi-mt devices are too
|
||||
* unreliable to do pinch gestures. */
|
||||
|
|
@ -1835,6 +2229,14 @@ tp_init_gesture(struct tp_dispatch *tp)
|
|||
tp_libinput_context(tp),
|
||||
timer_name,
|
||||
tp_gesture_hold_timeout, tp);
|
||||
snprintf(timer_name,
|
||||
sizeof(timer_name),
|
||||
"%s drag_3fg",
|
||||
evdev_device_get_sysname(tp->device));
|
||||
libinput_timer_init(&tp->gesture.drag_3fg_timer,
|
||||
tp_libinput_context(tp),
|
||||
timer_name,
|
||||
tp_gesture_3fg_drag_timeout, tp);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1842,4 +2244,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1910,6 +1910,7 @@ tp_handle_state(struct tp_dispatch *tp,
|
|||
|
||||
tp_clickpad_middlebutton_apply_config(tp->device);
|
||||
tp_apply_rotation(tp->device);
|
||||
tp_3fg_drag_apply_config(tp->device);
|
||||
}
|
||||
|
||||
LIBINPUT_UNUSED
|
||||
|
|
@ -2023,6 +2024,7 @@ tp_interface_destroy(struct evdev_dispatch *dispatch)
|
|||
libinput_timer_destroy(&tp->tap.timer);
|
||||
libinput_timer_destroy(&tp->gesture.finger_count_switch_timer);
|
||||
libinput_timer_destroy(&tp->gesture.hold_timer);
|
||||
libinput_timer_destroy(&tp->gesture.drag_3fg_timer);
|
||||
free(tp->touches);
|
||||
free(tp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,9 @@ enum tp_gesture_state {
|
|||
GESTURE_STATE_PINCH,
|
||||
GESTURE_STATE_SWIPE_START,
|
||||
GESTURE_STATE_SWIPE,
|
||||
GESTURE_STATE_3FG_DRAG_START,
|
||||
GESTURE_STATE_3FG_DRAG,
|
||||
GESTURE_STATE_3FG_DRAG_RELEASED,
|
||||
};
|
||||
|
||||
enum tp_thumb_state {
|
||||
|
|
@ -365,6 +368,9 @@ struct tp_dispatch {
|
|||
struct device_float_coords center;
|
||||
struct libinput_timer hold_timer;
|
||||
bool hold_enabled;
|
||||
|
||||
struct libinput_timer drag_3fg_timer;
|
||||
uint64_t drag_3fg_release_time;
|
||||
} gesture;
|
||||
|
||||
struct {
|
||||
|
|
@ -442,6 +448,12 @@ struct tp_dispatch {
|
|||
unsigned int nfingers_down; /* number of fingers down for tapping (excl. thumb/palm) */
|
||||
} tap;
|
||||
|
||||
struct {
|
||||
struct libinput_device_config_3fg_drag config;
|
||||
size_t nfingers;
|
||||
size_t want_nfingers;
|
||||
} drag_3fg;
|
||||
|
||||
struct {
|
||||
struct libinput_device_config_dwtp config;
|
||||
bool dwtp_enabled;
|
||||
|
|
@ -775,4 +787,7 @@ tp_init_thumb(struct tp_dispatch *tp);
|
|||
struct tp_touch*
|
||||
tp_thumb_get_touch(struct tp_dispatch *tp);
|
||||
|
||||
void
|
||||
tp_3fg_drag_apply_config(struct evdev_device *device);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -218,6 +218,15 @@ struct libinput_device_config_tap {
|
|||
enum libinput_config_drag_lock_state (*get_default_draglock_enabled)(struct libinput_device *device);
|
||||
};
|
||||
|
||||
struct libinput_device_config_3fg_drag {
|
||||
int (*count)(struct libinput_device *device);
|
||||
enum libinput_config_status (*set_enabled)(struct libinput_device *device,
|
||||
enum libinput_config_3fg_drag_state enable);
|
||||
enum libinput_config_3fg_drag_state (*get_enabled)(struct libinput_device *device);
|
||||
enum libinput_config_3fg_drag_state (*get_default)(struct libinput_device *device);
|
||||
|
||||
};
|
||||
|
||||
struct libinput_device_config_calibration {
|
||||
int (*has_matrix)(struct libinput_device *device);
|
||||
enum libinput_config_status (*set_matrix)(struct libinput_device *device,
|
||||
|
|
@ -411,6 +420,7 @@ struct libinput_device_config {
|
|||
struct libinput_device_config_dwtp *dwtp;
|
||||
struct libinput_device_config_rotation *rotation;
|
||||
struct libinput_device_config_gesture *gesture;
|
||||
struct libinput_device_config_3fg_drag *drag_3fg;
|
||||
};
|
||||
|
||||
struct libinput_device_group {
|
||||
|
|
|
|||
|
|
@ -4118,6 +4118,48 @@ libinput_device_config_tap_get_default_drag_lock_enabled(struct libinput_device
|
|||
return device->config.tap->get_default_draglock_enabled(device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_device_config_3fg_drag_get_finger_count(struct libinput_device *device)
|
||||
{
|
||||
return device->config.drag_3fg ? device->config.drag_3fg->count(device) : 0;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT enum libinput_config_status
|
||||
libinput_device_config_3fg_drag_set_enabled(struct libinput_device *device,
|
||||
enum libinput_config_3fg_drag_state enable)
|
||||
{
|
||||
if (libinput_device_config_3fg_drag_get_finger_count(device) < 3)
|
||||
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
|
||||
|
||||
switch (enable) {
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_DISABLED:
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG:
|
||||
case LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG:
|
||||
return device->config.drag_3fg->set_enabled(device, enable);
|
||||
break;
|
||||
}
|
||||
|
||||
return LIBINPUT_CONFIG_STATUS_INVALID;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT enum libinput_config_3fg_drag_state
|
||||
libinput_device_config_3fg_drag_get_enabled(struct libinput_device *device)
|
||||
{
|
||||
if (libinput_device_config_3fg_drag_get_finger_count(device) < 3)
|
||||
return LIBINPUT_CONFIG_3FG_DRAG_DISABLED;
|
||||
|
||||
return device->config.drag_3fg->get_enabled(device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT enum libinput_config_3fg_drag_state
|
||||
libinput_device_config_3fg_drag_get_default_enabled(struct libinput_device *device)
|
||||
{
|
||||
if (libinput_device_config_3fg_drag_get_finger_count(device) < 3)
|
||||
return LIBINPUT_CONFIG_3FG_DRAG_DISABLED;
|
||||
|
||||
return device->config.drag_3fg->get_default(device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_device_config_calibration_has_matrix(struct libinput_device *device)
|
||||
{
|
||||
|
|
|
|||
101
src/libinput.h
101
src/libinput.h
|
|
@ -5024,6 +5024,107 @@ libinput_device_config_tap_get_drag_lock_enabled(struct libinput_device *device)
|
|||
enum libinput_config_drag_lock_state
|
||||
libinput_device_config_tap_get_default_drag_lock_enabled(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* A config status to distinguish or set 3-finger dragging on a device.
|
||||
*
|
||||
* @since 1.27
|
||||
*/
|
||||
enum libinput_config_3fg_drag_state {
|
||||
/**
|
||||
* Drag is to be disabled, or is
|
||||
* currently disabled.
|
||||
*/
|
||||
LIBINPUT_CONFIG_3FG_DRAG_DISABLED,
|
||||
/**
|
||||
* Drag is to be enabled for 3 fingers, or is
|
||||
* currently enabled
|
||||
*/
|
||||
LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG,
|
||||
/**
|
||||
* Drag is to be enabled for 4 fingers, or is
|
||||
* currently enabled
|
||||
*/
|
||||
LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Returns the maximum number of fingers available for 3-finger dragging.
|
||||
*
|
||||
* @param device The device to check
|
||||
*
|
||||
* @see libinput_device_config_3fg_drag_set_enabled
|
||||
* @see libinput_device_config_3fg_drag_get_enabled
|
||||
* @see libinput_device_config_3fg_drag_get_default_enabled
|
||||
*
|
||||
* @since 1.27
|
||||
*/
|
||||
int
|
||||
libinput_device_config_3fg_drag_get_finger_count(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Enable or disable 3-finger drag on this device. When enabled, three fingers
|
||||
* down will result in a button down event, subsequent finger motion triggers
|
||||
* a drag. The button is released shortly after all fingers are logically up.
|
||||
* See the libinput documentation for more details.
|
||||
*
|
||||
* @param device The device to configure
|
||||
* @param enable @ref LIBINPUT_CONFIG_DRAG_ENABLED to enable, @ref
|
||||
* LIBINPUT_CONFIG_DRAG_DISABLED to disable 3-finger drag
|
||||
*
|
||||
* @see libinput_device_config_3fg_drag_is_available
|
||||
* @see libinput_device_config_3fg_drag_get_enabled
|
||||
* @see libinput_device_config_3fg_drag_get_default_enabled
|
||||
*
|
||||
* @since 1.27
|
||||
*/
|
||||
enum libinput_config_status
|
||||
libinput_device_config_3fg_drag_set_enabled(struct libinput_device *device,
|
||||
enum libinput_config_3fg_drag_state enable);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Return whether 3-finger drag is enabled or disabled on this device.
|
||||
*
|
||||
* @param device The device to check
|
||||
* @retval LIBINPUT_CONFIG_DRAG_ENABLED if 3-finger drag is enabled
|
||||
* @retval LIBINPUT_CONFIG_DRAG_DISABLED if 3-finger drag is
|
||||
* disabled
|
||||
*
|
||||
* @see libinput_device_config_3fg_drag_is_available
|
||||
* @see libinput_device_config_3fg_drag_set_enabled
|
||||
* @see libinput_device_config_3fg_drag_get_default_enabled
|
||||
*
|
||||
* @since 1.27
|
||||
*/
|
||||
enum libinput_config_3fg_drag_state
|
||||
libinput_device_config_3fg_drag_get_enabled(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Return whether 3-finger drag is enabled or disabled by default on this device.
|
||||
*
|
||||
* @param device The device to check
|
||||
* @retval LIBINPUT_CONFIG_DRAG_ENABLED if 3-finger drag is enabled
|
||||
* @retval LIBINPUT_CONFIG_DRAG_DISABLED if 3-finger drag is
|
||||
* disabled
|
||||
*
|
||||
* @see libinput_device_config_3fg_drag_is_available
|
||||
* @see libinput_device_config_3fg_drag_set_enabled
|
||||
* @see libinput_device_config_3fg_drag_get_enabled
|
||||
*
|
||||
* @since 1.27
|
||||
*/
|
||||
enum libinput_config_3fg_drag_state
|
||||
libinput_device_config_3fg_drag_get_default_enabled(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
|
|
|
|||
|
|
@ -357,3 +357,10 @@ LIBINPUT_1.27 {
|
|||
libinput_device_config_area_get_rectangle;
|
||||
libinput_device_config_area_get_default_rectangle;
|
||||
} LIBINPUT_1.26;
|
||||
|
||||
LIBINPUT_1.28 {
|
||||
libinput_device_config_3fg_drag_get_finger_count;
|
||||
libinput_device_config_3fg_drag_set_enabled;
|
||||
libinput_device_config_3fg_drag_get_enabled;
|
||||
libinput_device_config_3fg_drag_get_default_enabled;
|
||||
} LIBINPUT_1.27;
|
||||
|
|
|
|||
|
|
@ -4914,6 +4914,12 @@ litest_timeout_hysteresis(void)
|
|||
msleep(90);
|
||||
}
|
||||
|
||||
void
|
||||
litest_timeout_3fg_drag(void)
|
||||
{
|
||||
msleep(800);
|
||||
}
|
||||
|
||||
void
|
||||
litest_push_event_frame(struct litest_device *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1236,6 +1236,9 @@ litest_timeout_touch_arbitration(void);
|
|||
void
|
||||
litest_timeout_hysteresis(void);
|
||||
|
||||
void
|
||||
litest_timeout_3fg_drag(void);
|
||||
|
||||
void
|
||||
litest_push_event_frame(struct litest_device *dev);
|
||||
|
||||
|
|
@ -1268,6 +1271,29 @@ litest_semi_mt_touch_up(struct litest_device *d,
|
|||
struct litest_semi_mt *semi_mt,
|
||||
unsigned int slot);
|
||||
|
||||
static inline
|
||||
void litest_enable_3fg_drag(struct libinput_device *device,
|
||||
unsigned int nfingers)
|
||||
{
|
||||
enum libinput_config_3fg_drag_state enabled;
|
||||
|
||||
switch (nfingers) {
|
||||
case 3:
|
||||
enabled = LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG;
|
||||
break;
|
||||
case 4:
|
||||
enabled = LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG;
|
||||
break;
|
||||
default:
|
||||
litest_abort_msg("Invalid finger count");
|
||||
break;
|
||||
}
|
||||
|
||||
enum libinput_config_status status =
|
||||
libinput_device_config_3fg_drag_set_enabled(device, enabled);
|
||||
litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static inline void
|
||||
litest_enable_tap(struct libinput_device *device)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1782,11 +1782,491 @@ START_TEST(gestures_hold_and_motion_after_timeout)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
uint32_t finger_count;
|
||||
bool tap_enabled;
|
||||
litest_test_param_fetch(test_env->params,
|
||||
"fingers", 'u', &finger_count,
|
||||
"tap-enabled", 'b', &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);
|
||||
|
||||
litest_dispatch(li);
|
||||
|
||||
litest_drain_events_of_type(li, LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
|
||||
if (tap_enabled) {
|
||||
litest_checkpoint("Expecting no immediate button press as tapping is enabled");
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (tap_enabled) {
|
||||
litest_checkpoint("Expecting late button press as tapping is enabled");
|
||||
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++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag_lock_resume_3fg_motion)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
uint32_t finger_count;
|
||||
bool tap_enabled;
|
||||
bool wait_for_timeout;
|
||||
litest_test_param_fetch(test_env->params,
|
||||
"fingers", 'u', &finger_count,
|
||||
"tap-enabled", 'b', &tap_enabled,
|
||||
"wait", 'b', &wait_for_timeout);
|
||||
|
||||
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);
|
||||
|
||||
litest_checkpoint("Putting three fingers down + movement)");
|
||||
double y = 30.0;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_down(dev, i, 10 + i, y);
|
||||
|
||||
litest_dispatch(li);
|
||||
|
||||
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_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_checkpoint("Releasing all fingers");
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_checkpoint("Putting three fingers down (no movement)");
|
||||
y = 30.0;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_down(dev, i, 10 + i, y);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_dispatch(li);
|
||||
|
||||
litest_checkpoint("Waiting past finger switch timeout");
|
||||
litest_timeout_finger_switch();
|
||||
litest_dispatch(li);
|
||||
|
||||
if (wait_for_timeout) {
|
||||
litest_checkpoint("Waiting past tap/3fg drag timeout");
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
|
||||
litest_checkpoint("Moving three fingers");
|
||||
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_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_checkpoint("Releasing three fingers");
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag_lock_resume_3fg_release_no_motion)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
uint32_t finger_count;
|
||||
bool tap_enabled;
|
||||
bool wait_for_timeout;
|
||||
litest_test_param_fetch(test_env->params,
|
||||
"fingers", 'u', &finger_count,
|
||||
"tap-enabled", 'b', &tap_enabled,
|
||||
"wait", 'b', &wait_for_timeout);
|
||||
|
||||
/* tap-enabled for 4fg finger count doesn't make a difference */
|
||||
bool expect_tap = finger_count <= 3 && tap_enabled && !wait_for_timeout;
|
||||
|
||||
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);
|
||||
|
||||
litest_checkpoint("Putting 3 fingers down with motion for drag");
|
||||
double y = 30.0;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_down(dev, i, 10 + i, y);
|
||||
|
||||
litest_dispatch(li);
|
||||
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_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++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_checkpoint("Putting 3 fingers down again (no motion)");
|
||||
y = 30.0;
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_down(dev, i, 10 + i, y);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_checkpoint("Waiting past finger switch timeout");
|
||||
litest_timeout_finger_switch();
|
||||
litest_dispatch(li);
|
||||
|
||||
if (wait_for_timeout) {
|
||||
litest_checkpoint("Waiting past tap/3fg drag timeout");
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
|
||||
litest_checkpoint("Releasing three fingers");
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
litest_dispatch(li);
|
||||
|
||||
if (expect_tap) {
|
||||
/* If we're not waiting and tapping is enabled, this is
|
||||
* the equivalent of a 3fg tap within the drag timeout */
|
||||
litest_checkpoint("Expecting 3fg drag release");
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_checkpoint("Expecting 3fg tap");
|
||||
litest_assert_button_event(li, BTN_MIDDLE, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li, BTN_MIDDLE, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
|
||||
if (!expect_tap)
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag_lock_resume_1fg_motion)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
uint32_t finger_count;
|
||||
bool tap_enabled;
|
||||
litest_test_param_fetch(test_env->params,
|
||||
"fingers", 'u', &finger_count,
|
||||
"tap-enabled", 'b', &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);
|
||||
|
||||
litest_checkpoint("Putting 3 fingers down + motion to trigger 3fg drag");
|
||||
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_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_checkpoint("Releasing 3 fingers");
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_checkpoint("Putting 1 finger down and moving it");
|
||||
/* fingers are up, now let's put one finger down and move it */
|
||||
y = 30.0;
|
||||
litest_touch_down(dev, 0, 10, y);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* We need to wait until the gesture code accepts this is one finger only */
|
||||
litest_timeout_finger_switch();
|
||||
litest_dispatch(li);
|
||||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
litest_touch_move(dev, 0, 10, y);
|
||||
litest_dispatch(li);
|
||||
}
|
||||
|
||||
litest_checkpoint("Expecting drag button release and motion");
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag_lock_resume_2fg_scroll)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
uint32_t finger_count;
|
||||
bool tap_enabled;
|
||||
litest_test_param_fetch(test_env->params,
|
||||
"fingers", 'u', &finger_count,
|
||||
"tap-enabled", 'b', &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);
|
||||
|
||||
litest_checkpoint("Putting 3 fingers down + motion to trigger 3fg drag");
|
||||
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_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_checkpoint("Releasing 3 fingers");
|
||||
for (uint32_t i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_checkpoint("Putting 2 fingers down and moving them");
|
||||
y = 30.0;
|
||||
litest_touch_down(dev, 0, 10, y);
|
||||
litest_touch_down(dev, 1, 20, y);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_finger_switch();
|
||||
litest_dispatch(li);
|
||||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
litest_touch_move(dev, 0, 10, y);
|
||||
litest_touch_move(dev, 1, 20, y);
|
||||
litest_dispatch(li);
|
||||
}
|
||||
|
||||
litest_checkpoint("Expecting drag button release and scroll");
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_assert_only_axis_events(li, LIBINPUT_EVENT_POINTER_SCROLL_FINGER);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(gestures_3fg_drag_lock_resume_1fg_tap)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
int finger_count = _i; /* ranged test */
|
||||
|
||||
if (litest_slot_count(dev) < 3)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
if (libinput_device_config_3fg_drag_get_finger_count(dev->libinput_device) < finger_count)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
litest_enable_3fg_drag(dev->libinput_device, finger_count);
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_checkpoint("Putting 3 fingers down for 3fg drag");
|
||||
double y = 30.0;
|
||||
for (int i = 0; i < finger_count; i++)
|
||||
litest_touch_down(dev, i, 10 + i, y);
|
||||
|
||||
litest_dispatch(li);
|
||||
|
||||
while (y < 60.0) {
|
||||
y += 2;
|
||||
for (int 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,
|
||||
-1);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_checkpoint("Releasing 3 fingers");
|
||||
for (int i = 0; i < finger_count; i++)
|
||||
litest_touch_up(dev, i);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_checkpoint("Tapping with 1 finger");
|
||||
/* fingers are up, now let's tap with one finger */
|
||||
y = 30.0;
|
||||
litest_touch_down(dev, 0, 10, y);
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_dispatch(li);
|
||||
|
||||
litest_timeout_tap();
|
||||
litest_dispatch(li);
|
||||
|
||||
litest_checkpoint("Expecting drag release followed by 1fg tap");
|
||||
|
||||
/* 3fg drag lock must be cancelled */
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
/* And a 1fg tap */
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_3fg_drag();
|
||||
litest_dispatch(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_COLLECTION(gestures)
|
||||
{
|
||||
struct range cardinals = { N, N + NCARDINALS };
|
||||
struct range range_hold = { 1, 5 };
|
||||
struct range range_multifinger_tap = {1, 4};
|
||||
struct range range_3fg_drag = { 3, 5 };
|
||||
|
||||
litest_add(gestures_cap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add(gestures_nocap, LITEST_ANY, LITEST_TOUCHPAD);
|
||||
|
|
@ -1830,6 +2310,32 @@ TEST_COLLECTION(gestures)
|
|||
litest_add(gestures_hold_and_motion_before_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add(gestures_hold_and_motion_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
||||
{
|
||||
struct litest_parameters *params = litest_parameters_new("fingers", 'u', 2, 3, 4,
|
||||
"tap-enabled", 'b');
|
||||
litest_add_parametrized(gestures_3fg_drag, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
litest_parameters_unref(params);
|
||||
}
|
||||
|
||||
{
|
||||
struct litest_parameters *params = litest_parameters_new("fingers", 'u', 2, 3, 4,
|
||||
"tap-enabled", 'b',
|
||||
"wait", 'b');
|
||||
litest_add_parametrized(gestures_3fg_drag_lock_resume_3fg_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
litest_add_parametrized(gestures_3fg_drag_lock_resume_3fg_release_no_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
litest_parameters_unref(params);
|
||||
}
|
||||
|
||||
{
|
||||
struct litest_parameters *params = litest_parameters_new("fingers", 'u', 2, 3, 4,
|
||||
"tap-enabled", 'b');
|
||||
litest_add_parametrized(gestures_3fg_drag_lock_resume_1fg_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
litest_add_parametrized(gestures_3fg_drag_lock_resume_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
|
||||
litest_parameters_unref(params);
|
||||
}
|
||||
litest_add_ranged(gestures_3fg_drag_lock_resume_1fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &range_3fg_drag);
|
||||
|
||||
|
||||
/* Timing-sensitive test, valgrind is too slow */
|
||||
if (!RUNNING_ON_VALGRIND)
|
||||
litest_add(gestures_swipe_3fg_unaccel, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
|
|
|||
|
|
@ -411,6 +411,21 @@ tools_parse_option(int option,
|
|||
options->area.y2 = y2;
|
||||
break;
|
||||
}
|
||||
case OPT_3FG_DRAG:
|
||||
if (!optarg)
|
||||
return 1;
|
||||
if (streq(optarg, "3fg"))
|
||||
options->drag_3fg = LIBINPUT_CONFIG_3FG_DRAG_ENABLED_3FG;
|
||||
else if (streq(optarg, "4fg"))
|
||||
options->drag_3fg = LIBINPUT_CONFIG_3FG_DRAG_ENABLED_4FG;
|
||||
else if (streq(optarg, "disabled"))
|
||||
options->drag_3fg = LIBINPUT_CONFIG_3FG_DRAG_DISABLED;
|
||||
else {
|
||||
fprintf(stderr, "Invalid --enable-3fg-drag\n"
|
||||
"Valid options: 3fg|4fg|disabled\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -629,6 +644,9 @@ tools_device_apply_config(struct libinput_device *device,
|
|||
|
||||
if (libinput_device_config_area_has_rectangle(device))
|
||||
libinput_device_config_area_set_rectangle(device, &options->area);
|
||||
|
||||
if (libinput_device_config_3fg_drag_get_finger_count(device) >= 3)
|
||||
libinput_device_config_3fg_drag_set_enabled(device, options->drag_3fg);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ enum configuration_options {
|
|||
OPT_PRESSURE_RANGE,
|
||||
OPT_CALIBRATION,
|
||||
OPT_AREA,
|
||||
OPT_3FG_DRAG,
|
||||
};
|
||||
|
||||
#define CONFIGURATION_OPTIONS \
|
||||
|
|
@ -91,6 +92,7 @@ enum configuration_options {
|
|||
{ "disable-dwtp", no_argument, 0, OPT_DWTP_DISABLE }, \
|
||||
{ "enable-scroll-button-lock", no_argument, 0, OPT_SCROLL_BUTTON_LOCK_ENABLE }, \
|
||||
{ "disable-scroll-button-lock",no_argument, 0, OPT_SCROLL_BUTTON_LOCK_DISABLE }, \
|
||||
{ "enable-3fg-drag", required_argument, 0, OPT_3FG_DRAG }, \
|
||||
{ "set-click-method", required_argument, 0, OPT_CLICK_METHOD }, \
|
||||
{ "set-clickfinger-map", required_argument, 0, OPT_CLICKFINGER_MAP }, \
|
||||
{ "set-scroll-method", required_argument, 0, OPT_SCROLL_METHOD }, \
|
||||
|
|
@ -141,6 +143,7 @@ struct tools_options {
|
|||
double pressure_range[2];
|
||||
float calibration[6];
|
||||
struct libinput_config_area_rectangle area;
|
||||
enum libinput_config_3fg_drag_state drag_3fg;
|
||||
};
|
||||
|
||||
void tools_init_options(struct tools_options *options);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue