diff --git a/doc/Makefile.am b/doc/Makefile.am index 5391f225..382f64da 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -27,6 +27,7 @@ header_files = \ $(srcdir)/tablet-support.dox \ $(srcdir)/tapping.dox \ $(srcdir)/test-suite.dox \ + $(srcdir)/timestamps.dox \ $(srcdir)/tools.dox \ $(srcdir)/touchpad-jumping-cursors.dox \ $(srcdir)/touchpad-pressure.dox \ diff --git a/doc/page-hierarchy.dox b/doc/page-hierarchy.dox index 65749feb..1f0b735a 100644 --- a/doc/page-hierarchy.dox +++ b/doc/page-hierarchy.dox @@ -24,10 +24,11 @@ - @subpage tablet-support -@page general General setup +@page general General - @subpage udev_config - @subpage seats +- @subpage timestamps @page misc Users diff --git a/doc/timestamps.dox b/doc/timestamps.dox new file mode 100644 index 00000000..a823c002 --- /dev/null +++ b/doc/timestamps.dox @@ -0,0 +1,36 @@ +/** + +@page timestamps Timestamps + +@section event_timestamps Event timestamps + +Most libinput events provide a timestamp in millisecond and/or microsecond +resolution. These timestamp usually increase monotonically, but libinput +does not guarantee that this always the case. In other words, it is possible +to receive an event with a timestamp earlier than the previous event. + +For example, if a touchpad has @ref tapping enabled, a button event may have a +lower timestamp than an event from a different device. Tapping requires the +use of timeouts to detect multi-finger taps and/or @ref tapndrag. + +Consider the following event sequences from a touchpad and a mouse: + +
+Time      Touchpad      Mouse
+---------------------------------
+t1       finger down
+t2        finger up
+t3                     movement
+t4       tap timeout
+
+ +For this event sequence, the first event to be sent to a caller is in +response to the mouse movement: an event of type @ref +LIBINPUT_EVENT_POINTER_MOTION with the timestamp t3. +Once the timeout expires at t4, libinput generates an event of +@ref LIBINPUT_EVENT_POINTER_BUTTON (press) with a timestamp t1 and an event +@ref LIBINPUT_EVENT_POINTER_BUTTON (release) with a timestamp t2. + +Thus, the caller gets events with timestamps in the order t3, t1, t2, +despite t3 > t2 > t1. +*/ diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 29989c9e..5a237fec 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -152,7 +152,7 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_TOUCH; - tp->tap.first_press_time = time; + tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: @@ -182,15 +182,17 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_TOUCH_2; + tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: tp_tap_notify(tp, - tp->tap.first_press_time, + tp->tap.saved_press_time, 1, LIBINPUT_BUTTON_STATE_PRESSED); if (tp->tap.drag_enabled) { tp->tap.state = TAP_STATE_TAPPED; + tp->tap.saved_release_time = time; tp_tap_set_timer(tp, time); } else { tp_tap_notify(tp, @@ -226,6 +228,7 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_TOUCH_2; + tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: @@ -258,15 +261,22 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DRAGGING_OR_DOUBLETAP; + tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_THUMB: break; @@ -282,10 +292,12 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: 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.state = TAP_STATE_TOUCH_2_RELEASE; + tp->tap.saved_release_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_MOTION: @@ -311,6 +323,7 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_TOUCH_3; + tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: @@ -341,8 +354,14 @@ tp_tap_touch2_release_handle_event(struct tp_dispatch *tp, tp_tap_clear_timer(tp); break; case TAP_EVENT_RELEASE: - tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_press_time, + 2, + LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 2, + LIBINPUT_BUTTON_STATE_RELEASED); tp->tap.state = TAP_STATE_IDLE; break; case TAP_EVENT_MOTION: @@ -376,7 +395,10 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_TOUCH_2_HOLD; if (t->tap.state == TAP_TOUCH_STATE_TOUCH) { - tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_press_time, + 3, + LIBINPUT_BUTTON_STATE_PRESSED); tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_RELEASED); } break; @@ -424,7 +446,11 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_MULTITAP; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); + tp->tap.saved_release_time = time; break; case TAP_EVENT_MOTION: case TAP_EVENT_TIMEOUT: @@ -432,7 +458,10 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_THUMB: break; @@ -568,7 +597,11 @@ tp_tap_multitap_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_MULTITAP_DOWN; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_press_time, + 1, + LIBINPUT_BUTTON_STATE_PRESSED); + tp->tap.saved_press_time = time; tp_tap_set_timer(tp, time); break; case TAP_EVENT_MOTION: @@ -577,8 +610,14 @@ tp_tap_multitap_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_press_time, + 1, + LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_IDLE; @@ -598,7 +637,11 @@ tp_tap_multitap_down_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_MULTITAP; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); + tp->tap.saved_release_time = time; break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DRAGGING_2; @@ -611,7 +654,10 @@ tp_tap_multitap_down_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, + tp->tap.saved_release_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); tp_tap_clear_timer(tp); break; case TAP_EVENT_THUMB: diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 38c3c921..8140c446 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1262,6 +1262,28 @@ tp_handle_state(struct tp_dispatch *tp, tp_clickpad_middlebutton_apply_config(tp->device); } +static inline void +tp_debug_touch_state(struct tp_dispatch *tp, + struct evdev_device *device) +{ + char buf[1024] = {0}; + struct tp_touch *t; + size_t i = 0; + + tp_for_each_touch(tp, t) { + if (i >= tp->nfingers_down) + break; + sprintf(&buf[strlen(buf)], + "slot %zd: %04d/%04d p%03d %s |", + i++, + t->point.x, + t->point.y, + t->pressure, + tp_touch_active(tp, t) ? "" : "inactive"); + } + evdev_log_debug(device, "touch state: %s\n", buf); +} + static void tp_interface_process(struct evdev_dispatch *dispatch, struct evdev_device *device, @@ -1285,6 +1307,9 @@ tp_interface_process(struct evdev_dispatch *dispatch, break; case EV_SYN: tp_handle_state(tp, time); +#if 0 + tp_debug_touch_state(tp, device); +#endif break; } } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 8d5bbc44..304e92f8 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -321,7 +321,8 @@ struct tp_dispatch { struct libinput_timer timer; enum tp_tap_state state; uint32_t buttons_pressed; - uint64_t first_press_time; + uint64_t saved_press_time, + saved_release_time; enum libinput_config_tap_button_map map; enum libinput_config_tap_button_map want_map; diff --git a/src/libinput-private.h b/src/libinput-private.h index a1d50002..1a564f9f 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -136,6 +136,8 @@ struct libinput { int refcount; struct list device_group_list; + + uint64_t last_event_time; }; typedef void (*libinput_seat_destroy_func) (struct libinput_seat *seat); diff --git a/src/libinput.c b/src/libinput.c index 514a6119..472b1c0c 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -25,6 +25,7 @@ #include "config.h" #include +#include #include #include #include @@ -73,6 +74,43 @@ check_event_type(struct libinput *libinput, return rc; } +static inline const char * +event_type_to_str(enum libinput_event_type type) +{ + switch(type) { + CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_ADDED); + CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_REMOVED); + CASE_RETURN_STRING(LIBINPUT_EVENT_KEYBOARD_KEY); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_BUTTON); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_AXIS); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_DOWN); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_UP); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_MOTION); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_CANCEL); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_FRAME); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_AXIS); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_TIP); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_BUTTON); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_RING); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_STRIP); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_END); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END); + CASE_RETURN_STRING(LIBINPUT_EVENT_SWITCH_TOGGLE); + case LIBINPUT_EVENT_NONE: + abort(); + } + + return NULL; +} + struct libinput_source { libinput_source_dispatch_t dispatch; void *user_data; @@ -2026,6 +2064,17 @@ post_device_event(struct libinput_device *device, struct libinput_event *event) { struct libinput_event_listener *listener, *tmp; +#if 0 + struct libinput *libinput = device->seat->libinput; + + if (libinput->last_event_time > time) { + log_bug_libinput(device->seat->libinput, + "out-of-order timestamps for %s time %" PRIu64 "\n", + event_type_to_str(type), + time); + } + libinput->last_event_time = time; +#endif init_event_base(event, device, type); @@ -2660,43 +2709,6 @@ gesture_notify_pinch_end(struct libinput_device *device, finger_count, cancelled, &zero, &zero, scale, 0.0); } -static inline const char * -event_type_to_str(enum libinput_event_type type) -{ - switch(type) { - CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_ADDED); - CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_REMOVED); - CASE_RETURN_STRING(LIBINPUT_EVENT_KEYBOARD_KEY); - CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION); - CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); - CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_BUTTON); - CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_AXIS); - CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_DOWN); - CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_UP); - CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_MOTION); - CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_CANCEL); - CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_FRAME); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_AXIS); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_TIP); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_BUTTON); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_BUTTON); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_RING); - CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_STRIP); - CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN); - CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE); - CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_END); - CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN); - CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE); - CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END); - CASE_RETURN_STRING(LIBINPUT_EVENT_SWITCH_TOGGLE); - case LIBINPUT_EVENT_NONE: - abort(); - } - - return NULL; -} - void switch_notify_toggle(struct libinput_device *device, uint64_t time, diff --git a/src/libinput.h b/src/libinput.h index 0540f231..6b63d475 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -972,6 +972,9 @@ libinput_event_device_notify_get_base_event(struct libinput_event_device_notify /** * @ingroup event_keyboard * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event */ uint32_t @@ -980,6 +983,9 @@ libinput_event_keyboard_get_time(struct libinput_event_keyboard *event); /** * @ingroup event_keyboard * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event in microseconds */ uint64_t @@ -1035,6 +1041,9 @@ libinput_event_keyboard_get_seat_key_count( /** * @ingroup event_pointer * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event */ uint32_t @@ -1043,6 +1052,9 @@ libinput_event_pointer_get_time(struct libinput_event_pointer *event); /** * @ingroup event_pointer * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event in microseconds */ uint64_t @@ -1400,6 +1412,9 @@ libinput_event_pointer_get_base_event(struct libinput_event_pointer *event); /** * @ingroup event_touch * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event */ uint32_t @@ -1408,6 +1423,9 @@ libinput_event_touch_get_time(struct libinput_event_touch *event); /** * @ingroup event_touch * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event in microseconds */ uint64_t @@ -1564,6 +1582,9 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event); /** * @ingroup event_gesture * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event */ uint32_t @@ -1572,6 +1593,9 @@ libinput_event_gesture_get_time(struct libinput_event_gesture *event); /** * @ingroup event_gesture * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @return The event time for this event in microseconds */ uint64_t @@ -2300,6 +2324,9 @@ libinput_event_tablet_tool_get_seat_button_count(struct libinput_event_tablet_to /** * @ingroup event_tablet * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @param event The libinput tablet tool event * @return The event time for this event */ @@ -2309,6 +2336,9 @@ libinput_event_tablet_tool_get_time(struct libinput_event_tablet_tool *event); /** * @ingroup event_tablet * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @param event The libinput tablet tool event * @return The event time for this event in microseconds */ @@ -2735,6 +2765,9 @@ libinput_event_tablet_pad_get_mode_group(struct libinput_event_tablet_pad *event /** * @ingroup event_tablet_pad * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @param event The libinput tablet pad event * @return The event time for this event */ @@ -2744,6 +2777,9 @@ libinput_event_tablet_pad_get_time(struct libinput_event_tablet_pad *event); /** * @ingroup event_tablet_pad * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @param event The libinput tablet pad event * @return The event time for this event in microseconds */ @@ -2799,6 +2835,9 @@ libinput_event_switch_get_base_event(struct libinput_event_switch *event); /** * @ingroup event_switch * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @param event The libinput switch event * @return The event time for this event */ @@ -2808,6 +2847,9 @@ libinput_event_switch_get_time(struct libinput_event_switch *event); /** * @ingroup event_switch * + * @note Timestamps may not always increase. See @ref event_timestamps for + * details. + * * @param event The libinput switch event * @return The event time for this event in microseconds */ diff --git a/test/test-touchpad-tap.c b/test/test-touchpad-tap.c index cc0d86fd..d7b39ef9 100644 --- a/test/test-touchpad-tap.c +++ b/test/test-touchpad-tap.c @@ -69,8 +69,11 @@ START_TEST(touchpad_1fg_doubletap) litest_drain_events(li); litest_touch_down(dev, 0, 50, 50); + msleep(10); litest_touch_up(dev, 0); + msleep(10); litest_touch_down(dev, 0, 50, 50); + msleep(10); litest_touch_up(dev, 0); libinput_dispatch(li); @@ -90,7 +93,7 @@ START_TEST(touchpad_1fg_doubletap) LIBINPUT_BUTTON_STATE_RELEASED); curtime = libinput_event_pointer_get_time(ptrev); libinput_event_destroy(event); - ck_assert_int_le(oldtime, curtime); + ck_assert_int_lt(oldtime, curtime); event = libinput_get_event(li); ptrev = litest_is_button_event(event, @@ -107,7 +110,7 @@ START_TEST(touchpad_1fg_doubletap) LIBINPUT_BUTTON_STATE_RELEASED); curtime = libinput_event_pointer_get_time(ptrev); libinput_event_destroy(event); - ck_assert_int_le(oldtime, curtime); + ck_assert_int_lt(oldtime, curtime); litest_assert_empty_queue(li); } @@ -125,6 +128,7 @@ START_TEST(touchpad_1fg_multitap) ntaps; litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -173,6 +177,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_move) ntaps; litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -242,6 +247,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_2fg) return; litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -313,6 +319,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_click) ntaps; litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -361,6 +368,54 @@ START_TEST(touchpad_1fg_multitap_n_drag_click) } END_TEST +START_TEST(touchpad_1fg_multitap_timeout) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t ptime, rtime; + int range = _i, /* looped test */ + ntaps; + + litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); + + litest_drain_events(li); + + for (ntaps = 0; ntaps <= range; ntaps++) { + litest_touch_down(dev, 0, 50, 50); + msleep(10); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(10); + } + + libinput_dispatch(li); + litest_timeout_tap(); + libinput_dispatch(li); + + for (ntaps = 0; ntaps <= range; ntaps++) { + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + ptime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + rtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_lt(ptime, rtime); + } + + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(touchpad_1fg_multitap_n_drag_timeout) { struct litest_device *dev = litest_current_device(); @@ -373,11 +428,13 @@ START_TEST(touchpad_1fg_multitap_n_drag_timeout) ntaps; litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); for (ntaps = 0; ntaps <= range; ntaps++) { litest_touch_down(dev, 0, 50, 50); + msleep(10); litest_touch_up(dev, 0); libinput_dispatch(li); msleep(10); @@ -405,7 +462,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_timeout) LIBINPUT_BUTTON_STATE_RELEASED); curtime = libinput_event_pointer_get_time(ptrev); libinput_event_destroy(event); - ck_assert_int_ge(curtime, oldtime); + ck_assert_int_gt(curtime, oldtime); oldtime = curtime; } @@ -449,6 +506,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_tap) for (ntaps = 0; ntaps <= range; ntaps++) { litest_touch_down(dev, 0, 50, 50); + msleep(10); litest_touch_up(dev, 0); libinput_dispatch(li); msleep(10); @@ -522,6 +580,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_tap_click) for (ntaps = 0; ntaps <= range; ntaps++) { litest_touch_down(dev, 0, 50, 50); + msleep(10); litest_touch_up(dev, 0); libinput_dispatch(li); msleep(10); @@ -916,6 +975,9 @@ START_TEST(touchpad_2fg_tap) struct libinput *li = dev->libinput; enum libinput_config_tap_button_map map = _i; /* ranged test */ unsigned int button = 0; + struct libinput_event *ev; + struct libinput_event_pointer *ptrev; + uint64_t ptime, rtime; litest_enable_tap(dev->libinput_device); litest_set_tap_map(dev->libinput_device, map); @@ -940,11 +1002,20 @@ START_TEST(touchpad_2fg_tap) libinput_dispatch(li); - litest_assert_button_event(li, button, - LIBINPUT_BUTTON_STATE_PRESSED); - litest_timeout_tap(); - litest_assert_button_event(li, button, - LIBINPUT_BUTTON_STATE_RELEASED); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + button, + LIBINPUT_BUTTON_STATE_PRESSED); + ptime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + button, + LIBINPUT_BUTTON_STATE_RELEASED); + rtime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + + ck_assert_int_lt(ptime, rtime); litest_assert_empty_queue(li); } @@ -956,6 +1027,9 @@ START_TEST(touchpad_2fg_tap_inverted) struct libinput *li = dev->libinput; enum libinput_config_tap_button_map map = _i; /* ranged test */ unsigned int button = 0; + struct libinput_event *ev; + struct libinput_event_pointer *ptrev; + uint64_t ptime, rtime; litest_enable_tap(dev->libinput_device); litest_set_tap_map(dev->libinput_device, map); @@ -980,11 +1054,20 @@ START_TEST(touchpad_2fg_tap_inverted) libinput_dispatch(li); - litest_assert_button_event(li, button, - LIBINPUT_BUTTON_STATE_PRESSED); - litest_timeout_tap(); - litest_assert_button_event(li, button, - LIBINPUT_BUTTON_STATE_RELEASED); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + button, + LIBINPUT_BUTTON_STATE_PRESSED); + ptime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + button, + LIBINPUT_BUTTON_STATE_RELEASED); + rtime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + + ck_assert_int_lt(ptime, rtime); litest_assert_empty_queue(li); } @@ -1379,11 +1462,18 @@ START_TEST(touchpad_3fg_tap) } for (i = 0; i < 3; i++) { + uint64_t ptime, rtime; + struct libinput_event *ev; + struct libinput_event_pointer *ptrev; + litest_drain_events(li); litest_touch_down(dev, 0, 50, 50); + msleep(5); litest_touch_down(dev, 1, 70, 50); + msleep(5); litest_touch_down(dev, 2, 80, 50); + msleep(10); litest_touch_up(dev, (i + 2) % 3); litest_touch_up(dev, (i + 1) % 3); @@ -1391,13 +1481,73 @@ START_TEST(touchpad_3fg_tap) libinput_dispatch(li); - litest_assert_button_event(li, button, - LIBINPUT_BUTTON_STATE_PRESSED); - litest_timeout_tap(); - litest_assert_button_event(li, button, - LIBINPUT_BUTTON_STATE_RELEASED); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + button, + LIBINPUT_BUTTON_STATE_PRESSED); + ptime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + button, + LIBINPUT_BUTTON_STATE_RELEASED); + rtime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); - litest_assert_empty_queue(li); + ck_assert_int_lt(ptime, rtime); + + } +} +END_TEST + +START_TEST(touchpad_3fg_tap_tap_again) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int i; + + if (libevdev_get_abs_maximum(dev->evdev, ABS_MT_SLOT) <= 2) + return; + + litest_enable_tap(dev->libinput_device); + + uint64_t ptime, rtime; + struct libinput_event *ev; + struct libinput_event_pointer *ptrev; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 50); + msleep(5); + litest_touch_down(dev, 1, 70, 50); + msleep(5); + litest_touch_down(dev, 2, 80, 50); + msleep(10); + litest_touch_up(dev, 0); + msleep(10); + litest_touch_down(dev, 0, 80, 50); + msleep(10); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + litest_touch_up(dev, 2); + + libinput_dispatch(li); + + for (i = 0; i < 2; i++) { + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + ptime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + ev = libinput_get_event(li); + ptrev = litest_is_button_event(ev, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); + rtime = libinput_event_pointer_get_time_usec(ptrev); + libinput_event_destroy(ev); + + ck_assert_int_lt(ptime, rtime); } } END_TEST @@ -2182,6 +2332,7 @@ litest_setup_tests_touchpad_tap(void) litest_add("tap-1fg:1fg", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY); litest_add("tap-1fg:1fg", touchpad_1fg_doubletap, LITEST_TOUCHPAD, LITEST_ANY); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); + litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap_timeout, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap_n_drag_tap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap_n_drag_move, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); @@ -2210,6 +2361,7 @@ litest_setup_tests_touchpad_tap(void) litest_add_ranged("tap-3fg:3fg", touchpad_3fg_tap_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &tap_map_range); litest_add_ranged("tap-3fg:3fg", touchpad_3fg_tap_btntool_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &tap_map_range); litest_add_ranged("tap-3fg:3fg", touchpad_3fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &tap_map_range); + litest_add("tap-3fg:3fg", touchpad_3fg_tap_tap_again, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-3fg:3fg", touchpad_3fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-4fg:4fg", touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); litest_add("tap-4fg:4fg", touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);