mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 01:10:25 +01:00
Merge branch 'wip/4fg-tap' into 'main'
Draft: tap: implement support for 4-finger tap as a new gesture See merge request libinput/libinput!1417
This commit is contained in:
commit
5d3741ce11
12 changed files with 475 additions and 97 deletions
|
|
@ -692,12 +692,13 @@ tp_gesture_handle_event_on_state_hold(struct tp_dispatch *tp,
|
|||
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;
|
||||
case GESTURE_EVENT_TAP_TIMEOUT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ tap_state_to_str(enum tp_tap_state state)
|
|||
CASE_RETURN_STRING(TAP_STATE_TOUCH_3_HOLD);
|
||||
CASE_RETURN_STRING(TAP_STATE_TOUCH_3_RELEASE);
|
||||
CASE_RETURN_STRING(TAP_STATE_TOUCH_3_RELEASE_2);
|
||||
CASE_RETURN_STRING(TAP_STATE_TOUCH_4);
|
||||
CASE_RETURN_STRING(TAP_STATE_TOUCH_4_HOLD);
|
||||
CASE_RETURN_STRING(TAP_STATE_TOUCH_4_RELEASE);
|
||||
CASE_RETURN_STRING(TAP_STATE_TOUCH_4_RELEASE_4);
|
||||
CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING);
|
||||
CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING);
|
||||
CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING);
|
||||
|
|
@ -132,22 +136,33 @@ tp_tap_notify(struct tp_dispatch *tp,
|
|||
|
||||
assert(tp->tap.map < ARRAY_LENGTH(button_map));
|
||||
|
||||
if (nfingers < 1 || nfingers > 3)
|
||||
if (nfingers < 1 || nfingers > 4)
|
||||
return;
|
||||
|
||||
tp_gesture_cancel(tp, time);
|
||||
|
||||
button = button_map[tp->tap.map][nfingers - 1];
|
||||
if (nfingers < 4) {
|
||||
button = button_map[tp->tap.map][nfingers - 1];
|
||||
|
||||
if (state == LIBINPUT_BUTTON_STATE_PRESSED)
|
||||
tp->tap.buttons_pressed |= bit(nfingers);
|
||||
else
|
||||
tp->tap.buttons_pressed &= ~bit(nfingers);
|
||||
if (state == LIBINPUT_BUTTON_STATE_PRESSED)
|
||||
tp->tap.buttons_pressed |= bit(nfingers);
|
||||
else
|
||||
tp->tap.buttons_pressed &= ~bit(nfingers);
|
||||
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
time,
|
||||
evdev_usage_from_uint32_t(button),
|
||||
state);
|
||||
evdev_pointer_notify_button(tp->device,
|
||||
time,
|
||||
evdev_usage_from_uint32_t(button),
|
||||
state);
|
||||
} else {
|
||||
if (state == LIBINPUT_BUTTON_STATE_PRESSED) {
|
||||
gesture_notify_tap_begin(&tp->device->base, time, nfingers);
|
||||
} else {
|
||||
gesture_notify_tap_end(&tp->device->base,
|
||||
time,
|
||||
nfingers,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -511,8 +526,9 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp,
|
|||
|
||||
switch (event) {
|
||||
case TAP_EVENT_TOUCH:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_clear_timer(tp);
|
||||
tp->tap.state = TAP_STATE_TOUCH_4;
|
||||
tp->tap.saved_press_time = time;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_MOTION:
|
||||
tp_tap_move_to_dead(tp, t);
|
||||
|
|
@ -549,7 +565,8 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp,
|
|||
|
||||
switch (event) {
|
||||
case TAP_EVENT_TOUCH:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp->tap.state = TAP_STATE_TOUCH_4;
|
||||
tp->tap.saved_press_time = time;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_RELEASE:
|
||||
|
|
@ -739,6 +756,238 @@ tp_tap_touch3_release2_handle_event(struct tp_dispatch *tp,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_tap_touch4_handle_event(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
enum tap_event event,
|
||||
usec_t time)
|
||||
{
|
||||
|
||||
switch (event) {
|
||||
case TAP_EVENT_TOUCH:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_clear_timer(tp);
|
||||
break;
|
||||
case TAP_EVENT_MOTION:
|
||||
tp_tap_move_to_dead(tp, t);
|
||||
break;
|
||||
case TAP_EVENT_TIMEOUT:
|
||||
tp->tap.state = TAP_STATE_TOUCH_4_HOLD;
|
||||
tp_tap_clear_timer(tp);
|
||||
tp_gesture_tap_timeout(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_RELEASE:
|
||||
tp->tap.state = TAP_STATE_TOUCH_4_RELEASE;
|
||||
tp->tap.saved_release_time = time;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
case TAP_EVENT_PALM:
|
||||
tp->tap.state = TAP_STATE_TOUCH_3;
|
||||
break;
|
||||
case TAP_EVENT_PALM_UP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_tap_touch4_hold_handle_event(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
enum tap_event event,
|
||||
usec_t time)
|
||||
{
|
||||
|
||||
switch (event) {
|
||||
case TAP_EVENT_TOUCH:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_RELEASE:
|
||||
tp->tap.state = TAP_STATE_TOUCH_3_HOLD;
|
||||
break;
|
||||
case TAP_EVENT_MOTION:
|
||||
tp_tap_move_to_dead(tp, t);
|
||||
break;
|
||||
case TAP_EVENT_TIMEOUT:
|
||||
break;
|
||||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
case TAP_EVENT_PALM:
|
||||
tp->tap.state = TAP_STATE_TOUCH_3;
|
||||
break;
|
||||
case TAP_EVENT_PALM_UP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_tap_touch4_release_handle_event(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
enum tap_event event,
|
||||
usec_t time)
|
||||
{
|
||||
|
||||
switch (event) {
|
||||
case TAP_EVENT_TOUCH:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_TOUCH_4_HOLD;
|
||||
tp->tap.saved_press_time = time;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_RELEASE:
|
||||
tp->tap.state = TAP_STATE_TOUCH_4_RELEASE_4;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_MOTION:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp_tap_move_to_dead(tp, t);
|
||||
break;
|
||||
case TAP_EVENT_TIMEOUT:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_TOUCH_3_HOLD;
|
||||
break;
|
||||
case TAP_EVENT_BUTTON:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
case TAP_EVENT_PALM:
|
||||
tp->tap.state = TAP_STATE_TOUCH_3_RELEASE;
|
||||
break;
|
||||
case TAP_EVENT_PALM_UP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_tap_touch4_release4_handle_event(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
enum tap_event event,
|
||||
usec_t time)
|
||||
{
|
||||
|
||||
switch (event) {
|
||||
case TAP_EVENT_TOUCH:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_TOUCH_3;
|
||||
tp->tap.saved_press_time = time;
|
||||
tp_tap_set_timer(tp, time);
|
||||
break;
|
||||
case TAP_EVENT_RELEASE:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_IDLE;
|
||||
break;
|
||||
case TAP_EVENT_MOTION:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp_tap_move_to_dead(tp, t);
|
||||
break;
|
||||
case TAP_EVENT_TIMEOUT:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_HOLD;
|
||||
break;
|
||||
case TAP_EVENT_BUTTON:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
4,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
case TAP_EVENT_PALM:
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_press_time,
|
||||
3,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
if (tp->tap.drag_enabled) {
|
||||
/* Resetting the timer to the appropriate delay
|
||||
* for a three-finger tap would be ideal, but the
|
||||
* timestamp of the last real finger release is lost,
|
||||
* so the in-progress similar delay for release
|
||||
* of the finger which became a palm instead
|
||||
* will have to do */
|
||||
tp->tap.state = TAP_STATE_3FGTAP_TAPPED;
|
||||
} else {
|
||||
tp_tap_notify(tp,
|
||||
tp->tap.saved_release_time,
|
||||
3,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp->tap.state = TAP_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
case TAP_EVENT_PALM_UP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
|
|
@ -1107,6 +1356,18 @@ tp_tap_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_STATE_TOUCH_3_RELEASE_2:
|
||||
tp_tap_touch3_release2_handle_event(tp, t, event, time);
|
||||
break;
|
||||
case TAP_STATE_TOUCH_4:
|
||||
tp_tap_touch4_handle_event(tp, t, event, time);
|
||||
break;
|
||||
case TAP_STATE_TOUCH_4_HOLD:
|
||||
tp_tap_touch4_hold_handle_event(tp, t, event, time);
|
||||
break;
|
||||
case TAP_STATE_TOUCH_4_RELEASE:
|
||||
tp_tap_touch4_release_handle_event(tp, t, event, time);
|
||||
break;
|
||||
case TAP_STATE_TOUCH_4_RELEASE_4:
|
||||
tp_tap_touch4_release4_handle_event(tp, t, event, time);
|
||||
break;
|
||||
case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP:
|
||||
tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time, 1);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#define DEFAULT_TRACKPOINT_EVENT_TIMEOUT usec_from_millis(40)
|
||||
#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 usec_from_millis(200)
|
||||
#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 usec_from_millis(500)
|
||||
#define FAKE_FINGER_OVERFLOW bit(7)
|
||||
#define THUMB_IGNORE_SPEED_THRESHOLD 20 /* mm/s */
|
||||
|
||||
#define MOUSE_HAS_SENT_EVENTS bit(1)
|
||||
|
|
@ -261,7 +260,7 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
|
|||
static inline unsigned int
|
||||
tp_fake_finger_count(struct tp_dispatch *tp)
|
||||
{
|
||||
unsigned int fake_touches = tp->fake_touches & ~(FAKE_FINGER_OVERFLOW | 0x1);
|
||||
unsigned int fake_touches = tp->fake_touches & ~0x1;
|
||||
|
||||
/* Only one of BTN_TOOL_DOUBLETAP/TRIPLETAP/... may be set at any
|
||||
* time */
|
||||
|
|
@ -270,9 +269,6 @@ tp_fake_finger_count(struct tp_dispatch *tp)
|
|||
"Invalid fake finger state %#x\n",
|
||||
tp->fake_touches);
|
||||
|
||||
if (tp->fake_touches & FAKE_FINGER_OVERFLOW)
|
||||
return FAKE_FINGER_OVERFLOW;
|
||||
|
||||
/* don't count BTN_TOUCH */
|
||||
return ffs(tp->fake_touches >> 1);
|
||||
}
|
||||
|
|
@ -290,33 +286,29 @@ tp_fake_finger_set(struct tp_dispatch *tp, evdev_usage_t usage, bool is_press)
|
|||
|
||||
switch (evdev_usage_enum(usage)) {
|
||||
case EVDEV_BTN_TOUCH:
|
||||
if (!is_press)
|
||||
tp->fake_touches &= ~FAKE_FINGER_OVERFLOW;
|
||||
shift = 0;
|
||||
break;
|
||||
case EVDEV_BTN_TOOL_FINGER:
|
||||
shift = 1;
|
||||
break;
|
||||
case EVDEV_BTN_TOOL_DOUBLETAP:
|
||||
case EVDEV_BTN_TOOL_TRIPLETAP:
|
||||
case EVDEV_BTN_TOOL_QUADTAP:
|
||||
shift = evdev_usage_enum(usage) - EVDEV_BTN_TOOL_DOUBLETAP + 2;
|
||||
shift = 2;
|
||||
break;
|
||||
case EVDEV_BTN_TOOL_TRIPLETAP:
|
||||
shift = 3;
|
||||
break;
|
||||
case EVDEV_BTN_TOOL_QUADTAP:
|
||||
shift = 4;
|
||||
break;
|
||||
/* when QUINTTAP is released we're either switching to 6 fingers
|
||||
(flag stays in place until BTN_TOUCH is released) or
|
||||
one of DOUBLE/TRIPLE/QUADTAP (will clear the flag on press) */
|
||||
case EVDEV_BTN_TOOL_QUINTTAP:
|
||||
if (is_press)
|
||||
tp->fake_touches |= FAKE_FINGER_OVERFLOW;
|
||||
return;
|
||||
shift = 5;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_press) {
|
||||
tp->fake_touches &= ~FAKE_FINGER_OVERFLOW;
|
||||
tp->fake_touches |= bit(shift);
|
||||
|
||||
} else {
|
||||
tp->fake_touches &= ~bit(shift);
|
||||
}
|
||||
|
|
@ -629,9 +621,6 @@ tp_process_fake_touches(struct tp_dispatch *tp, usec_t time)
|
|||
unsigned int i, start;
|
||||
|
||||
nfake_touches = tp_fake_finger_count(tp);
|
||||
if (nfake_touches == FAKE_FINGER_OVERFLOW)
|
||||
return;
|
||||
|
||||
if (tp->device->model_flags & EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD)
|
||||
tp_restore_synaptics_touches(tp, time);
|
||||
|
||||
|
|
@ -1144,9 +1133,6 @@ tp_unhover_pressure(struct tp_dispatch *tp, usec_t time)
|
|||
unsigned int real_fingers_down = 0;
|
||||
|
||||
nfake_touches = tp_fake_finger_count(tp);
|
||||
if (nfake_touches == FAKE_FINGER_OVERFLOW)
|
||||
nfake_touches = 0;
|
||||
|
||||
for (i = 0; i < (int)tp->num_slots; i++) {
|
||||
t = tp_get_touch(tp, i);
|
||||
|
||||
|
|
@ -1270,9 +1256,6 @@ tp_unhover_fake_touches(struct tp_dispatch *tp, usec_t time)
|
|||
return;
|
||||
|
||||
nfake_touches = tp_fake_finger_count(tp);
|
||||
if (nfake_touches == FAKE_FINGER_OVERFLOW)
|
||||
return;
|
||||
|
||||
if (tp->nfingers_down == nfake_touches &&
|
||||
((tp->nfingers_down == 0 && !tp_fake_finger_is_touching(tp)) ||
|
||||
(tp->nfingers_down > 0 && tp_fake_finger_is_touching(tp))))
|
||||
|
|
|
|||
|
|
@ -116,6 +116,10 @@ enum tp_tap_state {
|
|||
TAP_STATE_TOUCH_3_HOLD,
|
||||
TAP_STATE_TOUCH_3_RELEASE,
|
||||
TAP_STATE_TOUCH_3_RELEASE_2,
|
||||
TAP_STATE_TOUCH_4,
|
||||
TAP_STATE_TOUCH_4_HOLD,
|
||||
TAP_STATE_TOUCH_4_RELEASE,
|
||||
TAP_STATE_TOUCH_4_RELEASE_4,
|
||||
TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP,
|
||||
TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP,
|
||||
TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP,
|
||||
|
|
|
|||
|
|
@ -892,6 +892,15 @@ gesture_notify_hold_end(struct libinput_device *device,
|
|||
int finger_count,
|
||||
bool cancelled);
|
||||
|
||||
void
|
||||
gesture_notify_tap_begin(struct libinput_device *device, usec_t time, int finger_count);
|
||||
|
||||
void
|
||||
gesture_notify_tap_end(struct libinput_device *device,
|
||||
usec_t time,
|
||||
int finger_count,
|
||||
bool cancelled);
|
||||
|
||||
void
|
||||
tablet_notify_axis(struct libinput_device *device,
|
||||
usec_t time,
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ event_type_to_str(enum libinput_event_type type)
|
|||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_HOLD_BEGIN);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_TAP_BEGIN);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_TAP_END);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_SWITCH_TOGGLE);
|
||||
case LIBINPUT_EVENT_NONE:
|
||||
abort();
|
||||
|
|
@ -448,7 +450,9 @@ libinput_event_get_gesture_event(struct libinput_event *event)
|
|||
LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
|
||||
LIBINPUT_EVENT_GESTURE_PINCH_END,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END);
|
||||
|
||||
return (struct libinput_event_gesture *)event;
|
||||
}
|
||||
|
|
@ -997,7 +1001,9 @@ libinput_event_gesture_get_time(struct libinput_event_gesture *event)
|
|||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_END,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END);
|
||||
|
||||
return usec_to_millis(event->time);
|
||||
}
|
||||
|
|
@ -1015,7 +1021,9 @@ libinput_event_gesture_get_time_usec(struct libinput_event_gesture *event)
|
|||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_END,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END);
|
||||
|
||||
return usec_as_uint64_t(event->time);
|
||||
}
|
||||
|
|
@ -1033,7 +1041,9 @@ libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event)
|
|||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_END,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END);
|
||||
|
||||
return event->finger_count;
|
||||
}
|
||||
|
|
@ -1046,7 +1056,8 @@ libinput_event_gesture_get_cancelled(struct libinput_event_gesture *event)
|
|||
0,
|
||||
LIBINPUT_EVENT_GESTURE_PINCH_END,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_END,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END);
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END);
|
||||
|
||||
return event->cancelled;
|
||||
}
|
||||
|
|
@ -3213,6 +3224,41 @@ gesture_notify_hold_end(struct libinput_device *device,
|
|||
0.0);
|
||||
}
|
||||
|
||||
void
|
||||
gesture_notify_tap_begin(struct libinput_device *device, usec_t time, int finger_count)
|
||||
{
|
||||
const struct normalized_coords zero = { 0.0, 0.0 };
|
||||
|
||||
gesture_notify(device,
|
||||
time,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
finger_count,
|
||||
0,
|
||||
&zero,
|
||||
&zero,
|
||||
0.0,
|
||||
0.0);
|
||||
}
|
||||
|
||||
void
|
||||
gesture_notify_tap_end(struct libinput_device *device,
|
||||
usec_t time,
|
||||
int finger_count,
|
||||
bool cancelled)
|
||||
{
|
||||
const struct normalized_coords zero = { 0.0, 0.0 };
|
||||
|
||||
gesture_notify(device,
|
||||
time,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END,
|
||||
finger_count,
|
||||
cancelled,
|
||||
&zero,
|
||||
&zero,
|
||||
0.0,
|
||||
0.0);
|
||||
}
|
||||
|
||||
void
|
||||
switch_notify_toggle(struct libinput_device *device,
|
||||
usec_t time,
|
||||
|
|
|
|||
|
|
@ -1036,6 +1036,22 @@ enum libinput_event_type {
|
|||
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_HOLD_END,
|
||||
|
||||
/**
|
||||
* A tap gesture signals a number of fingers put down and released in
|
||||
* the same position within a given timeout.
|
||||
*
|
||||
* For historical reasons, taps for one, two and three fingers are
|
||||
* sent as button events, see libinput_device_config_tap_set_button_map()
|
||||
* This gesture is currently only sent for a four-finger tap but may
|
||||
* be sent for other taps in the future.
|
||||
*
|
||||
* See libinput_device_config_tap_set_enabled() for details.
|
||||
*
|
||||
* @since 1.31
|
||||
*/
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END,
|
||||
|
||||
/**
|
||||
* @since 1.7
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -108,6 +108,12 @@ event_type_to_str(enum libinput_event_type evtype)
|
|||
case LIBINPUT_EVENT_GESTURE_HOLD_END:
|
||||
type = "GESTURE_HOLD_END";
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_BEGIN:
|
||||
type = "GESTURE_TAP_BEGIN";
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_END:
|
||||
type = "GESTURE_TAP_END";
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
||||
type = "TABLET_TOOL_AXIS";
|
||||
break;
|
||||
|
|
@ -789,6 +795,7 @@ print_gesture_event_without_coords(struct libinput_event *ev,
|
|||
|
||||
if (type == LIBINPUT_EVENT_GESTURE_SWIPE_END ||
|
||||
type == LIBINPUT_EVENT_GESTURE_PINCH_END ||
|
||||
type == LIBINPUT_EVENT_GESTURE_TAP_END ||
|
||||
type == LIBINPUT_EVENT_GESTURE_HOLD_END)
|
||||
cancelled = libinput_event_gesture_get_cancelled(t);
|
||||
|
||||
|
|
@ -1076,6 +1083,12 @@ libinput_event_to_str(struct libinput_event *ev,
|
|||
case LIBINPUT_EVENT_GESTURE_HOLD_END:
|
||||
event_str = print_gesture_event_without_coords(ev, &opts);
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_BEGIN:
|
||||
event_str = print_gesture_event_without_coords(ev, &opts);
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_END:
|
||||
event_str = print_gesture_event_without_coords(ev, &opts);
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
||||
event_str = print_tablet_axis_event(ev, &opts);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3702,6 +3702,12 @@ litest_event_type_str(enum libinput_event_type type)
|
|||
case LIBINPUT_EVENT_GESTURE_HOLD_END:
|
||||
str = "GESTURE HOLD END";
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_BEGIN:
|
||||
str = "GESTURE TAP BEGIN";
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_END:
|
||||
str = "GESTURE TAP END";
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
||||
str = "TABLET TOOL AXIS";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1772,7 +1772,7 @@ START_TEST(gestures_3fg_drag_lock_resume_3fg_release_no_motion)
|
|||
bool wait_for_timeout = litest_test_param_get_bool(test_env->params, "wait");
|
||||
|
||||
/* tap-enabled for 4fg finger count doesn't make a difference */
|
||||
bool expect_tap = finger_count <= 3 && tap_enabled && !wait_for_timeout;
|
||||
bool expect_tap = tap_enabled && !wait_for_timeout;
|
||||
|
||||
if (litest_slot_count(dev) < 3)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
|
@ -1845,12 +1845,21 @@ START_TEST(gestures_3fg_drag_lock_resume_3fg_release_no_motion)
|
|||
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);
|
||||
if (finger_count < 4) {
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
} else {
|
||||
litest_assert_gesture_event(li,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_BEGIN,
|
||||
finger_count);
|
||||
litest_assert_gesture_event(li,
|
||||
LIBINPUT_EVENT_GESTURE_TAP_END,
|
||||
finger_count);
|
||||
}
|
||||
}
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
|
|
|
|||
|
|
@ -3225,13 +3225,17 @@ START_TEST(touchpad_4fg_tap)
|
|||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
bool with_hold = litest_test_param_get_bool(test_env->params, "with-hold");
|
||||
int i;
|
||||
|
||||
if (litest_slot_count(dev) <= 4)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
if (with_hold)
|
||||
litest_enable_hold_gestures(dev->libinput_device);
|
||||
else
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
litest_drain_events(li);
|
||||
|
|
@ -3247,49 +3251,12 @@ START_TEST(touchpad_4fg_tap)
|
|||
litest_touch_up(dev, (i + 0) % 4);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_timeout_tap(li);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_assert_gesture_event(li, LIBINPUT_EVENT_GESTURE_TAP_BEGIN, 4);
|
||||
litest_assert_gesture_event(li, LIBINPUT_EVENT_GESTURE_TAP_END, 4);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_4fg_tap_quickrelease)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (litest_slot_count(dev) <= 4)
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 70, 50);
|
||||
litest_touch_down(dev, 2, 80, 50);
|
||||
litest_touch_down(dev, 3, 90, 50);
|
||||
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 2);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 3);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_timeout_tap(li);
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_move_after_touch)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -4825,8 +4792,7 @@ START_TEST(touchpad_tap_palm_on_touch_4)
|
|||
litest_drain_events(li);
|
||||
|
||||
/* 4fg tap with one finger detected as palm, that finger is lifted,
|
||||
other two fingers lifted cause nothing because we terminate
|
||||
tapping as soon as 4 fingers are down */
|
||||
then put down again as normal finger -> 3fg tap */
|
||||
litest_touch_down(dev, this, 50, 50);
|
||||
litest_touch_down(dev, (this + 1) % 4, 60, 50);
|
||||
litest_touch_down(dev, (this + 2) % 4, 70, 50);
|
||||
|
|
@ -4840,6 +4806,11 @@ START_TEST(touchpad_tap_palm_on_touch_4)
|
|||
litest_touch_up(dev, (this + 2) % 4);
|
||||
litest_touch_up(dev, (this + 3) % 4);
|
||||
|
||||
litest_dispatch(li);
|
||||
litest_assert_button_event(li, BTN_MIDDLE, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_timeout_tap(li);
|
||||
litest_assert_button_event(li, BTN_MIDDLE, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
|
@ -5420,8 +5391,9 @@ TEST_COLLECTION(touchpad_tap)
|
|||
litest_add_for_device(touchpad_3fg_tap_slot_release_btntool, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
litest_add(touchpad_3fg_tap_after_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
||||
litest_add(touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
litest_add(touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
litest_with_parameters(params, "with-hold", 'b') {
|
||||
litest_add_parametrized(touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT, params);
|
||||
}
|
||||
litest_add(touchpad_5fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
litest_add(touchpad_5fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,11 @@ struct window {
|
|||
bool active;
|
||||
} hold;
|
||||
|
||||
struct {
|
||||
int nfingers;
|
||||
bool active;
|
||||
} tap;
|
||||
|
||||
struct {
|
||||
double x, y;
|
||||
double x_in, y_in;
|
||||
|
|
@ -607,6 +612,20 @@ draw_gestures(struct window *w, cairo_t *cr)
|
|||
cairo_stroke(cr);
|
||||
}
|
||||
|
||||
/* 4fg tap uses the same rings but blue */
|
||||
for (int i = 4; w->tap.active && i > 0; i--) { /* 4 fg max */
|
||||
double r, g, b, hold_alpha;
|
||||
|
||||
r = .2;
|
||||
g = .2;
|
||||
b = .4 + .2 * (i % 2);
|
||||
hold_alpha = i <= w->hold.nfingers ? 1 : .5;
|
||||
|
||||
cairo_set_source_rgba(cr, r, g, b, hold_alpha);
|
||||
cairo_arc(cr, 0, 0, 20 * i, 0, 2 * M_PI);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
|
|
@ -1671,6 +1690,40 @@ handle_event_hold(struct libinput_event *ev, struct window *w)
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
undo_tap(gpointer data)
|
||||
{
|
||||
struct window *w = data;
|
||||
|
||||
w->tap.active = false;
|
||||
gtk_widget_queue_draw(w->area);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_event_tap(struct libinput_event *ev, struct window *w)
|
||||
{
|
||||
struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev);
|
||||
int nfingers;
|
||||
|
||||
nfingers = libinput_event_gesture_get_finger_count(g);
|
||||
|
||||
switch (libinput_event_get_type(ev)) {
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_BEGIN:
|
||||
w->tap.nfingers = nfingers;
|
||||
w->tap.active = true;
|
||||
g_timeout_add(75, undo_tap, w);
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_END:
|
||||
/* active is handled by a timer because we get begin/end
|
||||
* at effectively the same time */
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_event_tablet(struct libinput_event *ev, struct window *w)
|
||||
{
|
||||
|
|
@ -1811,6 +1864,7 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
|
|||
tools_dispatch(li);
|
||||
|
||||
while ((ev = libinput_get_event(li))) {
|
||||
|
||||
switch (libinput_event_get_type(ev)) {
|
||||
case LIBINPUT_EVENT_NONE:
|
||||
abort();
|
||||
|
|
@ -1864,6 +1918,10 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
|
|||
case LIBINPUT_EVENT_GESTURE_HOLD_END:
|
||||
handle_event_hold(ev, w);
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_BEGIN:
|
||||
case LIBINPUT_EVENT_GESTURE_TAP_END:
|
||||
handle_event_tap(ev, w);
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue