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);