diff --git a/README.txt b/README.txt index 0849e1d1..f557f69c 100644 --- a/README.txt +++ b/README.txt @@ -56,6 +56,8 @@ Where possible, please provide an [evemu](http://www.freedesktop.org/wiki/Evemu/) recording of the input device and/or the event sequence in question. +See @ref reporting_bugs for more info. + Documentation ------------- diff --git a/configure.ac b/configure.ac index 65478d63..4a5cd825 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.64]) m4_define([libinput_major_version], [0]) -m4_define([libinput_minor_version], [20]) +m4_define([libinput_minor_version], [21]) m4_define([libinput_micro_version], [0]) m4_define([libinput_version], [libinput_major_version.libinput_minor_version.libinput_micro_version]) @@ -31,7 +31,7 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) # b) If interfaces have been changed or added, but binary compatibility has # been preserved, change to C+1:0:A+1 # c) If the interface is the same as the previous version, change to C:R+1:A -LIBINPUT_LT_VERSION=14:0:4 +LIBINPUT_LT_VERSION=15:0:5 AC_SUBST(LIBINPUT_LT_VERSION) AM_SILENT_RULES([yes]) diff --git a/doc/Makefile.am b/doc/Makefile.am index 4c487a3a..ff65e5ce 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -18,13 +18,15 @@ header_files = \ $(srcdir)/normalization-of-relative-motion.dox \ $(srcdir)/palm-detection.dox \ $(srcdir)/page-hierarchy.dox \ + $(srcdir)/reporting-bugs.dox \ $(srcdir)/scrolling.dox \ $(srcdir)/seats.dox \ $(srcdir)/t440-support.dox \ $(srcdir)/tablet-support.dox \ $(srcdir)/tapping.dox \ $(srcdir)/test-suite.dox \ - $(srcdir)/tools.dox + $(srcdir)/tools.dox \ + $(srcdir)/touchpads.dox diagram_files = \ $(srcdir)/dot/seats-sketch.gv \ diff --git a/doc/page-hierarchy.dox b/doc/page-hierarchy.dox index 78592fc2..1e82535f 100644 --- a/doc/page-hierarchy.dox +++ b/doc/page-hierarchy.dox @@ -25,6 +25,7 @@ - @subpage faq - @subpage tools +- @subpage reporting_bugs @page developers Developers diff --git a/doc/reporting-bugs.dox b/doc/reporting-bugs.dox new file mode 100644 index 00000000..0755a9ee --- /dev/null +++ b/doc/reporting-bugs.dox @@ -0,0 +1,88 @@ +/** +@page reporting_bugs Reporting bugs + +A new bug can be filed here: +https://bugs.freedesktop.org/enter_bug.cgi?product=Wayland&component=libinput + +When reporting bugs against libinput, please follow the instructions below +and provide the required data. This will speed up triage, resulting in a +quicker bugfix. + +First, try to identify the bugi by reproducing it reliably. The more +specific a bug description is, the easier it is to fix. The @ref +libinput-debug-events helper tool can help identify whether the bug is in +libinput at all. This tool is a direct hook to libinput without a desktop +stack in between and can thus help to identify whether a bug is in libinput +or in one of the higher layers. See the @ref libinput-debug-events section +for information on this tool. + +@section triage Required information for triage + +When you file a bug, please attach the following information: +- a virtual description of your input device, see @ref evemu. This is the + most important piece of information, do not forget it! +- the libinput version. Either the package version from your distribution + or, when running from git: git log -n 1 HEAD or git describe + HEAD. As a last resort: libinput-list-devices --version. +- the current libinput settings for the device. This is a bit harder to + obtain, for now we'll assume you are running X11. The current settings can + be obtained with xinput list-props "your device name". Use + xinput list to obtain the device name. +- if the device is a touchpad or a pointing stick, the vendor model number + of your laptop, and the content of /sys/class/dmi/id/modalias. +- if the device is a touchpad, the physical dimensions of your touchpad in + mm + +@section evemu Recording devices with evemu + +evemu records the +device capabilities together with the event stream from the kernel. On our +side, this allows us to recreate a virtual device identical to your device +and re-play the event sequence, hopefully triggering the same bug. + +evemu-record takes a /dev/input/eventX event node, but without arguments +it will simply show the list of devices and let you select: +@code +$ sudo evemu-record > scroll.evemu +Available devices: +/dev/input/event0: Lid Switch +/dev/input/event1: Sleep Button +/dev/input/event2: Power Button +/dev/input/event3: AT Translated Set 2 keyboard +/dev/input/event4: SynPS/2 Synaptics TouchPad +/dev/input/event5: Video Bus +/dev/input/event6: ELAN Touchscreen +/dev/input/event10: ThinkPad Extra Buttons +/dev/input/event11: HDA Intel HDMI HDMI/DP,pcm=3 +/dev/input/event12: HDA Intel HDMI HDMI/DP,pcm=7 +/dev/input/event13: HDA Intel HDMI HDMI/DP,pcm=8 +/dev/input/event14: HDA Intel PCH Dock Mic +/dev/input/event15: HDA Intel PCH Mic +/dev/input/event16: HDA Intel PCH Dock Headphone +/dev/input/event17: HDA Intel PCH Headphone +/dev/input/event18: Integrated Camera +/dev/input/event19: TPPS/2 IBM TrackPoint +Select the device event number [0-19]: +@endcode + +Select the device that triggers the issue, then reproduce the bug and Ctrl+C +the process. The resulting recording, ("scroll.evemu" in this example) will +contain the sequence required to reproduce the bug. If the bug fails to +reproduce during recording, simply Ctrl+C and restart evemu-record. +Always start the recording from a neutral state, i.e. without any buttons or +keys down, with the position of the device in the neutral position, without +touching the screen/touchpad. + +@note The longer the recording, the harder it is to identify the event +sequence triggering the bug. Please keep the event sequence as short as possible. + +To verify that the recording contains the bug, you can replay it on your +device. For example, to replay the sequence recorded in the example above: +@code +$ sudo evemu-play /dev/input/event4 < scroll.evemu +@endcode + +If the bug is triggered by replaying on your device, attach the recording to +the bug report. + +*/ diff --git a/doc/scrolling.dox b/doc/scrolling.dox index 658fe4b6..0c03c98d 100644 --- a/doc/scrolling.dox +++ b/doc/scrolling.dox @@ -44,6 +44,13 @@ movements will translate into tiny scroll movements. Scrolling in both directions at once is possible by meeting the required distance thresholds to enable each direction separately. +Two-finger scrolling requires the touchpad to track both touch points with +reasonable precision. Unfortunately, some so-called "semi-mt" touchpads can +only track the bounding box of the two fingers rather than the actual +position of each finger. In addition, that bounding box usually suffers from +a low resolution, causing jumpy movement during two-finger scrolling. +libinput does not provide two-finger scrolling on those touchpads. + @section edge_scrolling Edge scrolling On some touchpads, edge scrolling is available, triggered by moving a single diff --git a/doc/touchpads.dox b/doc/touchpads.dox new file mode 100644 index 00000000..fa509bc6 --- /dev/null +++ b/doc/touchpads.dox @@ -0,0 +1,162 @@ +/** +@page touchpads Touchpads + +This page provides an outline of touchpad devices. Touchpads aren't simply +categorised into a single type, instead they have a set of properties, a +combination of number of physical buttons, multitouch support abilities and +other properties. + +@section touchpads_buttons Number of buttons + +@subsection touchapds_buttons_phys Physically separate buttons + +Touchpads with physical buttons usually provide two buttons, left and right. +A few touchpads with three buttons exist, and Apple used to have touchpads +with a single physical buttons until ca 2008. Touchpads with only two +buttons require the software stack to emulate a middle button. libinput does +this when both buttons are pressed simultaneously. + +Note that many Lenovo laptops provide a pointing stick above the touchpad. +This pointing stick has a set of physical buttons just above the touchpad. +While many users use those as substitute touchpad buttons, they logically +belong to the pointing stick. The *40 and *50 series are an exception here, +the former had no physical buttons on the touchpad and required the top +section of the pad to emulate pointing stick buttons, the *50 series has +physical buttons but they are wired to the touchpads. The kernel re-routes +those buttons through the trackstick device. See @ref t440_support for more +information. + +@subsection touchpads_buttons_clickpads Clickpads + +Clickpads are the most common type of touchpads these days. A Clickpad has +no separate physical buttons, instead the touchpad itself is clickable as a +whole, i.e. a user presses down on the touch area and triggers a physical +click. Clickpads thus only provide a single button, everything else needs to +be software-emulated. See @ref clickpad_softbuttons for more information. + +Clickpads are labelled by the kernel with the @c INPUT_PROP_BUTTONPAD input +property. + +@subsection touchpads_buttons_forcepads Forcepads + +Forcepads are Clickpads without a physical button underneath the hardware. +They provide pressure and may have a vibration element that is +software-controlled. This element can simulate the feel of a physical +click or be co-opted for other tasks. + + +@section touchpads_touch Touch capabilities + +Virtually all touchpads available now can detect multiple fingers on +the touchpad, i.e. provide information on how many fingers are on the +touchpad. The touch capabilities described here specify how many fingers a +device can track, i.e. provide reliable positional information for. +In the kernel each finger is tracked in a so-called "slot", the number of +slots thus equals the number of simultaneous touches a device can track. + +@subsection touchapds_touch_st Single-touch touchpads + +Single-finger touchpads can track a single touchpoint. Most single-touch +touchpads can also detect three fingers on the touchpad, but no positional +information is provided for those. In libinput, these touches are termed +"fake touches". The kernel sends @c BTN_TOOL_DOUBLETAP, @c +BTN_TOOL_TRIPLETAP, @c BTN_TOOL_QUADTAP and @c BTN_TOOL_QUINTTAP events when +multiple fingers are detected. + +@subsection touchpads_touch_mt Pure multi-touch touchpads + +Pure multi-touch touchpads are those that can track, i.e. identify the +location of all fingers on the touchpad. Apple's touchpads support 16 +touches, others support 5 touches like the Synaptics touchpads when using +SMBus. + +These touchpads usually also provide extra information. Apple touchpads +provide an ellipsis and the orientation of the ellipsis for each touch point. +Other touchpads provide a pressure value for each touch point (see @ref +touchpads_pressure_handling). + +Note that the kernel sends @c BTN_TOOL_DOUBLETAP, @c +BTN_TOOL_TRIPLETAP, @c BTN_TOOL_QUADTAP and @c BTN_TOOL_QUINTTAP events for +all touches for backwards compatibility. libinput ignores these events if +the touchpad can track touches correctly. + +@subsection touchpads_touch_partial_mt Partial multi-touch touchpads + +The vast majority of touchpads fall into this category, the half-way +point between single-touch and pure multi-touch. These devices can track N +fingers, but detect more than N. For example, when using the serial +protocol, Synaptics touchpads can track two fingers but may detect up to +five. + +The number of slots may limit which features are available in libinput. +Any device with two slots can support two-finger scrolling, but @ref +thumb-detection or @ref palm_detection may be limited if only two slots are +available. + +@subsection touchpads_touch_semi_mt Semi-mt touchpads + +A sub-class of partial multi-touch touchpads. These touchpads can +technically detect two fingers but the location of both is limited to the +bounding box, i.e. the first touch is always the top-left one and the second +touch is the bottom-right one. Coordinates jump around as fingers move past +each other. + +Many semi-mt touchpads also have a lower resolution for the second touch, or +both touches. This may limit some features such as @ref gestures or +@ref scrolling. + +Semi-mt are labelled by the kernel with the @c INPUT_PROP_SEMI_MT input +property. + +@section touchpads_mis Other touchpad properties + +@subsection touchpads_external External touchpads + +External touchpads are USB or Bluetooth touchpads not in a laptop chassis, +e.g. Apple Magic Trackpad or the Logitech T650. These are usually @ref +touchpads_buttons_clickpads the biggest difference is that they can be +removed or added at runtime. + +One interaction method that is only possible on external touchpads is a +thumb resting on the very edge/immediately next to the touchpad. On the far +edge, touchpads don't always detect the finger location so clicking with a +thumb barely touching the edge makes it hard or impossible to figure out +which software button area the finger is on. + +These touchpads also don't need @ref palm_detection - since they're not +located underneath the keyboard, accidental palm touches are a non-issue. + +@subsection touchpads_pressure_handling Touchpads pressure handling + +Pressure is usually directly related to contact area. Human fingers flatten +out as the pressure on the pad increases, resulting in a bigger contact area +and the firmware then calculates that back into a ressure reading. + +libinput uses pressure to detect accidental palm contact and thumbs, though +pressure data is often device-specific and unreliable. + +@subsection touchpads_circular Circular touchpads + +Only listed for completeness, circular touchpads have not been used in +laptops for a number of years. These touchpad shaped in an ellipsis or +straight. + +@subsection touchpads_tablets Graphics tablets + +Touch-capable graphics tablets are effectively external touchpads, with two +differentiators: they are larger than normal touchpads and they have no +regular touchpad buttons. They either work like a @ref +touchpads_buttons_forcepads Forcepad, or rely on interaction methods that +don't require buttons (like @ref tapping). Since the physical device is +shared with the pen input, some touch arbitration is required to avoid touch +input interfering when the pen is in use. + +@subsection touchpads_edge_zone Dedicated edge scroll area + +Before @ref twofinger_scrolling became the default scroll method, some +touchpads provided a marking on the touch area that designates the +edge to be used for scrolling. A finger movement in that edge zone should +trigger vertical motions. Some touchpads had markers for a horizontal +scroll area too at the bottom of the touchpad. +*/ + diff --git a/src/evdev-middle-button.c b/src/evdev-middle-button.c index 48330d39..397b699c 100644 --- a/src/evdev-middle-button.c +++ b/src/evdev-middle-button.c @@ -27,7 +27,7 @@ #include "evdev.h" -#define MIDDLEBUTTON_TIMEOUT 50 +#define MIDDLEBUTTON_TIMEOUT ms2us(50) /***************************************** * BEFORE YOU EDIT THIS FILE, look at the state diagram in diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 1ee74cad..8822e08c 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -32,8 +32,8 @@ #include "evdev-mt-touchpad.h" -#define DEFAULT_BUTTON_ENTER_TIMEOUT 100 /* ms */ -#define DEFAULT_BUTTON_LEAVE_TIMEOUT 300 /* ms */ +#define DEFAULT_BUTTON_ENTER_TIMEOUT ms2us(100) +#define DEFAULT_BUTTON_LEAVE_TIMEOUT ms2us(300) /***************************************** * BEFORE YOU EDIT THIS FILE, look at the state diagram in @@ -714,7 +714,8 @@ tp_init_buttons(struct tp_dispatch *tp, "%s: clickpad advertising right button\n", device->devname); } else if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) && - !tp->buttons.is_clickpad) { + !tp->buttons.is_clickpad && + libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) { log_bug_kernel(libinput, "%s: non clickpad without right button?\n", device->devname); @@ -857,14 +858,12 @@ tp_clickfinger_set_button(struct tp_dispatch *tp) unsigned int nfingers = tp->nfingers_down; struct tp_touch *t; struct tp_touch *first = NULL, - *second = NULL, - *third = NULL; - uint32_t close_touches = 0; + *second = NULL; - if (nfingers < 2 || nfingers > 3) + if (nfingers != 2) goto out; - /* two or three fingers down on the touchpad. Check for distance + /* two fingers down on the touchpad. Check for distance * between the fingers. */ tp_for_each_touch(tp, t) { if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE) @@ -877,10 +876,6 @@ tp_clickfinger_set_button(struct tp_dispatch *tp) first = t; else if (!second) second = t; - else if (!third) { - third = t; - break; - } } if (!first || !second) { @@ -888,15 +883,10 @@ tp_clickfinger_set_button(struct tp_dispatch *tp) goto out; } - close_touches |= tp_check_clickfinger_distance(tp, first, second) << 0; - close_touches |= tp_check_clickfinger_distance(tp, second, third) << 1; - close_touches |= tp_check_clickfinger_distance(tp, first, third) << 2; - - switch(__builtin_popcount(close_touches)) { - case 0: nfingers = 1; break; - case 1: nfingers = 2; break; - default: nfingers = 3; break; - } + if (tp_check_clickfinger_distance(tp, first, second)) + nfingers = 2; + else + nfingers = 1; out: switch (nfingers) { @@ -923,8 +913,8 @@ tp_notify_clickpadbutton(struct tp_dispatch *tp, struct evdev_dispatch *dispatch = tp->buttons.trackpoint->dispatch; struct input_event event; - event.time.tv_sec = time/1000; - event.time.tv_usec = (time % 1000) * 1000; + event.time.tv_sec = time / ms2us(1000); + event.time.tv_usec = time % ms2us(1000); event.type = EV_KEY; event.code = button; event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0; diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index 928f6029..49028087 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -93,7 +93,7 @@ static inline void tp_edge_scroll_set_timer(struct tp_dispatch *tp, struct tp_touch *t) { - const int DEFAULT_SCROLL_LOCK_TIMEOUT = 300; /* ms */ + const int DEFAULT_SCROLL_LOCK_TIMEOUT = ms2us(300); /* if we use software buttons, we disable timeout-based * edge scrolling. A finger resting on the button areas is * likely there to trigger a button event. diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 1acf1111..d82a6fb9 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -29,8 +29,8 @@ #include "evdev-mt-touchpad.h" -#define DEFAULT_GESTURE_SWITCH_TIMEOUT 100 /* ms */ -#define DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT 1000 /* ms */ +#define DEFAULT_GESTURE_SWITCH_TIMEOUT ms2us(100) +#define DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT ms2us(500) static inline const char* gesture_state_to_str(enum tp_gesture_2fg_state state) @@ -157,7 +157,7 @@ tp_gesture_get_active_touches(struct tp_dispatch *tp, memset(touches, 0, count * sizeof(struct tp_touch *)); - for (i = 0; i < tp->num_slots; i++) { + for (i = 0; i < tp->ntouches; i++) { t = &tp->touches[i]; if (tp_touch_active(tp, t)) { touches[n++] = t; @@ -189,8 +189,10 @@ tp_gesture_get_direction(struct tp_dispatch *tp, struct tp_touch *touch) /* * Semi-mt touchpads have somewhat inaccurate coordinates when * 2 fingers are down, so use a slightly larger threshold. + * Elantech semi-mt touchpads are accurate enough though. */ - if (tp->semi_mt) + if (tp->semi_mt && + (tp->device->model_flags & EVDEV_MODEL_ELANTECH_TOUCHPAD) == 0) move_threshold = TP_MM_TO_DPI_NORMALIZED(4); else move_threshold = TP_MM_TO_DPI_NORMALIZED(2); @@ -264,26 +266,11 @@ tp_gesture_twofinger_handle_state_none(struct tp_dispatch *tp, uint64_t time) static enum tp_gesture_2fg_state tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) { - struct normalized_coords normalized; - struct device_float_coords delta; struct tp_touch *first = tp->gesture.touches[0], *second = tp->gesture.touches[1]; int dir1, dir2; - delta = device_delta(first->point, second->point); - normalized = tp_normalize_delta(tp, delta); - - /* If fingers are further than 3 cm apart assume pinch */ - if (normalized_length(normalized) > TP_MM_TO_DPI_NORMALIZED(30)) { - tp_gesture_get_pinch_info(tp, - &tp->gesture.initial_distance, - &tp->gesture.angle, - &tp->gesture.center); - tp->gesture.prev_scale = 1.0; - return GESTURE_2FG_STATE_PINCH; - } - - /* Elif fingers have been close together for a while, scroll */ + /* if fingers stay unmoving for a while, assume (slow) scroll */ if (time > (tp->gesture.initial_time + DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT)) { tp_gesture_set_scroll_buildup(tp); return GESTURE_2FG_STATE_SCROLL; @@ -310,7 +297,7 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) ((dir2 & 0x80) && (dir1 & 0x01))) { tp_gesture_set_scroll_buildup(tp); return GESTURE_2FG_STATE_SCROLL; - } else { + } else if (tp->gesture.enabled) { tp_gesture_get_pinch_info(tp, &tp->gesture.initial_distance, &tp->gesture.angle, @@ -318,6 +305,8 @@ tp_gesture_twofinger_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) tp->gesture.prev_scale = 1.0; return GESTURE_2FG_STATE_PINCH; } + + return GESTURE_2FG_STATE_UNKNOWN; } static enum tp_gesture_2fg_state @@ -578,6 +567,11 @@ tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time) int tp_init_gesture(struct tp_dispatch *tp) { + if (tp->device->model_flags & EVDEV_MODEL_JUMPING_SEMI_MT) + tp->gesture.enabled = false; + else + tp->gesture.enabled = true; + tp->gesture.twofinger_state = GESTURE_2FG_STATE_NONE; libinput_timer_init(&tp->gesture.finger_count_switch_timer, diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index b2977545..de4945e6 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -35,8 +35,8 @@ #include "evdev-mt-touchpad.h" -#define DEFAULT_TAP_TIMEOUT_PERIOD 180 -#define DEFAULT_DRAG_TIMEOUT_PERIOD 300 +#define DEFAULT_TAP_TIMEOUT_PERIOD ms2us(180) +#define DEFAULT_DRAG_TIMEOUT_PERIOD ms2us(300) #define DEFAULT_TAP_MOVE_THRESHOLD TP_MM_TO_DPI_NORMALIZED(3) enum tap_event { diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 8be7db30..0d4d8578 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -30,9 +30,10 @@ #include "evdev-mt-touchpad.h" -#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT 300 /* ms */ -#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 200 /* ms */ -#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 500 /* ms */ +#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT ms2us(300) +#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 ms2us(200) +#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 ms2us(500) +#define THUMB_MOVE_TIMEOUT ms2us(300) #define FAKE_FINGER_OVERFLOW (1 << 7) static inline int @@ -588,7 +589,7 @@ tp_palm_detect_trackpoint(struct tp_dispatch *tp, static void tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { - const int PALM_TIMEOUT = 200; /* ms */ + const int PALM_TIMEOUT = ms2us(200); const int DIRECTIONS = NE|E|SE|SW|W|NW; struct device_float_coords delta; int dirs; @@ -700,7 +701,7 @@ tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) t->thumb.state = THUMB_STATE_YES; else if (t->point.y > tp->thumb.lower_thumb_line && tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE && - t->thumb.first_touch_time + 300 < time) + t->thumb.first_touch_time + THUMB_MOVE_TIMEOUT < time) t->thumb.state = THUMB_STATE_YES; /* now what? we marked it as thumb, so: @@ -1465,6 +1466,21 @@ tp_init_slots(struct tp_dispatch *tp, tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT); + /* This device has a terrible resolution when two fingers are down, + * causing scroll jumps. The single-touch emulation ABS_X/Y is + * accurate but the ABS_MT_POSITION touchpoints report the bounding + * box and that causes jumps. So we simply pretend it's a single + * touch touchpad with the BTN_TOOL bits. + * See https://bugzilla.redhat.com/show_bug.cgi?id=1235175 for an + * explanation. + */ + if (tp->semi_mt && + (device->model_flags & EVDEV_MODEL_JUMPING_SEMI_MT)) { + tp->num_slots = 1; + tp->slot = 0; + tp->has_mt = false; + } + ARRAY_FOR_EACH(max_touches, m) { if (libevdev_has_event_code(device->evdev, EV_KEY, @@ -1522,10 +1538,8 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) } static uint32_t -tp_scroll_config_scroll_method_get_methods(struct libinput_device *device) +tp_scroll_get_methods(struct tp_dispatch *tp) { - struct evdev_device *evdev = (struct evdev_device*)device; - struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; uint32_t methods = LIBINPUT_CONFIG_SCROLL_EDGE; if (tp->ntouches >= 2) @@ -1534,6 +1548,15 @@ tp_scroll_config_scroll_method_get_methods(struct libinput_device *device) return methods; } +static uint32_t +tp_scroll_config_scroll_method_get_methods(struct libinput_device *device) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp_scroll_get_methods(tp); +} + static enum libinput_config_status tp_scroll_config_scroll_method_set_method(struct libinput_device *device, enum libinput_config_scroll_method method) @@ -1565,10 +1588,21 @@ tp_scroll_config_scroll_method_get_method(struct libinput_device *device) static enum libinput_config_scroll_method tp_scroll_get_default_method(struct tp_dispatch *tp) { - if (tp->ntouches >= 2) - return LIBINPUT_CONFIG_SCROLL_2FG; + uint32_t methods; + enum libinput_config_scroll_method method; + + methods = tp_scroll_get_methods(tp); + + if (methods & LIBINPUT_CONFIG_SCROLL_2FG) + method = LIBINPUT_CONFIG_SCROLL_2FG; else - return LIBINPUT_CONFIG_SCROLL_EDGE; + method = LIBINPUT_CONFIG_SCROLL_EDGE; + + if ((methods & method) == 0) + log_bug_libinput(tp_libinput_context(tp), + "Invalid default scroll method %d\n", + method); + return method; } static enum libinput_config_scroll_method @@ -1732,13 +1766,6 @@ tp_init_thumb(struct tp_dispatch *tp) if (!tp->buttons.is_clickpad) return 0; - abs = libevdev_get_abs_info(device->evdev, ABS_MT_PRESSURE); - if (!abs) - return 0; - - if (abs->maximum - abs->minimum < 255) - return 0; - /* if the touchpad is less than 50mm high, skip thumb detection. * it's too small to meaningfully interact with a thumb on the * touchpad */ @@ -1746,6 +1773,23 @@ tp_init_thumb(struct tp_dispatch *tp) if (h < 50) return 0; + tp->thumb.detect_thumbs = true; + tp->thumb.threshold = INT_MAX; + + /* detect thumbs by pressure in the bottom 15mm, detect thumbs by + * lingering in the bottom 8mm */ + ymax = tp->device->abs.absinfo_y->maximum; + yres = tp->device->abs.absinfo_y->resolution; + tp->thumb.upper_thumb_line = ymax - yres * 15; + tp->thumb.lower_thumb_line = ymax - yres * 8; + + abs = libevdev_get_abs_info(device->evdev, ABS_MT_PRESSURE); + if (!abs) + goto out; + + if (abs->maximum - abs->minimum < 255) + goto out; + /* Our reference touchpad is the T440s with 42x42 resolution. * Higher-res touchpads exhibit higher pressure for the same * interaction. On the T440s, the threshold value is 100, you don't @@ -1757,14 +1801,12 @@ tp_init_thumb(struct tp_dispatch *tp) yres = tp->device->abs.absinfo_y->resolution; threshold = 100.0 * hypot(xres, yres)/hypot(42, 42); tp->thumb.threshold = max(100, threshold); - tp->thumb.detect_thumbs = true; - /* detect thumbs by pressure in the bottom 15mm, detect thumbs by - * lingering in the bottom 8mm */ - ymax = tp->device->abs.absinfo_y->maximum; - yres = tp->device->abs.absinfo_y->resolution; - tp->thumb.upper_thumb_line = ymax - yres * 15; - tp->thumb.lower_thumb_line = ymax - yres * 8; +out: + log_debug(tp_libinput_context(tp), + "thumb: enabled thumb detection%s on '%s'\n", + tp->thumb.threshold != INT_MAX ? " (+pressure)" : "", + device->devname); return 0; } @@ -1892,6 +1934,8 @@ tp_init(struct tp_dispatch *tp, return -1; device->seat_caps |= EVDEV_DEVICE_POINTER; + if (tp->gesture.enabled) + device->seat_caps |= EVDEV_DEVICE_GESTURE; return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 6350a9f6..3bd84258 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -203,7 +203,7 @@ struct tp_touch { struct { enum touch_palm_state state; struct device_coords first; /* first coordinates if is_palm == true */ - uint32_t time; /* first timestamp if is_palm == true */ + uint64_t time; /* first timestamp if is_palm == true */ } palm; struct { @@ -246,6 +246,7 @@ struct tp_dispatch { } accel; struct { + bool enabled; bool started; unsigned int finger_count; unsigned int finger_count_pending; diff --git a/src/evdev.c b/src/evdev.c index 84768324..e58b007f 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -44,7 +44,7 @@ #include "libinput-private.h" #define DEFAULT_WHEEL_CLICK_ANGLE 15 -#define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT 200 +#define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT ms2us(200) enum evdev_key_type { EVDEV_KEY_TYPE_NONE, @@ -129,7 +129,7 @@ update_key_down_count(struct evdev_device *device, int code, int pressed) void evdev_keyboard_notify_key(struct evdev_device *device, - uint32_t time, + uint64_t time, int key, enum libinput_key_state state) { @@ -144,7 +144,7 @@ evdev_keyboard_notify_key(struct evdev_device *device, void evdev_pointer_notify_physical_button(struct evdev_device *device, - uint32_t time, + uint64_t time, int button, enum libinput_button_state state) { @@ -159,7 +159,7 @@ evdev_pointer_notify_physical_button(struct evdev_device *device, void evdev_pointer_notify_button(struct evdev_device *device, - uint32_t time, + uint64_t time, int button, enum libinput_button_state state) { @@ -457,7 +457,7 @@ evdev_button_scroll_button(struct evdev_device *device, { if (is_press) { libinput_timer_set(&device->scroll.timer, - time + DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT); + time + DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT); device->scroll.button_down_time = time; } else { libinput_timer_cancel(&device->scroll.timer); @@ -1271,7 +1271,7 @@ static inline void evdev_process_event(struct evdev_device *device, struct input_event *e) { struct evdev_dispatch *dispatch = device->dispatch; - uint64_t time = e->time.tv_sec * 1000ULL + e->time.tv_usec / 1000; + uint64_t time = s2us(e->time.tv_sec) + e->time.tv_usec; #if 0 if (libevdev_event_is_code(e, EV_SYN, SYN_REPORT)) @@ -1543,6 +1543,8 @@ evdev_read_model_flags(struct evdev_device *device) { "LIBINPUT_MODEL_WACOM_TOUCHPAD", EVDEV_MODEL_WACOM_TOUCHPAD }, { "LIBINPUT_MODEL_ALPS_TOUCHPAD", EVDEV_MODEL_ALPS_TOUCHPAD }, { "LIBINPUT_MODEL_SYNAPTICS_SERIAL_TOUCHPAD", EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD }, + { "LIBINPUT_MODEL_JUMPING_SEMI_MT", EVDEV_MODEL_JUMPING_SEMI_MT }, + { "LIBINPUT_MODEL_ELANTECH_TOUCHPAD", EVDEV_MODEL_ELANTECH_TOUCHPAD }, { NULL, EVDEV_MODEL_DEFAULT }, }; const struct model_map *m = model_map; @@ -1966,7 +1968,6 @@ evdev_configure_device(struct evdev_device *device) if (udev_tags & EVDEV_UDEV_TAG_TOUCHPAD) { device->dispatch = evdev_mt_touchpad_create(device); - device->seat_caps |= EVDEV_DEVICE_GESTURE; log_info(libinput, "input device '%s', %s is a touchpad\n", device->devname, devnode); @@ -2173,7 +2174,7 @@ evdev_device_create(struct libinput_seat *seat, device->dpi = DEFAULT_MOUSE_DPI; /* at most 5 SYN_DROPPED log-messages per 30s */ - ratelimit_init(&device->syn_drop_limit, 30ULL * 1000, 5); + ratelimit_init(&device->syn_drop_limit, s2us(30), 5); matrix_init_identity(&device->abs.calibration); matrix_init_identity(&device->abs.usermatrix); diff --git a/src/evdev.h b/src/evdev.h index 16f8be7a..b7c56c62 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -106,6 +106,8 @@ enum evdev_device_model { EVDEV_MODEL_WACOM_TOUCHPAD = (1 << 7), EVDEV_MODEL_ALPS_TOUCHPAD = (1 << 8), EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD = (1 << 9), + EVDEV_MODEL_JUMPING_SEMI_MT = (1 << 10), + EVDEV_MODEL_ELANTECH_TOUCHPAD = (1 << 11), }; struct mt_slot { @@ -368,18 +370,18 @@ evdev_notify_resumed_device(struct evdev_device *device); void evdev_keyboard_notify_key(struct evdev_device *device, - uint32_t time, + uint64_t time, int key, enum libinput_key_state state); void evdev_pointer_notify_button(struct evdev_device *device, - uint32_t time, + uint64_t time, int button, enum libinput_button_state state); void evdev_pointer_notify_physical_button(struct evdev_device *device, - uint32_t time, + uint64_t time, int button, enum libinput_button_state state); diff --git a/src/filter.c b/src/filter.c index 35449f56..2506ee27 100644 --- a/src/filter.c +++ b/src/filter.c @@ -85,13 +85,13 @@ filter_get_speed(struct motion_filter *filter) * Pointer acceleration filter constants */ -#define MAX_VELOCITY_DIFF 1.0 /* units/ms */ -#define MOTION_TIMEOUT 1000 /* (ms) */ +#define MAX_VELOCITY_DIFF 1 /* units/ms */ +#define MOTION_TIMEOUT ms2us(1000) #define NUM_POINTER_TRACKERS 16 struct pointer_tracker { struct normalized_coords delta; /* delta to most recent event */ - uint64_t time; /* ms */ + uint64_t time; /* us */ int dir; }; @@ -150,8 +150,7 @@ static double calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time) { double tdelta = time - tracker->time + 1; - - return normalized_length(tracker->delta) / tdelta; /* units/ms */ + return normalized_length(tracker->delta) / tdelta * 1000.0; /* units/ms */ } static inline double @@ -257,7 +256,7 @@ calculate_acceleration(struct pointer_accelerator *accel, static struct normalized_coords accelerator_filter(struct motion_filter *filter, const struct normalized_coords *unaccelerated, - void *data, uint64_t time) + void *data, uint64_t time /* in us */) { struct pointer_accelerator *accel = (struct pointer_accelerator *) filter; @@ -334,9 +333,9 @@ accelerator_set_speed(struct motion_filter *filter, assert(speed >= -1.0 && speed <= 1.0); /* delay when accel kicks in */ - accel_filter->threshold = DEFAULT_THRESHOLD - speed / 4.0; - if (accel_filter->threshold < 0.2) - accel_filter->threshold = 0.2; + accel_filter->threshold = DEFAULT_THRESHOLD - speed / 4000.0; + if (accel_filter->threshold < 0.0002) + accel_filter->threshold = 0.0002; /* adjust max accel factor */ accel_filter->accel = DEFAULT_ACCELERATION + speed * 1.5; @@ -398,8 +397,8 @@ create_pointer_accelerator_filter(accel_profile_func_t profile, double pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, void *data, - double speed_in, /* in device units */ - uint64_t time) + double speed_in, /* in device units (units/ms) */ + uint64_t time /* in us */) { struct pointer_accelerator *accel_filter = (struct pointer_accelerator *)filter; @@ -413,7 +412,7 @@ pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, max_accel /= dpi_factor; - s1 = min(1, 0.3 + speed_in * 10); + s1 = min(1, 0.3 + speed_in * 10.0); s2 = 1 + (speed_in - threshold * dpi_factor) * incline; factor = min(max_accel, s2 > 1 ? s2 : s1); @@ -425,7 +424,7 @@ double pointer_accel_profile_linear(struct motion_filter *filter, void *data, double speed_in, /* 1000-dpi normalized */ - uint64_t time) + uint64_t time /* in us */) { struct pointer_accelerator *accel_filter = (struct pointer_accelerator *)filter; @@ -446,9 +445,9 @@ pointer_accel_profile_linear(struct motion_filter *filter, double touchpad_accel_profile_linear(struct motion_filter *filter, - void *data, - double speed_in, - uint64_t time) + void *data, + double speed_in, + uint64_t time /* in us */) { /* Once normalized, touchpads see the same acceleration as mice. that is technically correct but @@ -469,7 +468,7 @@ double touchpad_lenovo_x230_accel_profile(struct motion_filter *filter, void *data, double speed_in, - uint64_t time) + uint64_t time /* in us */) { /* Keep the magic factor from touchpad_accel_profile_linear. */ const double TP_MAGIC_SLOWDOWN = 0.4; diff --git a/src/libinput-private.h b/src/libinput-private.h index c238da99..69ed26e3 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -307,6 +307,9 @@ open_restricted(struct libinput *libinput, void close_restricted(struct libinput *libinput, int fd); +bool +ignore_litest_test_suite_device(struct udev_device *device); + void libinput_seat_init(struct libinput_seat *seat, struct libinput *libinput, @@ -462,7 +465,7 @@ libinput_now(struct libinput *libinput) return 0; } - return ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; + return s2us(ts.tv_sec) + ns2us(ts.tv_nsec); } static inline struct device_float_coords diff --git a/src/libinput-util.c b/src/libinput-util.c index a383fa17..d35d7022 100644 --- a/src/libinput-util.c +++ b/src/libinput-util.c @@ -72,9 +72,9 @@ list_empty(const struct list *list) } void -ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst) +ratelimit_init(struct ratelimit *r, uint64_t ival_us, unsigned int burst) { - r->interval = ival_ms; + r->interval = ival_us; r->begin = 0; r->burst = burst; r->num = 0; @@ -97,17 +97,17 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r) { struct timespec ts; - uint64_t mtime; + uint64_t utime; if (r->interval <= 0 || r->burst <= 0) return RATELIMIT_PASS; clock_gettime(CLOCK_MONOTONIC, &ts); - mtime = ts.tv_sec * 1000 + ts.tv_nsec / 1000 / 1000; + utime = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); - if (r->begin <= 0 || r->begin + r->interval < mtime) { + if (r->begin <= 0 || r->begin + r->interval < utime) { /* reset counter */ - r->begin = mtime; + r->begin = utime; r->num = 1; return RATELIMIT_PASS; } else if (r->num < r->burst) { diff --git a/src/libinput-util.h b/src/libinput-util.h index 11d23780..ccb55677 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -328,4 +328,34 @@ int parse_mouse_wheel_click_angle_property(const char *prop); double parse_trackpoint_accel_property(const char *prop); bool parse_dimension_property(const char *prop, size_t *width, size_t *height); +static inline uint64_t +us(uint64_t us) +{ + return us; +} + +static inline uint64_t +ns2us(uint64_t ns) +{ + return us(ns / 1000); +} + +static inline uint64_t +ms2us(uint64_t ms) +{ + return us(ms * 1000); +} + +static inline uint64_t +s2us(uint64_t s) +{ + return ms2us(s * 1000); +} + +static inline uint32_t +us2ms(uint64_t us) +{ + return (uint32_t)(us / 1000); +} + #endif /* LIBINPUT_UTIL_H */ diff --git a/src/libinput.c b/src/libinput.c index 21b3cdc6..3557b8fd 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -86,7 +86,7 @@ struct libinput_event_device_notify { struct libinput_event_keyboard { struct libinput_event base; - uint32_t time; + uint64_t time; uint32_t key; uint32_t seat_key_count; enum libinput_key_state state; @@ -94,7 +94,7 @@ struct libinput_event_keyboard { struct libinput_event_pointer { struct libinput_event base; - uint32_t time; + uint64_t time; struct normalized_coords delta; struct device_float_coords delta_raw; struct device_coords absolute; @@ -108,7 +108,7 @@ struct libinput_event_pointer { struct libinput_event_touch { struct libinput_event base; - uint32_t time; + uint64_t time; int32_t slot; int32_t seat_slot; struct device_coords point; @@ -116,7 +116,7 @@ struct libinput_event_touch { struct libinput_event_gesture { struct libinput_event base; - uint32_t time; + uint64_t time; int finger_count; int cancelled; struct normalized_coords delta; @@ -304,6 +304,17 @@ libinput_event_get_device_notify_event(struct libinput_event *event) LIBINPUT_EXPORT uint32_t libinput_event_keyboard_get_time(struct libinput_event_keyboard *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_keyboard_get_time_usec(struct libinput_event_keyboard *event) { require_event_type(libinput_event_get_context(&event->base), event->base.type, @@ -349,6 +360,20 @@ libinput_event_keyboard_get_seat_key_count( LIBINPUT_EXPORT uint32_t libinput_event_pointer_get_time(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, + LIBINPUT_EVENT_POINTER_BUTTON, + LIBINPUT_EVENT_POINTER_AXIS); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_pointer_get_time_usec(struct libinput_event_pointer *event) { require_event_type(libinput_event_get_context(&event->base), event->base.type, @@ -587,6 +612,21 @@ libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event) LIBINPUT_EXPORT uint32_t libinput_event_touch_get_time(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL, + LIBINPUT_EVENT_TOUCH_FRAME); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_touch_get_time_usec(struct libinput_event_touch *event) { require_event_type(libinput_event_get_context(&event->base), event->base.type, @@ -692,6 +732,22 @@ libinput_event_touch_get_y(struct libinput_event_touch *event) LIBINPUT_EXPORT uint32_t libinput_event_gesture_get_time(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_gesture_get_time_usec(struct libinput_event_gesture *event) { require_event_type(libinput_event_get_context(&event->base), event->base.type, @@ -1226,6 +1282,16 @@ close_restricted(struct libinput *libinput, int fd) return libinput->interface->close_restricted(fd, libinput->user_data); } +bool +ignore_litest_test_suite_device(struct udev_device *device) +{ + if (!getenv("LIBINPUT_RUNNING_TEST_SUITE") && + udev_device_get_property_value(device, "LIBINPUT_TEST_DEVICE")) + return true; + + return false; +} + void libinput_seat_init(struct libinput_seat *seat, struct libinput *libinput, diff --git a/src/libinput.h b/src/libinput.h index 9a3052c8..212ee351 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -555,6 +555,14 @@ libinput_event_device_notify_get_base_event(struct libinput_event_device_notify uint32_t libinput_event_keyboard_get_time(struct libinput_event_keyboard *event); +/** + * @ingroup event_keyboard + * + * @return The event time for this event in microseconds + */ +uint64_t +libinput_event_keyboard_get_time_usec(struct libinput_event_keyboard *event); + /** * @ingroup event_keyboard * @@ -610,6 +618,14 @@ libinput_event_keyboard_get_seat_key_count( uint32_t libinput_event_pointer_get_time(struct libinput_event_pointer *event); +/** + * @ingroup event_pointer + * + * @return The event time for this event in microseconds + */ +uint64_t +libinput_event_pointer_get_time_usec(struct libinput_event_pointer *event); + /** * @ingroup event_pointer * @@ -952,6 +968,14 @@ libinput_event_pointer_get_base_event(struct libinput_event_pointer *event); uint32_t libinput_event_touch_get_time(struct libinput_event_touch *event); +/** + * @ingroup event_touch + * + * @return The event time for this event in microseconds + */ +uint64_t +libinput_event_touch_get_time_usec(struct libinput_event_touch *event); + /** * @ingroup event_touch * @@ -1104,6 +1128,14 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event); uint32_t libinput_event_gesture_get_time(struct libinput_event_gesture *event); +/** + * @ingroup event_gesture + * + * @return The event time for this event in microseconds + */ +uint64_t +libinput_event_gesture_get_time_usec(struct libinput_event_gesture *event); + /** * @ingroup event_gesture * diff --git a/src/libinput.sym b/src/libinput.sym index fb1c59b7..15295474 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -168,6 +168,10 @@ LIBINPUT_0.21.0 { libinput_device_config_dwt_set_enabled; libinput_device_config_dwt_get_enabled; libinput_device_config_dwt_get_default_enabled; + libinput_event_gesture_get_time_usec; + libinput_event_keyboard_get_time_usec; + libinput_event_pointer_get_time_usec; + libinput_event_touch_get_time_usec; } LIBINPUT_0.20.0; /* tablet APIs, they are not part of any stable API promise yet. diff --git a/src/path.c b/src/path.c index 04c703c1..b14d8b67 100644 --- a/src/path.c +++ b/src/path.c @@ -343,6 +343,11 @@ libinput_path_add_device(struct libinput *libinput, return NULL; } + if (ignore_litest_test_suite_device(udev_device)) { + udev_device_unref(udev_device); + return NULL; + } + device = path_create_device(libinput, udev_device, NULL); udev_device_unref(udev_device); return device; diff --git a/src/timer.c b/src/timer.c index 6a343dbf..5ad23f31 100644 --- a/src/timer.c +++ b/src/timer.c @@ -57,8 +57,8 @@ libinput_timer_arm_timer_fd(struct libinput *libinput) } if (earliest_expire != UINT64_MAX) { - its.it_value.tv_sec = earliest_expire / 1000; - its.it_value.tv_nsec = (earliest_expire % 1000) * 1000 * 1000; + its.it_value.tv_sec = earliest_expire / ms2us(1000); + its.it_value.tv_nsec = (earliest_expire % ms2us(1000)) * 1000; } r = timerfd_settime(libinput->timer.fd, TFD_TIMER_ABSTIME, &its, NULL); @@ -71,7 +71,10 @@ libinput_timer_set(struct libinput_timer *timer, uint64_t expire) { #ifndef NDEBUG uint64_t now = libinput_now(timer->libinput); - if (abs(expire - now) > 5000) + if (expire < now) + log_bug_libinput(timer->libinput, + "timer offset negative\n"); + else if ((expire - now) > ms2us(5000)) log_bug_libinput(timer->libinput, "timer offset more than 5s, now %" PRIu64 " expire %" PRIu64 "\n", diff --git a/src/timer.h b/src/timer.h index b005fbb8..f8315cfe 100644 --- a/src/timer.h +++ b/src/timer.h @@ -33,7 +33,7 @@ struct libinput; struct libinput_timer { struct libinput *libinput; struct list link; - uint64_t expire; /* in absolute ms CLOCK_MONOTONIC */ + uint64_t expire; /* in absolute us CLOCK_MONOTONIC */ void (*timer_func)(uint64_t now, void *timer_func_data); void *timer_func_data; }; @@ -43,7 +43,7 @@ libinput_timer_init(struct libinput_timer *timer, struct libinput *libinput, void (*timer_func)(uint64_t now, void *timer_func_data), void *timer_func_data); -/* Set timer expire time, in absolute ms CLOCK_MONOTONIC */ +/* Set timer expire time, in absolute us CLOCK_MONOTONIC */ void libinput_timer_set(struct libinput_timer *timer, uint64_t expire); diff --git a/src/udev-seat.c b/src/udev-seat.c index 6b019da2..6bf85de9 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -62,6 +62,9 @@ device_added(struct udev_device *udev_device, if (!streq(device_seat, input->seat_id)) return 0; + if (ignore_litest_test_suite_device(udev_device)) + return 0; + devnode = udev_device_get_devnode(udev_device); /* Search for matching logical seat */ diff --git a/test/Makefile.am b/test/Makefile.am index 75c61480..70a5302f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -50,8 +50,9 @@ liblitest_la_SOURCES = \ litest.c liblitest_la_LIBADD = $(top_builddir)/src/libinput-util.la liblitest_la_CFLAGS = $(AM_CFLAGS) \ - -DLIBINPUT_UDEV_RULES_FILE="\"$(abs_top_builddir)/udev/90-libinput-model-quirks-litest.rules\"" \ - -DLIBINPUT_UDEV_HWDB_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.hwdb\"" + -DLIBINPUT_MODEL_QUIRKS_UDEV_RULES_FILE="\"$(abs_top_builddir)/udev/90-libinput-model-quirks-litest.rules\"" \ + -DLIBINPUT_MODEL_QUIRKS_UDEV_HWDB_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.hwdb\"" \ + -DLIBINPUT_TEST_DEVICE_RULES_FILE="\"$(abs_top_srcdir)/udev/80-libinput-test-device.rules\"" if HAVE_LIBUNWIND liblitest_la_LIBADD += $(LIBUNWIND_LIBS) -ldl liblitest_la_CFLAGS += $(LIBUNWIND_CFLAGS) diff --git a/test/gestures.c b/test/gestures.c index b9d73257..9e447248 100644 --- a/test/gestures.c +++ b/test/gestures.c @@ -34,8 +34,12 @@ START_TEST(gestures_cap) struct litest_device *dev = litest_current_device(); struct libinput_device *device = dev->libinput_device; - ck_assert(libinput_device_has_capability(device, - LIBINPUT_DEVICE_CAP_GESTURE)); + if (litest_is_synaptics_semi_mt(dev)) + ck_assert(!libinput_device_has_capability(device, + LIBINPUT_DEVICE_CAP_GESTURE)); + else + ck_assert(libinput_device_has_capability(device, + LIBINPUT_DEVICE_CAP_GESTURE)); } END_TEST @@ -349,6 +353,41 @@ START_TEST(gestures_spread) } END_TEST +START_TEST(gestures_time_usec) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_gesture *gevent; + + if (libevdev_get_num_slots(dev->evdev) < 3) + return; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 40, 40); + litest_touch_down(dev, 1, 40, 50); + litest_touch_down(dev, 2, 40, 60); + libinput_dispatch(li); + litest_touch_move_three_touches(dev, + 40, 40, + 40, 50, + 40, 60, + 0, 30, + 4, 2); + + litest_wait_for_event(li); + + event = libinput_get_event(li); + gevent = litest_is_gesture_event(event, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + 3); + ck_assert_int_eq(libinput_event_gesture_get_time(gevent), + libinput_event_gesture_get_time_usec(gevent) / 1000); + libinput_event_destroy(event); +} +END_TEST + void litest_setup_tests(void) { @@ -361,4 +400,6 @@ litest_setup_tests(void) litest_add_ranged("gestures:swipe", gestures_swipe_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); litest_add_ranged("gestures:pinch", gestures_pinch, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); litest_add_ranged("gestures:pinch", gestures_spread, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals); + + litest_add("gesture:time", gestures_time_usec, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); } diff --git a/test/keyboard.c b/test/keyboard.c index 204d57c4..e9f3bcb1 100644 --- a/test/keyboard.c +++ b/test/keyboard.c @@ -311,6 +311,35 @@ START_TEST(keyboard_keys_bad_device) } END_TEST +START_TEST(keyboard_time_usec) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event_keyboard *kev; + struct libinput_event *event; + + if (!libevdev_has_event_code(dev->evdev, EV_KEY, KEY_A)) + return; + + litest_drain_events(dev->libinput); + + litest_keyboard_key(dev, KEY_A, true); + + litest_wait_for_event(li); + + event = libinput_get_event(li); + kev = litest_is_keyboard_event(event, + KEY_A, + LIBINPUT_KEY_STATE_PRESSED); + + ck_assert_int_eq(libinput_event_keyboard_get_time(kev), + libinput_event_keyboard_get_time_usec(kev) / 1000); + + libinput_event_destroy(event); + litest_drain_events(dev->libinput); +} +END_TEST + void litest_setup_tests(void) { @@ -319,4 +348,5 @@ litest_setup_tests(void) litest_add_no_device("keyboard:key counting", keyboard_key_auto_release); litest_add("keyboard:keys", keyboard_has_key, LITEST_KEYS, LITEST_ANY); litest_add("keyboard:keys", keyboard_keys_bad_device, LITEST_ANY, LITEST_ANY); + litest_add("keyboard:time", keyboard_time_usec, LITEST_KEYS, LITEST_ANY); } diff --git a/test/litest-device-synaptics-hover.c b/test/litest-device-synaptics-hover.c index 2cc9b725..3c36affa 100644 --- a/test/litest-device-synaptics-hover.c +++ b/test/litest-device-synaptics-hover.c @@ -102,6 +102,15 @@ static struct input_absinfo absinfo[] = { { .value = -1 } }; +static const char udev_rule[] = +"ACTION==\"remove\", GOTO=\"synaptics_semi_mt_end\"\n" +"KERNEL!=\"event*\", GOTO=\"synaptics_semi_mt_end\"\n" +"\n" +"ATTRS{name}==\"SynPS/2 Synaptics TouchPad\",\n" +" ENV{LIBINPUT_MODEL_JUMPING_SEMI_MT}=\"1\"\n" +"\n" +"LABEL=\"synaptics_semi_mt_end\""; + struct litest_test_device litest_synaptics_hover_device = { .type = LITEST_SYNAPTICS_HOVER_SEMI_MT, .features = LITEST_TOUCHPAD | LITEST_SEMI_MT | LITEST_BUTTON, @@ -114,6 +123,7 @@ struct litest_test_device litest_synaptics_hover_device = { .id = &input_id, .events = events, .absinfo = absinfo, + .udev_rule = udev_rule, }; static void diff --git a/test/litest.c b/test/litest.c index 0e434c8c..6b361f3d 100644 --- a/test/litest.c +++ b/test/litest.c @@ -53,8 +53,12 @@ #define UDEV_RULES_D "/run/udev/rules.d" #define UDEV_RULE_PREFIX "99-litest-" #define UDEV_HWDB_D "/etc/udev/hwdb.d" -#define UDEV_COMMON_RULE_FILE UDEV_RULES_D "/91-litest-model-quirks-REMOVEME.rules" -#define UDEV_COMMON_HWDB_FILE UDEV_HWDB_D "/91-litest-model-quirks-REMOVEME.hwdb" +#define UDEV_MODEL_QUIRKS_RULE_FILE UDEV_RULES_D \ + "/91-litest-model-quirks-REMOVEME.rules" +#define UDEV_MODEL_QUIRKS_HWDB_FILE UDEV_HWDB_D \ + "/91-litest-model-quirks-REMOVEME.hwdb" +#define UDEV_TEST_DEVICE_RULE_FILE UDEV_RULES_D \ + "/91-litest-test-device-REMOVEME.rules" static int in_debugger = -1; static int verbose = 0; @@ -783,6 +787,10 @@ litest_log_handler(struct libinput *libinput, fprintf(stderr, "litest %s: ", priority); vfprintf(stderr, format, args); + + if (strstr(format, "client bug: ") || + strstr(format, "libinput bug: ")) + litest_abort_msg("libinput bug triggered, aborting.\n"); } static int @@ -957,19 +965,23 @@ litest_install_model_quirks(void) "# running, remove this file and update your hwdb: \n" "# sudo udevadm hwdb --update\n" "#################################################################\n\n"; - litest_copy_file(UDEV_COMMON_RULE_FILE, - LIBINPUT_UDEV_RULES_FILE, + litest_copy_file(UDEV_MODEL_QUIRKS_RULE_FILE, + LIBINPUT_MODEL_QUIRKS_UDEV_RULES_FILE, warning); - litest_copy_file(UDEV_COMMON_HWDB_FILE, - LIBINPUT_UDEV_HWDB_FILE, + litest_copy_file(UDEV_MODEL_QUIRKS_HWDB_FILE, + LIBINPUT_MODEL_QUIRKS_UDEV_HWDB_FILE, + warning); + litest_copy_file(UDEV_TEST_DEVICE_RULE_FILE, + LIBINPUT_TEST_DEVICE_RULES_FILE, warning); } static inline void litest_remove_model_quirks(void) { - unlink(UDEV_COMMON_RULE_FILE); - unlink(UDEV_COMMON_HWDB_FILE); + unlink(UDEV_MODEL_QUIRKS_RULE_FILE); + unlink(UDEV_MODEL_QUIRKS_HWDB_FILE); + unlink(UDEV_TEST_DEVICE_RULE_FILE); } static void @@ -1059,6 +1071,7 @@ litest_create(enum litest_device_type which, litest_abort_msg("Custom create cannot be overridden"); } + d->udev_rule_file = udev_file; return d; } @@ -2336,9 +2349,9 @@ litest_assert_scroll(struct libinput *li, } } else { /* Last scroll event, must be 0 */ - litest_assert_int_eq( + ck_assert_double_eq( libinput_event_pointer_get_axis_value(ptrev, axis), - 0); + 0.0); } libinput_event_destroy(event); event = next_event; @@ -2662,6 +2675,7 @@ main(int argc, char **argv) list_init(&all_tests); setenv("CK_DEFAULT_TIMEOUT", "10", 0); + setenv("LIBINPUT_RUNNING_TEST_SUITE", "1", 1); mode = litest_parse_argv(argc, argv); if (mode == LITEST_MODE_ERROR) diff --git a/test/litest.h b/test/litest.h index 3716753d..bf165f07 100644 --- a/test/litest.h +++ b/test/litest.h @@ -509,6 +509,99 @@ litest_disable_tap(struct libinput_device *device) litest_assert_int_eq(status, expected); } +static inline bool +litest_has_2fg_scroll(struct litest_device *dev) +{ + struct libinput_device *device = dev->libinput_device; + + return !!(libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_2FG); +} + +static inline void +litest_enable_2fg_scroll(struct litest_device *dev) +{ + enum libinput_config_status status, expected; + struct libinput_device *device = dev->libinput_device; + + status = libinput_device_config_scroll_set_method(device, + LIBINPUT_CONFIG_SCROLL_2FG); + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + litest_assert_int_eq(status, expected); +} + +static inline void +litest_enable_edge_scroll(struct litest_device *dev) +{ + enum libinput_config_status status, expected; + struct libinput_device *device = dev->libinput_device; + + status = libinput_device_config_scroll_set_method(device, + LIBINPUT_CONFIG_SCROLL_EDGE); + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + litest_assert_int_eq(status, expected); +} + +static inline void +litest_enable_clickfinger(struct litest_device *dev) +{ + enum libinput_config_status status, expected; + struct libinput_device *device = dev->libinput_device; + + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + litest_assert_int_eq(status, expected); +} + +static inline void +litest_enable_buttonareas(struct litest_device *dev) +{ + enum libinput_config_status status, expected; + struct libinput_device *device = dev->libinput_device; + + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + litest_assert_int_eq(status, expected); +} + +static inline int +litest_is_synaptics_semi_mt(struct litest_device *dev) +{ + struct libevdev *evdev = dev->evdev; + + return libevdev_has_property(evdev, INPUT_PROP_SEMI_MT) && + libevdev_get_id_vendor(evdev) == 0x2 && + libevdev_get_id_product(evdev) == 0x7; +} + +static inline void +litest_enable_drag_lock(struct libinput_device *device) +{ + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_tap_set_drag_lock_enabled(device, + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); + + litest_assert_int_eq(status, expected); +} + +static inline void +litest_disable_drag_lock(struct libinput_device *device) +{ + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_tap_set_drag_lock_enabled(device, + LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); + + litest_assert_int_eq(status, expected); +} + #define CK_DOUBLE_EQ_EPSILON 1E-3 #define ck_assert_double_eq(X,Y) \ do { \ diff --git a/test/misc.c b/test/misc.c index 7ac95a76..a0c459dc 100644 --- a/test/misc.c +++ b/test/misc.c @@ -596,7 +596,7 @@ START_TEST(ratelimit_helpers) unsigned int i, j; /* 10 attempts every 100ms */ - ratelimit_init(&rl, 100, 10); + ratelimit_init(&rl, ms2us(100), 10); for (j = 0; j < 3; ++j) { /* a burst of 9 attempts must succeed */ @@ -772,6 +772,16 @@ START_TEST(dimension_prop_parser) } END_TEST +START_TEST(time_conversion) +{ + ck_assert_int_eq(us(10), 10); + ck_assert_int_eq(ns2us(10000), 10); + ck_assert_int_eq(ms2us(10), 10000); + ck_assert_int_eq(s2us(1), 1000000); + ck_assert_int_eq(us2ms(10000), 10); +} +END_TEST + void litest_setup_tests(void) { @@ -794,4 +804,5 @@ litest_setup_tests(void) litest_add_no_device("misc:parser", wheel_click_parser); litest_add_no_device("misc:parser", trackpoint_accel_parser); litest_add_no_device("misc:parser", dimension_prop_parser); + litest_add_no_device("misc:time", time_conversion); } diff --git a/test/path.c b/test/path.c index 22db7ae5..0b04b196 100644 --- a/test/path.c +++ b/test/path.c @@ -331,7 +331,9 @@ START_TEST(path_add_invalid_path) li = litest_create_context(); + litest_disable_log_handler(li); device = libinput_path_add_device(li, "/tmp/"); + litest_restore_log_handler(li); ck_assert(device == NULL); libinput_dispatch(li); diff --git a/test/pointer.c b/test/pointer.c index e971f759..50e502ad 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -897,15 +897,18 @@ START_TEST(pointer_accel_defaults) double speed; ck_assert(libinput_device_config_accel_is_available(device)); - ck_assert(libinput_device_config_accel_get_default_speed(device) == 0.0); - ck_assert(libinput_device_config_accel_get_speed(device) == 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_default_speed(device), + 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + 0.0); for (speed = -2.0; speed < -1.0; speed += 0.2) { status = libinput_device_config_accel_set_speed(device, speed); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); - ck_assert(libinput_device_config_accel_get_speed(device) == 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + 0.0); } for (speed = -1.0; speed <= 1.0; speed += 0.2) { @@ -913,7 +916,8 @@ START_TEST(pointer_accel_defaults) speed); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); - ck_assert(libinput_device_config_accel_get_speed(device) == speed); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + speed); } for (speed = 1.2; speed <= -2.0; speed += 0.2) { @@ -921,7 +925,8 @@ START_TEST(pointer_accel_defaults) speed); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); - ck_assert(libinput_device_config_accel_get_speed(device) == 1.0); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + 1.0); } } @@ -952,8 +957,10 @@ START_TEST(pointer_accel_defaults_absolute) double speed; ck_assert(!libinput_device_config_accel_is_available(device)); - ck_assert(libinput_device_config_accel_get_default_speed(device) == 0.0); - ck_assert(libinput_device_config_accel_get_speed(device) == 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_default_speed(device), + 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + 0.0); for (speed = -2.0; speed <= 2.0; speed += 0.2) { status = libinput_device_config_accel_set_speed(device, @@ -964,7 +971,8 @@ START_TEST(pointer_accel_defaults_absolute) else ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); - ck_assert(libinput_device_config_accel_get_speed(device) == 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + 0.0); } } END_TEST @@ -975,8 +983,10 @@ START_TEST(pointer_accel_defaults_absolute_relative) struct libinput_device *device = dev->libinput_device; ck_assert(libinput_device_config_accel_is_available(device)); - ck_assert(libinput_device_config_accel_get_default_speed(device) == 0.0); - ck_assert(libinput_device_config_accel_get_speed(device) == 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_default_speed(device), + 0.0); + ck_assert_double_eq(libinput_device_config_accel_get_speed(device), + 0.0); } END_TEST @@ -988,7 +998,6 @@ START_TEST(pointer_accel_direction_change) struct libinput_event_pointer *pev; int i; double delta; - double max_accel; litest_drain_events(li); @@ -1008,16 +1017,14 @@ START_TEST(pointer_accel_direction_change) pev = libinput_event_get_pointer_event(event); delta = libinput_event_pointer_get_dx(pev); - ck_assert(delta <= 0.0); - max_accel = delta; + ck_assert_double_le(delta, 0.0); libinput_event_destroy(event); event = libinput_get_event(li); } while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE); pev = libinput_event_get_pointer_event(event); delta = libinput_event_pointer_get_dx(pev); - ck_assert(delta > 0.0); - ck_assert(delta < -max_accel); + ck_assert_double_gt(delta, 0.0); libinput_event_destroy(event); } END_TEST @@ -1412,6 +1419,32 @@ START_TEST(middlebutton_default_disabled) } END_TEST +START_TEST(pointer_time_usec) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event_pointer *ptrev; + struct libinput_event *event; + + litest_drain_events(dev->libinput); + + litest_event(dev, EV_REL, REL_X, 1); + litest_event(dev, EV_REL, REL_Y, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_wait_for_event(li); + + event = libinput_get_event(li); + ptrev = litest_is_motion_event(event); + + ck_assert_int_eq(libinput_event_pointer_get_time(ptrev), + libinput_event_pointer_get_time_usec(ptrev) / 1000); + + libinput_event_destroy(event); + litest_drain_events(dev->libinput); +} +END_TEST + void litest_setup_tests(void) { @@ -1459,4 +1492,6 @@ litest_setup_tests(void) litest_add_for_device("pointer:middlebutton", middlebutton_default_alps, LITEST_ALPS_SEMI_MT); litest_add_ranged("pointer:state", pointer_absolute_initial_state, LITEST_ABSOLUTE, LITEST_ANY, &axis_range); + + litest_add("pointer:time", pointer_time_usec, LITEST_RELATIVE, LITEST_ANY); } diff --git a/test/touch.c b/test/touch.c index b519613d..eae8007c 100644 --- a/test/touch.c +++ b/test/touch.c @@ -652,6 +652,27 @@ START_TEST(touch_initial_state) } END_TEST +START_TEST(touch_time_usec) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_touch *tev; + + litest_drain_events(dev->libinput); + + litest_touch_down(dev, 0, 10, 10); + + litest_wait_for_event(li); + + event = libinput_get_event(li); + tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_DOWN); + ck_assert_int_eq(libinput_event_touch_get_time(tev), + libinput_event_touch_get_time_usec(tev) / 1000); + libinput_event_destroy(event); +} +END_TEST + void litest_setup_tests(void) { @@ -678,4 +699,6 @@ litest_setup_tests(void) litest_add("touch:protocol a", touch_protocol_a_2fg_touch, LITEST_PROTOCOL_A, LITEST_ANY); litest_add_ranged("touch:state", touch_initial_state, LITEST_TOUCH, LITEST_PROTOCOL_A, &axes); + + litest_add("touch:time", touch_time_usec, LITEST_TOUCH, LITEST_TOUCHPAD); } diff --git a/test/touchpad-buttons.c b/test/touchpad-buttons.c index 896b34b4..064c29ef 100644 --- a/test/touchpad-buttons.c +++ b/test/touchpad-buttons.c @@ -32,30 +32,6 @@ #include "libinput-util.h" #include "litest.h" -static void -enable_clickfinger(struct litest_device *dev) -{ - enum libinput_config_status status, expected; - struct libinput_device *device = dev->libinput_device; - - status = libinput_device_config_click_set_method(device, - LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - litest_assert_int_eq(status, expected); -} - -static void -enable_buttonareas(struct litest_device *dev) -{ - enum libinput_config_status status, expected; - struct libinput_device *device = dev->libinput_device; - - status = libinput_device_config_click_set_method(device, - LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - litest_assert_int_eq(status, expected); -} - START_TEST(touchpad_click_defaults_clickfinger) { struct litest_device *dev = litest_current_device(); @@ -141,7 +117,7 @@ START_TEST(touchpad_1fg_clickfinger) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -166,7 +142,7 @@ START_TEST(touchpad_1fg_clickfinger_no_touch) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -189,7 +165,7 @@ START_TEST(touchpad_2fg_clickfinger) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -219,7 +195,7 @@ START_TEST(touchpad_3fg_clickfinger) if (libevdev_get_num_slots(dev->evdev) < 3) return; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -254,7 +230,7 @@ START_TEST(touchpad_3fg_clickfinger_btntool) !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP)) return; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -293,7 +269,7 @@ START_TEST(touchpad_4fg_clickfinger) if (libevdev_get_num_slots(dev->evdev) < 4) return; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -338,7 +314,7 @@ START_TEST(touchpad_4fg_clickfinger_btntool_2slots) !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_QUADTAP)) return; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -384,7 +360,7 @@ START_TEST(touchpad_4fg_clickfinger_btntool_3slots) !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP)) return; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -435,7 +411,7 @@ START_TEST(touchpad_2fg_clickfinger_distance) h < 50.0) small_touchpad = true; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -482,6 +458,78 @@ START_TEST(touchpad_2fg_clickfinger_distance) } END_TEST +START_TEST(touchpad_3fg_clickfinger_distance) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + if (libevdev_get_num_slots(dev->evdev) < 3) + return; + + litest_enable_clickfinger(dev); + + litest_drain_events(li); + + litest_touch_down(dev, 0, 90, 90); + litest_touch_down(dev, 1, 10, 15); + litest_touch_down(dev, 2, 10, 15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + litest_touch_up(dev, 2); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); +} +END_TEST + +START_TEST(touchpad_3fg_clickfinger_distance_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + if (libevdev_get_num_slots(dev->evdev) > 2) + return; + + litest_enable_clickfinger(dev); + + litest_drain_events(li); + + litest_touch_down(dev, 0, 90, 90); + litest_touch_down(dev, 1, 10, 15); + libinput_dispatch(li); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); +} +END_TEST + START_TEST(touchpad_2fg_clickfinger_bottom) { struct litest_device *dev = litest_current_device(); @@ -556,7 +604,7 @@ START_TEST(touchpad_clickfinger_to_area_method) litest_drain_events(li); - enable_buttonareas(dev); + litest_enable_buttonareas(dev); litest_touch_down(dev, 0, 95, 95); litest_event(dev, EV_KEY, BTN_LEFT, 1); @@ -571,7 +619,7 @@ START_TEST(touchpad_clickfinger_to_area_method) litest_assert_button_event(li, BTN_RIGHT, LIBINPUT_BUTTON_STATE_RELEASED); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -599,7 +647,7 @@ START_TEST(touchpad_clickfinger_to_area_method_while_down) litest_drain_events(li); - enable_buttonareas(dev); + litest_enable_buttonareas(dev); litest_touch_down(dev, 0, 95, 95); litest_event(dev, EV_KEY, BTN_LEFT, 1); @@ -608,7 +656,7 @@ START_TEST(touchpad_clickfinger_to_area_method_while_down) litest_assert_button_event(li, BTN_RIGHT, LIBINPUT_BUTTON_STATE_PRESSED); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_event(dev, EV_KEY, BTN_LEFT, 0); litest_event(dev, EV_SYN, SYN_REPORT, 0); @@ -642,7 +690,7 @@ START_TEST(touchpad_area_to_clickfinger_method) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -660,7 +708,7 @@ START_TEST(touchpad_area_to_clickfinger_method) litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED); - enable_buttonareas(dev); + litest_enable_buttonareas(dev); litest_touch_down(dev, 0, 95, 95); litest_event(dev, EV_KEY, BTN_LEFT, 1); @@ -683,7 +731,7 @@ START_TEST(touchpad_area_to_clickfinger_method_while_down) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -694,7 +742,7 @@ START_TEST(touchpad_area_to_clickfinger_method_while_down) litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED); - enable_buttonareas(dev); + litest_enable_buttonareas(dev); litest_event(dev, EV_KEY, BTN_LEFT, 0); litest_event(dev, EV_SYN, SYN_REPORT, 0); @@ -725,11 +773,11 @@ START_TEST(touchpad_clickfinger_3fg_tool_position) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); - /* one in thumb area, one in normal area. spread is wide so the two - * real fingers don't count together. we expect a 2-finger click */ + /* one in thumb area, one in normal area + TRIPLETAP. spread is wide + * but any 3fg touch+click counts as middle */ litest_touch_down(dev, 0, 5, 99); litest_touch_down(dev, 1, 90, 15); litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); @@ -743,9 +791,9 @@ START_TEST(touchpad_clickfinger_3fg_tool_position) litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - litest_assert_button_event(li, BTN_RIGHT, + litest_assert_button_event(li, BTN_MIDDLE, LIBINPUT_BUTTON_STATE_PRESSED); - litest_assert_button_event(li, BTN_RIGHT, + litest_assert_button_event(li, BTN_MIDDLE, LIBINPUT_BUTTON_STATE_RELEASED); } END_TEST @@ -755,7 +803,7 @@ START_TEST(touchpad_clickfinger_4fg_tool_position) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); litest_touch_down(dev, 0, 5, 99); @@ -806,7 +854,7 @@ START_TEST(clickpad_btn_left) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_buttonareas(dev); + litest_enable_buttonareas(dev); litest_drain_events(li); @@ -1415,7 +1463,7 @@ START_TEST(clickpad_topsoftbuttons_clickfinger) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); @@ -1462,7 +1510,7 @@ START_TEST(clickpad_topsoftbuttons_clickfinger_dev_disabled) libinput_device_config_send_events_set_mode(dev->libinput_device, LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); litest_touch_down(dev, 0, 90, 5); @@ -1513,6 +1561,8 @@ litest_setup_tests(void) litest_add("touchpad:clickfinger", touchpad_4fg_clickfinger_btntool_2slots, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:clickfinger", touchpad_4fg_clickfinger_btntool_3slots, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", touchpad_3fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", touchpad_3fg_clickfinger_distance_btntool, LITEST_CLICKPAD, LITEST_ANY); litest_add_for_device("touchpad:clickfinger", touchpad_2fg_clickfinger_bottom, LITEST_SYNAPTICS_TOPBUTTONPAD); litest_add("touchpad:clickfinger", touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:clickfinger", diff --git a/test/touchpad-tap.c b/test/touchpad-tap.c index c021f1dc..62c7a5c3 100644 --- a/test/touchpad-tap.c +++ b/test/touchpad-tap.c @@ -32,30 +32,6 @@ #include "libinput-util.h" #include "litest.h" -static inline void -enable_drag_lock(struct libinput_device *device) -{ - enum libinput_config_status status, expected; - - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - status = libinput_device_config_tap_set_drag_lock_enabled(device, - LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); - - litest_assert_int_eq(status, expected); -} - -static inline void -disable_drag_lock(struct libinput_device *device) -{ - enum libinput_config_status status, expected; - - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - status = libinput_device_config_tap_set_drag_lock_enabled(device, - LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); - - litest_assert_int_eq(status, expected); -} - START_TEST(touchpad_1fg_tap) { struct litest_device *dev = litest_current_device(); @@ -265,6 +241,9 @@ START_TEST(touchpad_1fg_multitap_n_drag_2fg) int range = _i, ntaps; + if (litest_is_synaptics_semi_mt(dev)) + return; + litest_enable_tap(dev->libinput_device); litest_drain_events(li); @@ -467,7 +446,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_tap) ntaps; litest_enable_tap(dev->libinput_device); - enable_drag_lock(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -540,7 +519,7 @@ START_TEST(touchpad_1fg_multitap_n_drag_tap_click) ntaps; litest_enable_tap(dev->libinput_device); - enable_drag_lock(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -621,7 +600,7 @@ START_TEST(touchpad_1fg_tap_n_drag) struct libinput_event_pointer *ptrev __attribute__((unused)); litest_enable_tap(dev->libinput_device); - disable_drag_lock(dev->libinput_device); + litest_disable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -663,7 +642,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock) struct libinput *li = dev->libinput; litest_enable_tap(dev->libinput_device); - enable_drag_lock(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -704,7 +683,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_tap) struct libinput *li = dev->libinput; litest_enable_tap(dev->libinput_device); - enable_drag_lock(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -746,7 +725,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_tap_click) struct libinput *li = dev->libinput; litest_enable_tap(dev->libinput_device); - enable_drag_lock(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -791,7 +770,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_timeout) struct libinput *li = dev->libinput; litest_enable_tap(dev->libinput_device); - enable_drag_lock(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); litest_drain_events(li); @@ -806,6 +785,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_timeout) litest_assert_empty_queue(li); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tapndrag(); litest_assert_button_event(li, BTN_LEFT, @@ -821,7 +801,7 @@ START_TEST(touchpad_2fg_tap_n_drag) struct libinput *li = dev->libinput; litest_enable_tap(dev->libinput_device); - disable_drag_lock(dev->libinput_device); + litest_disable_drag_lock(dev->libinput_device); litest_drain_events(li); diff --git a/test/touchpad.c b/test/touchpad.c index b910d0ea..6e7ea5ff 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -32,65 +32,6 @@ #include "libinput-util.h" #include "litest.h" -static bool -has_2fg_scroll(struct litest_device *dev) -{ - struct libinput_device *device = dev->libinput_device; - - return !!(libinput_device_config_scroll_get_methods(device) & - LIBINPUT_CONFIG_SCROLL_2FG); -} - -static void -enable_2fg_scroll(struct litest_device *dev) -{ - enum libinput_config_status status, expected; - struct libinput_device *device = dev->libinput_device; - - status = libinput_device_config_scroll_set_method(device, - LIBINPUT_CONFIG_SCROLL_2FG); - - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - litest_assert_int_eq(status, expected); -} - -static void -enable_edge_scroll(struct litest_device *dev) -{ - enum libinput_config_status status, expected; - struct libinput_device *device = dev->libinput_device; - - status = libinput_device_config_scroll_set_method(device, - LIBINPUT_CONFIG_SCROLL_EDGE); - - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - litest_assert_int_eq(status, expected); -} - -static void -enable_clickfinger(struct litest_device *dev) -{ - enum libinput_config_status status, expected; - struct libinput_device *device = dev->libinput_device; - - status = libinput_device_config_click_set_method(device, - LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - litest_assert_int_eq(status, expected); -} - -static void -enable_buttonareas(struct litest_device *dev) -{ - enum libinput_config_status status, expected; - struct libinput_device *device = dev->libinput_device; - - status = libinput_device_config_click_set_method(device, - LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); - expected = LIBINPUT_CONFIG_STATUS_SUCCESS; - litest_assert_int_eq(status, expected); -} - START_TEST(touchpad_1fg_motion) { struct litest_device *dev = litest_current_device(); @@ -182,6 +123,10 @@ START_TEST(touchpad_2fg_scroll) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!litest_has_2fg_scroll(dev)) + return; + + litest_enable_2fg_scroll(dev); litest_drain_events(li); test_2fg_scroll(dev, 0.1, 40, 0); @@ -208,6 +153,9 @@ START_TEST(touchpad_2fg_scroll_slow_distance) const struct input_absinfo *y; double y_move; + if (!litest_has_2fg_scroll(dev)) + return; + /* We want to move > 5 mm. */ y = libevdev_get_abs_info(dev->evdev, ABS_Y); if (y->resolution) { @@ -217,6 +165,7 @@ START_TEST(touchpad_2fg_scroll_slow_distance) y_move = 20.0; } + litest_enable_2fg_scroll(dev); litest_drain_events(li); litest_touch_down(dev, 0, 49, 50); @@ -261,6 +210,10 @@ START_TEST(touchpad_2fg_scroll_source) struct libinput_event *event; struct libinput_event_pointer *ptrev; + if (!litest_has_2fg_scroll(dev)) + return; + + litest_enable_2fg_scroll(dev); litest_drain_events(li); test_2fg_scroll(dev, 0, 30, 0); @@ -282,6 +235,10 @@ START_TEST(touchpad_2fg_scroll_semi_mt) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!litest_has_2fg_scroll(dev)) + return; + + litest_enable_2fg_scroll(dev); litest_drain_events(li); litest_touch_down(dev, 0, 20, 20); @@ -302,6 +259,10 @@ START_TEST(touchpad_2fg_scroll_return_to_motion) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!litest_has_2fg_scroll(dev)) + return; + + litest_enable_2fg_scroll(dev); litest_drain_events(li); /* start with motion */ @@ -364,11 +325,15 @@ START_TEST(touchpad_scroll_natural_enable_config) } END_TEST -START_TEST(touchpad_scroll_natural) +START_TEST(touchpad_scroll_natural_2fg) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!litest_has_2fg_scroll(dev)) + return; + + litest_enable_2fg_scroll(dev); litest_drain_events(li); libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1); @@ -391,7 +356,7 @@ START_TEST(touchpad_edge_scroll) struct libinput *li = dev->libinput; litest_drain_events(li); - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_touch_down(dev, 0, 99, 20); litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10, 0); @@ -439,6 +404,8 @@ START_TEST(touchpad_scroll_defaults) ck_assert(method & LIBINPUT_CONFIG_SCROLL_EDGE); if (libevdev_get_num_slots(evdev) > 1) ck_assert(method & LIBINPUT_CONFIG_SCROLL_2FG); + else + ck_assert((method & LIBINPUT_CONFIG_SCROLL_2FG) == 0); if (libevdev_get_num_slots(evdev) > 1) expected = LIBINPUT_CONFIG_SCROLL_2FG; @@ -483,7 +450,7 @@ START_TEST(touchpad_edge_scroll_timeout) } litest_drain_events(li); - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_touch_down(dev, 0, 99, 20); libinput_dispatch(li); @@ -529,7 +496,7 @@ START_TEST(touchpad_edge_scroll_no_motion) struct libinput *li = dev->libinput; litest_drain_events(li); - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_touch_down(dev, 0, 99, 10); litest_touch_move_to(dev, 0, 99, 10, 99, 70, 10, 0); @@ -551,7 +518,7 @@ START_TEST(touchpad_edge_scroll_no_edge_after_motion) struct libinput *li = dev->libinput; litest_drain_events(li); - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); /* moving into the edge zone must not trigger scroll events */ litest_touch_down(dev, 0, 20, 20); @@ -573,7 +540,7 @@ START_TEST(touchpad_edge_scroll_source) struct libinput_event_pointer *ptrev; litest_drain_events(li); - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_touch_down(dev, 0, 99, 20); litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10, 0); @@ -598,7 +565,7 @@ START_TEST(touchpad_edge_scroll_no_2fg) struct libinput *li = dev->libinput; litest_drain_events(li); - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_touch_down(dev, 0, 49, 50); litest_touch_down(dev, 1, 51, 50); @@ -617,8 +584,8 @@ START_TEST(touchpad_edge_scroll_into_buttonareas) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_buttonareas(dev); - enable_edge_scroll(dev); + litest_enable_buttonareas(dev); + litest_enable_edge_scroll(dev); litest_drain_events(li); litest_touch_down(dev, 0, 99, 40); @@ -643,8 +610,8 @@ START_TEST(touchpad_edge_scroll_within_buttonareas) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_buttonareas(dev); - enable_edge_scroll(dev); + litest_enable_buttonareas(dev); + litest_enable_edge_scroll(dev); litest_drain_events(li); litest_touch_down(dev, 0, 20, 99); @@ -671,8 +638,8 @@ START_TEST(touchpad_edge_scroll_buttonareas_click_stops_scroll) struct libinput_event_pointer *ptrev; double val; - enable_buttonareas(dev); - enable_edge_scroll(dev); + litest_enable_buttonareas(dev); + litest_enable_edge_scroll(dev); litest_drain_events(li); litest_touch_down(dev, 0, 20, 95); @@ -718,8 +685,8 @@ START_TEST(touchpad_edge_scroll_clickfinger_click_stops_scroll) struct libinput_event_pointer *ptrev; double val; - enable_clickfinger(dev); - enable_edge_scroll(dev); + litest_enable_clickfinger(dev); + litest_enable_edge_scroll(dev); litest_drain_events(li); litest_touch_down(dev, 0, 20, 95); @@ -763,7 +730,7 @@ START_TEST(touchpad_edge_scroll_into_area) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_drain_events(li); /* move into area, move vertically, move back to edge */ @@ -807,10 +774,10 @@ START_TEST(touchpad_palm_detect_at_edge) struct libinput *li = dev->libinput; if (!touchpad_has_palm_detect_size(dev) || - !has_2fg_scroll(dev)) + !litest_has_2fg_scroll(dev)) return; - enable_2fg_scroll(dev); + litest_enable_2fg_scroll(dev); litest_disable_tap(dev->libinput_device); @@ -836,7 +803,7 @@ START_TEST(touchpad_no_palm_detect_at_edge_for_edge_scrolling) if (!touchpad_has_palm_detect_size(dev)) return; - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_drain_events(li); @@ -854,10 +821,10 @@ START_TEST(touchpad_palm_detect_at_bottom_corners) struct libinput *li = dev->libinput; if (!touchpad_has_palm_detect_size(dev) || - !has_2fg_scroll(dev)) + !litest_has_2fg_scroll(dev)) return; - enable_2fg_scroll(dev); + litest_enable_2fg_scroll(dev); litest_disable_tap(dev->libinput_device); @@ -883,10 +850,10 @@ START_TEST(touchpad_palm_detect_at_top_corners) struct libinput *li = dev->libinput; if (!touchpad_has_palm_detect_size(dev) || - !has_2fg_scroll(dev)) + !litest_has_2fg_scroll(dev)) return; - enable_2fg_scroll(dev); + litest_enable_2fg_scroll(dev); litest_disable_tap(dev->libinput_device); @@ -912,10 +879,10 @@ START_TEST(touchpad_palm_detect_palm_stays_palm) struct libinput *li = dev->libinput; if (!touchpad_has_palm_detect_size(dev) || - !has_2fg_scroll(dev)) + !litest_has_2fg_scroll(dev)) return; - enable_2fg_scroll(dev); + litest_enable_2fg_scroll(dev); litest_disable_tap(dev->libinput_device); @@ -934,10 +901,10 @@ START_TEST(touchpad_palm_detect_palm_becomes_pointer) struct libinput *li = dev->libinput; if (!touchpad_has_palm_detect_size(dev) || - !has_2fg_scroll(dev)) + !litest_has_2fg_scroll(dev)) return; - enable_2fg_scroll(dev); + litest_enable_2fg_scroll(dev); litest_disable_tap(dev->libinput_device); @@ -2176,6 +2143,8 @@ START_TEST(touchpad_initial_state) litest_touch_down(dev, 0, x, y); litest_touch_move_to(dev, 0, x, y, 80, 80, 10, 1); litest_touch_up(dev, 0); + libinput_dispatch(libinput1); + libinput_dispatch(libinput2); litest_wait_for_event(libinput1); litest_wait_for_event(libinput2); @@ -2532,7 +2501,7 @@ START_TEST(touchpad_dwt_edge_scroll) if (!has_disable_while_typing(touchpad)) return; - enable_edge_scroll(touchpad); + litest_enable_edge_scroll(touchpad); keyboard = litest_add_device(li, LITEST_KEYBOARD); litest_drain_events(li); @@ -2579,7 +2548,7 @@ START_TEST(touchpad_dwt_edge_scroll_interrupt) if (!has_disable_while_typing(touchpad)) return; - enable_edge_scroll(touchpad); + litest_enable_edge_scroll(touchpad); keyboard = litest_add_device(li, LITEST_KEYBOARD); litest_drain_events(li); @@ -2938,7 +2907,7 @@ START_TEST(touchpad_thumb_update_no_motion) }; litest_disable_tap(dev->libinput_device); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); if (!has_thumb_detect(dev)) return; @@ -2964,7 +2933,7 @@ START_TEST(touchpad_thumb_moving) }; litest_disable_tap(dev->libinput_device); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); if (!has_thumb_detect(dev)) return; @@ -3088,7 +3057,7 @@ START_TEST(touchpad_thumb_edgescroll) if (!has_thumb_detect(dev)) return; - enable_edge_scroll(dev); + litest_enable_edge_scroll(dev); litest_disable_tap(dev->libinput_device); litest_drain_events(li); @@ -3120,12 +3089,13 @@ START_TEST(touchpad_thumb_tap_begin) return; litest_enable_tap(dev->libinput_device); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); /* touch down is a thumb */ litest_touch_down_extended(dev, 0, 50, 99, axes); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_empty_queue(li); @@ -3133,6 +3103,7 @@ START_TEST(touchpad_thumb_tap_begin) /* make sure normal tap still works */ litest_touch_down(dev, 0, 50, 99); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); } @@ -3151,19 +3122,21 @@ START_TEST(touchpad_thumb_tap_touch) return; litest_enable_tap(dev->libinput_device); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); /* event after touch down is thumb */ litest_touch_down(dev, 0, 50, 50); litest_touch_move_extended(dev, 0, 51, 99, axes); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_empty_queue(li); /* make sure normal tap still works */ litest_touch_down(dev, 0, 50, 99); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); } @@ -3182,11 +3155,12 @@ START_TEST(touchpad_thumb_tap_hold) return; litest_enable_tap(dev->libinput_device); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); /* event in state HOLD is thumb */ litest_touch_down(dev, 0, 50, 99); + libinput_dispatch(li); litest_timeout_tap(); libinput_dispatch(li); litest_touch_move_extended(dev, 0, 51, 99, axes); @@ -3196,6 +3170,7 @@ START_TEST(touchpad_thumb_tap_hold) /* make sure normal tap still works */ litest_touch_down(dev, 0, 50, 99); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); } @@ -3214,11 +3189,12 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg) return; litest_enable_tap(dev->libinput_device); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); litest_drain_events(li); /* event in state HOLD is thumb */ litest_touch_down(dev, 0, 50, 99); + libinput_dispatch(li); litest_timeout_tap(); libinput_dispatch(li); litest_touch_move_extended(dev, 0, 51, 99, axes); @@ -3234,6 +3210,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg) litest_assert_empty_queue(li); /* timeout -> into HOLD, no event on release */ + libinput_dispatch(li); litest_timeout_tap(); libinput_dispatch(li); litest_touch_up(dev, 1); @@ -3242,6 +3219,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg) /* make sure normal tap still works */ litest_touch_down(dev, 0, 50, 99); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); } @@ -3266,6 +3244,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap) /* event in state HOLD is thumb */ litest_touch_down(dev, 0, 50, 99); + libinput_dispatch(li); litest_timeout_tap(); libinput_dispatch(li); litest_touch_move_extended(dev, 0, 51, 99, axes); @@ -3289,6 +3268,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap) LIBINPUT_BUTTON_STATE_PRESSED); libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev)); + libinput_dispatch(li); litest_timeout_tap(); libinput_dispatch(li); event = libinput_get_event(li); @@ -3300,6 +3280,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap) /* make sure normal tap still works */ litest_touch_down(dev, 0, 50, 99); litest_touch_up(dev, 0); + libinput_dispatch(li); litest_timeout_tap(); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); } @@ -3317,7 +3298,7 @@ START_TEST(touchpad_tool_tripletap_touch_count) * https://bugs.freedesktop.org/show_bug.cgi?id=91352 */ litest_drain_events(li); - enable_clickfinger(dev); + litest_enable_clickfinger(dev); /* touch 1 down */ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0); @@ -3419,6 +3400,40 @@ START_TEST(touchpad_tool_tripletap_touch_count) } END_TEST +START_TEST(touchpad_time_usec) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + + litest_disable_tap(dev->libinput_device); + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 80, 50, 5, 0); + litest_touch_up(dev, 0); + + libinput_dispatch(li); + + event = libinput_get_event(li); + ck_assert_notnull(event); + + while (event) { + uint64_t utime; + + ptrev = litest_is_motion_event(event); + utime = libinput_event_pointer_get_time_usec(ptrev); + + ck_assert_int_eq(libinput_event_pointer_get_time(ptrev), + utime / 1000); + libinput_event_destroy(event); + event = libinput_get_event(li); + } +} +END_TEST + void litest_setup_tests(void) { @@ -3434,7 +3449,7 @@ litest_setup_tests(void) litest_add("touchpad:scroll", touchpad_2fg_scroll_semi_mt, LITEST_SEMI_MT, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:scroll", touchpad_scroll_natural, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:scroll", touchpad_scroll_natural_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_scroll_defaults, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD, LITEST_ANY); @@ -3523,4 +3538,6 @@ litest_setup_tests(void) litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH); litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD); + + litest_add("touchpad:time", touchpad_time_usec, LITEST_TOUCHPAD, LITEST_ANY); } diff --git a/tools/ptraccel-debug.c b/tools/ptraccel-debug.c index b2dd1f90..1496763b 100644 --- a/tools/ptraccel-debug.c +++ b/tools/ptraccel-debug.c @@ -26,12 +26,14 @@ #include #include #include -#include #include #include #include #include +#include +#include + static void print_ptraccel_deltas(struct motion_filter *filter, double step) { @@ -50,7 +52,7 @@ print_ptraccel_deltas(struct motion_filter *filter, double step) for (i = 0.0; i < 15.0; i += step) { motion.x = i; motion.y = 0; - time += 12; /* pretend 80Hz data */ + time += us(12500); /* pretend 80Hz data */ motion = filter_dispatch(filter, &motion, NULL, time); @@ -93,7 +95,7 @@ print_ptraccel_movement(struct motion_filter *filter, for (i = 0; i < nevents; i++) { motion.x = dx; motion.y = 0; - time += 12; /* pretend 80Hz data */ + time += us(12500); /* pretend 80Hz data */ motion = filter_dispatch(filter, &motion, NULL, time); @@ -127,7 +129,7 @@ print_ptraccel_sequence(struct motion_filter *filter, for (i = 0; i < nevents; i++, dx++) { motion.x = *dx; motion.y = 0; - time += 12; /* pretend 80Hz data */ + time += us(12500); /* pretend 80Hz data */ motion = filter_dispatch(filter, &motion, NULL, time); diff --git a/udev/.gitignore b/udev/.gitignore index 2fdaedcf..cad377a8 100644 --- a/udev/.gitignore +++ b/udev/.gitignore @@ -1,3 +1,6 @@ libinput-device-group libinput-model-quirks -*.rules +80-libinput-device-groups-litest.rules +80-libinput-device-groups.rules +90-libinput-model-quirks-litest.rules +90-libinput-model-quirks.rules diff --git a/udev/80-libinput-test-device.rules b/udev/80-libinput-test-device.rules new file mode 100644 index 00000000..d37b2abe --- /dev/null +++ b/udev/80-libinput-test-device.rules @@ -0,0 +1 @@ +KERNELS=="*input*", ATTRS{name}=="litest *", ENV{LIBINPUT_TEST_DEVICE}="1" diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb index a34b8f17..cf4fbfaa 100644 --- a/udev/90-libinput-model-quirks.hwdb +++ b/udev/90-libinput-model-quirks.hwdb @@ -39,6 +39,7 @@ libinput:touchpad:input:b0005v05ACp* ########################################## libinput:name:*ETPS/2 Elantech Touchpad*:dmi:* LIBINPUT_ATTR_RESOLUTION_HINT=31x31 + LIBINPUT_MODEL_ELANTECH_TOUCHPAD=1 ########################################## # Google diff --git a/udev/Makefile.am b/udev/Makefile.am index 975f5370..cfb854e1 100644 --- a/udev/Makefile.am +++ b/udev/Makefile.am @@ -33,3 +33,4 @@ CLEANFILES = $(litest_rules) DISTCLEANFILES = \ 80-libinput-device-groups.rules \ 90-libinput-model-quirks.rules +EXTRA_DIST = 80-libinput-test-device.rules diff --git a/udev/libinput-model-quirks.c b/udev/libinput-model-quirks.c index fc3dbe85..0e737a4b 100644 --- a/udev/libinput-model-quirks.c +++ b/udev/libinput-model-quirks.c @@ -68,6 +68,30 @@ handle_touchpad_alps(struct udev_device *device) printf("LIBINPUT_MODEL_FIRMWARE_VERSION=%d\n", pid); } +static void +handle_touchpad_synaptics(struct udev_device *device) +{ + const char *product, *props; + int bus, vid, pid, version; + int prop; + + product = prop_value(device, "PRODUCT"); + if (!product) + return; + + if (sscanf(product, "%x/%x/%x/%x", &bus, &vid, &pid, &version) != 4) + return; + + if (bus != BUS_I8042 || vid != 0x2 || pid != 0x7) + return; + + props = prop_value(device, "PROP"); + if (sscanf(props, "%x", &prop) != 1) + return; + if (prop & (1 << INPUT_PROP_SEMI_MT)) + printf("LIBINPUT_MODEL_JUMPING_SEMI_MT=1\n"); +} + static void handle_touchpad(struct udev_device *device) { @@ -79,6 +103,8 @@ handle_touchpad(struct udev_device *device) if (strstr(name, "AlpsPS/2 ALPS") != NULL) handle_touchpad_alps(device); + if (strstr(name, "Synaptics ") != NULL) + handle_touchpad_synaptics(device); } int main(int argc, char **argv)