diff -Nru libinput-1.19.3/debian/changelog libinput-1.20.0/debian/changelog --- libinput-1.19.3/debian/changelog 2022-02-07 07:58:05.000000000 +0000 +++ libinput-1.20.0/debian/changelog 2022-02-22 13:24:35.000000000 +0000 @@ -1,3 +1,11 @@ +libinput (1.20.0-1) unstable; urgency=medium + + * New upstream release. + * watch: Updated to use gitlab tags, though signing checks had to be + disabled. + + -- Timo Aaltonen Tue, 22 Feb 2022 15:24:35 +0200 + libinput (1.19.3-2) unstable; urgency=medium * Rebuild against new libwacom. diff -Nru libinput-1.19.3/debian/watch libinput-1.20.0/debian/watch --- libinput-1.19.3/debian/watch 2022-01-14 11:23:22.000000000 +0000 +++ libinput-1.20.0/debian/watch 2022-02-22 13:21:04.000000000 +0000 @@ -1,4 +1,4 @@ #git=https://gitlab.freedesktop.org/libinput/libinput.git -version=3 -opts=pgpsigurlmangle=s/$/.sig/,dversionmangle=s/\+dfsg\d*$// \ -http://www.freedesktop.org/software/libinput/libinput-(.*)\.tar\.xz +version=4 +opts=dversionmangle=s/\+dfsg\d*$// \ +https://gitlab.freedesktop.org/libinput/libinput/tags?sort=updated_desc archive/@ANY_VERSION@/libinput-\d\S*.gz diff -Nru libinput-1.19.3/doc/touchpad-gestures-state-machine.svg libinput-1.20.0/doc/touchpad-gestures-state-machine.svg --- libinput-1.19.3/doc/touchpad-gestures-state-machine.svg 2021-12-13 03:43:13.871429200 +0000 +++ libinput-1.20.0/doc/touchpad-gestures-state-machine.svg 2022-02-19 12:32:09.000000000 +0000 @@ -1,3 +1,4 @@ + -
NONE
NONE
FINGER_DETECTED
FINGER_DETECTED
yes
yes
no
no
Gestures enabled?
Gestures enab...
UNKNOWN
UNKNOWN
  Start hold timer
  Start hold timer
Motion detected?
Motion detect...
yes
yes
no
no
Hold timeout
Hold timeout
HOLD_TIMEOUT
HOLD_TIMEOUT
HOLD
HOLD
HOLD_BEGIN
HOLD_BEGIN
yes
yes
no
no
Motion detected?
Motion detect...
HOLD_END
(CANCEL)
HOLD_END...
all
all
some (debounce)
some (debounce)
Finger up?
Finger up?
HOLD_END
HOLD_END
Number of fingers?
Number of fin...
2 fingers
2 fingers
3 or 4 fingers
3 or 4 fingers
1 finger
1 finger
(to NONE)
(to NONE)
5 or more
fingers
5 or more...
POINTER_MOTION
POINTER_MOTION
SCROLL
SCROLL
SWIPE
SWIPE
PINCH
PINCH
swipe
swipe
pinch
pinch
Gesture
type?
Gesture...
SWIPE
SWIPE
PINCH
PINCH
SWIPE_BEGIN
SWIPE_BEGIN
PINCH_BEGIN
PINCH_BEGIN
yes
yes
no
no
Motion
> hold threshold?
Motion...
no
no
yes
yes
1 finger?
1 finger?
Hold timeout
Hold timeout
yes
yes
no
no
Motion
< hold threshold?
Motion...
HOLD_AND_MOTION
HOLD_AND_MOTION
HOLD_BEGIN
HOLD_BEGIN
HOLD_TIMEOUT
HOLD_TIMEOUT
yes
yes
no
no
Gestures enabled?
Gestures enab...
SCROLL
SCROLL
POINTER_MOTION
POINTER_MOTION
yes
yes
no (to NONE)
no (to NONE)
Gestures enabled?
Gestures enab...
yes
yes
Finger up?
Finger up?
Finger count changed?
Finger count...
DEBOUNCE FINGER LOGIC
Start debounce timer
Start debounce timer
Debounce timeout
Debounce timeout
yes
yes
no
no
Number of fingers changed?
Number of fin...
CANCEL CURRENT GESTURE
CANCEL CURRENT GESTURE
Ignore this finger change and stay in the same state
Ignore this finger c...
(to NONE)
(to NONE)
all
all
some
some
no
no
Finger up?
Finger up?
(to NONE)
(to NONE)
SWIPE_END
SWIPE_END
some
some
all
all
no
no
Finger up?
Finger up?
(to NONE)
(to NONE)
PINCH_END
PINCH_END
yes (to NONE)
yes (to NONE)
no
no
Finger up?
Finger up?
SWIPE_UPDATE
SWIPE_UPDATE
PINCH_UPDATE
PINCH_UPDATE
POINTER_MOTION
POINTER_MOTION
no
no
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)
(to NONE)
(to NONE)
all
all
some (debounce)
some (debounce)
Finger up?
Finger up?
AXIS
AXIS
AXIS (0,0)
AXIS (0,0)
RESET
RESET
RESET
RESET
LEGEND
STATE
STATE
EVENT
EVENT
Conditional
Conditional
Time event
Time event
GESTURE
GESTURE
Condition
Condition
Hold
Hold
Hold and motion
Hold and motion
Pinch
Pinch
Swipe
Swipe
Pointer motion
Pointer motion
Scroll
Scroll
Viewer does not support full SVG 1.1
\ No newline at end of file +
NONE
NONE
FINGER_DETECTED
FINGER_DETECTED
yes
yes
no
no
Gestures enabled?
Gestures enab...
UNKNOWN
UNKNOWN
  Start hold timer
  Start hold timer
Motion detected?
Motion detect...
yes
yes
no
no
Hold timeout
Hold timeout
HOLD_TIMEOUT
HOLD_TIMEOUT
HOLD
HOLD
HOLD_BEGIN
HOLD_BEGIN
yes
yes
no
no
Motion detected?
Motion detect...
HOLD_END
(CANCEL)
HOLD_END...
all
all
some (debounce)
some (debounce)
Finger up?
Finger up?
HOLD_END
HOLD_END
Number of fingers?
Number of fin...
2 fingers
2 fingers
3 or 4 fingers
3 or 4 fingers
1 finger
1 finger
(to NONE)
(to NONE)
5 or more
fingers
5 or more...
POINTER_MOTION
POINTER_MOTION
SCROLL
SCROLL
SWIPE
SWIPE
PINCH
PINCH
swipe
swipe
pinch
pinch
Gesture
type?
Gesture...
SWIPE
SWIPE
PINCH
PINCH
SWIPE_BEGIN
SWIPE_BEGIN
PINCH_BEGIN
PINCH_BEGIN
yes
yes
no
no
Motion
> hold threshold?
Motion...
no
no
yes
yes
1 finger?
1 finger?
Hold timeout
Hold timeout
yes
yes
no
no
Motion
< hold threshold?
Motion...
HOLD_AND_MOTION
HOLD_AND_MOTION
HOLD_BEGIN
HOLD_BEGIN
HOLD_TIMEOUT
HOLD_TIMEOUT
yes
yes
no
no
Gestures enabled?
Gestures enab...
SCROLL
SCROLL
POINTER_MOTION
POINTER_MOTION
yes
yes
no (to NONE)
no (to NONE)
Gestures enabled?
Gestures enab...
yes
yes
Finger up?
Finger up?
Finger count changed?
Finger count...
DEBOUNCE FINGER LOGIC
Start debounce timer
Start debounce timer
Debounce timeout
Debounce timeout
yes
yes
no
no
Number of fingers changed?
Number of fin...
CANCEL CURRENT GESTURE
CANCEL CURRENT GESTURE
Ignore this finger change and stay in the same state
Ignore this finger c...
(to NONE)
(to NONE)
all
all
some
some
no
no
Finger up?
Finger up?
(to NONE)
(to NONE)
SWIPE_END
SWIPE_END
some
some
all
all
no
no
Finger up?
Finger up?
(to NONE)
(to NONE)
PINCH_END
PINCH_END
yes (to NONE)
yes (to NONE)
no
no
Finger up?
Finger up?
SWIPE_UPDATE
SWIPE_UPDATE
PINCH_UPDATE
PINCH_UPDATE
POINTER_MOTION
POINTER_MOTION
no
no
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)
(to NONE)
(to NONE)
all
all
some (debounce)
some (debounce)
Finger up?
Finger up?
AXIS
AXIS
AXIS (0,0)
AXIS (0,0)
RESET
RESET
RESET
RESET
LEGEND
STATE
STATE
EVENT
EVENT
Conditional
Conditional
Time event
Time event
GESTURE
GESTURE
Condition
Condition
Hold
Hold
Hold and motion
Hold and motion
Pinch
Pinch
Swipe
Swipe
Pointer motion
Pointer motion
Scroll
Scroll
yes
yes
Was pinch?
Was pinch?

We may confuse a pinch for a scroll initially, allow to transform an ongoing scroll into a pinch

We may confuse a pinch for a s...
Text is not SVG - cannot display
\ No newline at end of file diff -Nru libinput-1.19.3/doc/user/contributing.rst libinput-1.20.0/doc/user/contributing.rst --- libinput-1.19.3/doc/user/contributing.rst 2021-12-13 03:43:13.873429300 +0000 +++ libinput-1.20.0/doc/user/contributing.rst 2022-02-19 12:32:09.000000000 +0000 @@ -157,8 +157,8 @@ - `Register an account `_ in the freedesktop.org GitLab instance. -- `Fork libinput `_ - into your username's namespace +- `Fork libinput `_ + into your username's namespace. Select public visibility. - Get libinput's main repository. git will call this repository ``origin``. :: git clone https://gitlab.freedesktop.org/libinput/libinput.git diff -Nru libinput-1.19.3/doc/user/device-configuration-via-udev.rst libinput-1.20.0/doc/user/device-configuration-via-udev.rst --- libinput-1.19.3/doc/user/device-configuration-via-udev.rst 2021-12-13 03:43:13.873429300 +0000 +++ libinput-1.20.0/doc/user/device-configuration-via-udev.rst 2022-02-19 12:32:09.000000000 +0000 @@ -68,10 +68,13 @@ Below is an example udev rule to assign "seat1" to a device from vendor -0x012a with the model ID of 0x034b. :: +``0x012a`` with the model ID of ``0x034b``. :: - ACTION=="add|change", KERNEL=="event[0-9]*", ENV{ID_VENDOR_ID}=="012a", \ - ENV{ID_MODEL_ID}=="034b", ENV{ID_SEAT}="seat1" + $ cat /etc/udev/rules.d/99-my-device-is-on-seat1.rules + ACTION=="add|change", KERNEL=="event[0-9]*", \ + ENV{ID_VENDOR_ID}=="012a", \ + ENV{ID_MODEL_ID}=="034b", \ + ENV{ID_SEAT}="seat1" @@ -96,10 +99,13 @@ Below is an example udev rule to remove an **ID_INPUT_TOUCHPAD** setting and change it into an **ID_INPUT_TABLET** setting. This rule would apply -for a device with the vendor/model ID of 012a/034b. :: +for a device with the vendor/model ID of ``012a``/``034b``. :: - ACTION=="add|change", KERNEL=="event[0-9]*", ENV{ID_VENDOR_ID}=="012a", \ - ENV{ID_MODEL_ID}=="034b", ENV{ID_INPUT_TOUCHPAD}="", ENV{ID_INPUT_TABLET}="1" + $ cat /etc/udev/rules.d/99-my-device-is-a-tablet.rules + ACTION=="add|change", KERNEL=="event[0-9]*", \ + ENV{ID_VENDOR_ID}=="012a", \ + ENV{ID_MODEL_ID}=="034b", \ + ENV{ID_INPUT_TOUCHPAD}="", ENV{ID_INPUT_TABLET}="1" @@ -128,6 +134,15 @@ ignore this property but other parts of the stack (if any) should continue treating this device normally. +Below is an example udev rule to assign **LIBINPUT_IGNORE_DEVICE** to the +device with the vendor/model ID of ``012a``/``034b``. :: + + $ cat /etc/udev/rules.d/99-ignore-my-device.rules + ACTION=="add|change", KERNEL=="event[0-9]*", \ + ENV{ID_VENDOR_ID}=="012a", \ + ENV{ID_MODEL_ID}=="034b", \ + ENV{LIBINPUT_IGNORE_DEVICE}="1" + .. _model_specific_configuration: diff -Nru libinput-1.19.3/doc/user/faqs.rst libinput-1.20.0/doc/user/faqs.rst --- libinput-1.19.3/doc/user/faqs.rst 2021-12-13 03:43:13.874429200 +0000 +++ libinput-1.20.0/doc/user/faqs.rst 2022-02-19 12:32:09.000000000 +0000 @@ -335,3 +335,27 @@ devices directly but the compositor you want to use on your desktop needs an input stack that is more complex. And right now, libinput is the only input stack that exists for this use-case. + +.. _faq_separate_contexts: + +------------------------------------------------------------------------------ +Can I write a program to make libinput do $FOO +------------------------------------------------------------------------------ + +A common question is whether it's possible to write a program that can change +libinput's behavior - specifically the libinput that is used inside the +compositor. This indicates a misunderstanding of how libinput works: +libinput is a library that converts kernel events into libinput events, much +like ``sed`` reads data in, modifies it, and provides it to stdout. + +If ``sed`` is used by a shell-script, that script has full control over how +``sed`` processes data. In this analogy, ``sed`` is libinput and the +shell script is the compositor. It is not possible to write a program +to modify the behavior of the ``sed`` instance used inside that shell script + +Writing a program that uses libinput is akin to writing a new script that +invoke ``sed``. It will not have any effect on the original ``sed`` instance. + +The only way to modify libinput's behavior is to use the configuration options +exposed by the respective compositor. Those affect the libinput context inside +the compositor and thus have an effect on the input device behavior. diff -Nru libinput-1.19.3/doc/user/reporting-bugs.rst libinput-1.20.0/doc/user/reporting-bugs.rst --- libinput-1.19.3/doc/user/reporting-bugs.rst 2021-12-13 03:43:13.875429400 +0000 +++ libinput-1.20.0/doc/user/reporting-bugs.rst 2022-02-19 12:32:09.000000000 +0000 @@ -170,8 +170,7 @@ This is the most important piece of information, do not forget it! - the vendor model number of the device (e.g. "Logitech M325") - the output from udevadm info, see :ref:`udev_info`. -- the output of ``libinput measure trackpoint-range`` -- the sensitivity of the trackpoint (adjust the event node number as needed): :: +- the sensitivity of the trackpoint if it exists (adjust the event node number as needed): :: $ cat /sys/class/input/event17/device/device/sensitivity diff -Nru libinput-1.19.3/.gitignore libinput-1.20.0/.gitignore --- libinput-1.19.3/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ libinput-1.20.0/.gitignore 2022-02-19 12:32:09.000000000 +0000 @@ -0,0 +1,12 @@ +*.swp +*~ +*.sig +*.tar.* +*.announce +*.patch +*.rej +*.trs +*.gcda +*.gcno +tags +*.gnuplot diff -Nru libinput-1.19.3/.gitlab-ci/ci.template libinput-1.20.0/.gitlab-ci/ci.template --- libinput-1.19.3/.gitlab-ci/ci.template 2021-12-13 03:43:13.868429400 +0000 +++ libinput-1.20.0/.gitlab-ci/ci.template 2022-02-19 12:32:09.000000000 +0000 @@ -36,7 +36,7 @@ # :@activity: # e.g. fedora:31@build-default -.templates_sha: &template_sha 007f3e2fe2235328e77d3cd4ce007ab41cd9ce6c +.templates_sha: &template_sha 0c312d9c7255f46e741d43bcd1930f09cd12efe7 include: {% for distro in distributions|sort(attribute="name") %} diff -Nru libinput-1.19.3/.gitlab-ci.yml libinput-1.20.0/.gitlab-ci.yml --- libinput-1.19.3/.gitlab-ci.yml 2021-12-13 03:43:13.867429300 +0000 +++ libinput-1.20.0/.gitlab-ci.yml 2022-02-19 12:32:09.000000000 +0000 @@ -34,7 +34,7 @@ # :@activity: # e.g. fedora:31@build-default -.templates_sha: &template_sha 007f3e2fe2235328e77d3cd4ce007ab41cd9ce6c +.templates_sha: &template_sha 0c312d9c7255f46e741d43bcd1930f09cd12efe7 include: # Alpine container builder template diff -Nru libinput-1.19.3/meson.build libinput-1.20.0/meson.build --- libinput-1.19.3/meson.build 2021-12-13 03:43:13.882429400 +0000 +++ libinput-1.20.0/meson.build 2022-02-19 12:32:09.000000000 +0000 @@ -1,5 +1,5 @@ project('libinput', 'c', - version : '1.19.3', + version : '1.20.0', license : 'MIT/Expat', default_options : [ 'c_std=gnu99', 'warning_level=2' ], meson_version : '>= 0.49.0') @@ -368,6 +368,7 @@ 'src/evdev-tablet-pad.c', 'src/evdev-tablet-pad.h', 'src/evdev-tablet-pad-leds.c', + 'src/evdev-wheel.c', 'src/path-seat.c', 'src/udev-seat.c', 'src/udev-seat.h', @@ -797,6 +798,7 @@ 'test/litest-device-wacom-intuos5-pad.c', 'test/litest-device-wacom-intuos5-pen.c', 'test/litest-device-wacom-isdv4-4200-pen.c', + 'test/litest-device-wacom-isdv4-524c-pen.c', 'test/litest-device-wacom-isdv4-e6-pen.c', 'test/litest-device-wacom-isdv4-e6-finger.c', 'test/litest-device-wacom-mobilestudio-pro-pad.c', @@ -833,7 +835,8 @@ def_disable_backtrace = '-DLITEST_DISABLE_BACKTRACE_LOGGING' defs_litest_selftest = [ def_no_main, - def_disable_backtrace + def_disable_backtrace, + '-Wno-unused', ] test_litest_selftest_sources = [ 'test/litest-selftest.c', diff -Nru libinput-1.19.3/quirks/30-vendor-starlabs.quirks libinput-1.20.0/quirks/30-vendor-starlabs.quirks --- libinput-1.19.3/quirks/30-vendor-starlabs.quirks 2021-12-13 03:43:13.882429400 +0000 +++ libinput-1.20.0/quirks/30-vendor-starlabs.quirks 2022-02-19 12:32:09.000000000 +0000 @@ -27,15 +27,3 @@ MatchUdevType=touchpad MatchDMIModalias=dmi:*svnStarLabs:pnLite* AttrEventCodeDisable=BTN_RIGHT - -[StarLite Mk II - coreboot firmware] -MatchName=STAR0001:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLite* -AttrEventCodeDisable=BTN_RIGHT - -[StarLite Mk II - AMI firmware] -MatchName=ALPS0001:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLite* -AttrEventCodeDisable=BTN_RIGHT diff -Nru libinput-1.19.3/quirks/30-vendor-synaptics.quirks libinput-1.20.0/quirks/30-vendor-synaptics.quirks --- libinput-1.19.3/quirks/30-vendor-synaptics.quirks 2021-12-13 03:43:13.882429400 +0000 +++ libinput-1.20.0/quirks/30-vendor-synaptics.quirks 2022-02-19 12:32:09.000000000 +0000 @@ -6,3 +6,14 @@ MatchVendor=0x0002 MatchProduct=0x0007 ModelSynapticsSerialTouchpad=1 + +# SYNA3602:00 0911:5288 touchpad, clickpad pretending it has a right button. +# Integrated into several systems, including +# Purism Librem 14v1 +# Prestigio Smartbook 141 C2 +# StarLite Mk II +# Iota IOTA2320 +[Synaptics 0911:5288 Touchpad] +MatchUdevType=touchpad +MatchName=* 0911:5288 Touchpad +AttrEventCodeDisable=BTN_RIGHT diff -Nru libinput-1.19.3/quirks/30-vendor-wacom.quirks libinput-1.20.0/quirks/30-vendor-wacom.quirks --- libinput-1.19.3/quirks/30-vendor-wacom.quirks 2021-12-13 03:43:13.882429400 +0000 +++ libinput-1.20.0/quirks/30-vendor-wacom.quirks 2022-02-19 12:32:09.000000000 +0000 @@ -13,9 +13,16 @@ MatchProduct=0x0357 AttrPalmSizeThreshold=5 -[Wacom ISDV4 Pen] +[Wacom ISDV4 4200 Pen] MatchUdevType=tablet MatchBus=usb MatchVendor=0x56A MatchProduct=0x4200 AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y; + +[Wacom ISDV4 524c Pen] +MatchUdevType=tablet +MatchBus=usb +MatchVendor=0x2D1F +MatchProduct=0x524C +AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y; diff -Nru libinput-1.19.3/quirks/50-system-asus.quirks libinput-1.20.0/quirks/50-system-asus.quirks --- libinput-1.19.3/quirks/50-system-asus.quirks 2021-12-13 03:43:13.883429300 +0000 +++ libinput-1.20.0/quirks/50-system-asus.quirks 2022-02-19 12:32:09.000000000 +0000 @@ -33,3 +33,11 @@ MatchProduct=0x19B6 MatchUdevType=keyboard AttrKeyboardIntegration=internal + +# keyboard has a different vid/pid to the touchpad +# so libinput won't pair the two together and dwt isn't active. +[Asus ROG Strix G15 2021 keyboard] +MatchVendor=0x0B05 +MatchProduct=0x1866 +MatchUdevType=keyboard +AttrKeyboardIntegration=internal diff -Nru libinput-1.19.3/quirks/50-system-hp.quirks libinput-1.20.0/quirks/50-system-hp.quirks --- libinput-1.19.3/quirks/50-system-hp.quirks 2021-12-13 03:43:13.883429300 +0000 +++ libinput-1.20.0/quirks/50-system-hp.quirks 2022-02-19 12:32:09.000000000 +0000 @@ -36,6 +36,11 @@ MatchDMIModalias=dmi:*:svnHewlett-Packard:pnHPStreamx360ConvertiblePC11:* ModelTabletModeNoSuspend=1 +[HP Spectre x360 Convertible 15-bl000] +MatchName=AT Translated Set 2 keyboard +MatchDMIModalias=dmi:*:svnHP:pnHPSpectrex360Convertible15-bl0XX:* +ModelTabletModeNoSuspend=1 + [HP ZBook Studio G3] MatchName=AlpsPS/2 ALPS GlidePoint MatchDMIModalias=dmi:*svnHP:pnHPZBookStudioG3:* diff -Nru libinput-1.19.3/quirks/50-system-lenovo.quirks libinput-1.20.0/quirks/50-system-lenovo.quirks --- libinput-1.19.3/quirks/50-system-lenovo.quirks 2021-12-13 03:43:13.883429300 +0000 +++ libinput-1.20.0/quirks/50-system-lenovo.quirks 2022-02-19 12:32:09.000000000 +0000 @@ -246,6 +246,20 @@ MatchProduct=0xC101 AttrKeyboardIntegration=internal +[Lenovo Legion Y740 Keyboard] +MatchUdevType=keyboard +MatchBus=usb +MatchVendor=0x048D +MatchProduct=0xC936 +AttrKeyboardIntegration=internal + +[Lenovo Legion Slim 7] +MatchUdevType=keyboard +MatchBus=usb +MatchVendor=0x048D +MatchProduct=0xC967 +AttrKeyboardIntegration=internal + # https://gitlab.freedesktop.org/libinput/libinput/-/issues/604 [Lenovo Yoga Slim 9 14ITL5 Pressurepad] MatchBus=i2c @@ -260,19 +274,6 @@ MatchDMIModalias=dmi:*svnLENOVO:*pvrYogaDuet713IML05:* ModelTabletModeNoSuspend=1 -# https://gitlab.freedesktop.org/libinput/libinput/-/issues/651 -[Lenovo TrackPoint Keyboard II USB] -MatchBus=usb -MatchVendor=0x17EF -MatchProduct=0x60EE -ModelLenovoTrackpointKeyboard2=1 - -[Lenovo TrackPoint Keyboard II Bluetooth] -MatchBus=bluetooth -MatchVendor=0x17EF -MatchProduct=0x60E1 -ModelLenovoTrackpointKeyboard2=1 - # Modifies pressure range to avoid random jumps. # https://gitlab.freedesktop.org/libinput/libinput/-/issues/407 [Lenovo Yoga 2 Pro touchpad] diff -Nru libinput-1.19.3/quirks/50-system-prestigio.quirks libinput-1.20.0/quirks/50-system-prestigio.quirks --- libinput-1.19.3/quirks/50-system-prestigio.quirks 2021-12-13 03:43:13.883429300 +0000 +++ libinput-1.20.0/quirks/50-system-prestigio.quirks 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -# Clickpad that announces BTN_RIGHT -# https://gitlab.freedesktop.org/libinput/libinput/-/issues/674 -[Prestigio Smartbook 141 C2 Touchpad] -MatchName=SYNA3602:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnPrestigio:*pnPSB141C02* -AttrEventCodeDisable=BTN_RIGHT diff -Nru libinput-1.19.3/quirks/50-system-purism.quirks libinput-1.20.0/quirks/50-system-purism.quirks --- libinput-1.19.3/quirks/50-system-purism.quirks 2021-12-13 03:43:13.883429300 +0000 +++ libinput-1.20.0/quirks/50-system-purism.quirks 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -# Clickpad that announces BTN_RIGHT -# https://gitlab.freedesktop.org/libinput/libinput/-/issues/629 -[Librem 14v1 Touchpad] -MatchName=HTIX5288:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnPurism:*pn[Ll]ibrem*14:* -AttrEventCodeDisable=BTN_RIGHT diff -Nru libinput-1.19.3/src/evdev.c libinput-1.20.0/src/evdev.c --- libinput-1.19.3/src/evdev.c 2021-12-13 03:43:13.886429300 +0000 +++ libinput-1.20.0/src/evdev.c 2022-02-19 12:32:09.000000000 +0000 @@ -1010,6 +1010,7 @@ return r; } +LIBINPUT_UNUSED static inline void evdev_print_event(struct evdev_device *device, const struct input_event *e) @@ -1113,7 +1114,7 @@ return; tdelta = us2ms(libinput->dispatch_time - eventtime); - if (tdelta > 10) { + if (tdelta > 20) { evdev_log_bug_client_ratelimit(device, &device->delay_warning_limit, "event processing lagging behind by %dms, your system is too slow\n", @@ -1850,6 +1851,70 @@ libevdev_disable_event_code(evdev, EV_ABS, REL_Z); } +static bool +evdev_device_is_joystick_or_gamepad(struct evdev_device *device) +{ + enum evdev_device_udev_tags udev_tags; + bool has_joystick_tags; + struct libevdev *evdev = device->evdev; + unsigned int code, num_joystick_btns = 0, num_keys = 0; + + /* The EVDEV_UDEV_TAG_JOYSTICK is set when a joystick or gamepad button + * is found. However, it can not be used to identify joysticks or + * gamepads because there are keyboards that also have it. Even worse, + * many joysticks also map KEY_* and thus are tagged as keyboards. + * + * In order to be able to detect joysticks and gamepads and + * differentiate them from keyboards, apply the following rules: + * + * 1. The device is tagged as joystick but not as tablet + * 2. It has at least 2 joystick buttons + * 3. It doesn't have 10 keyboard keys */ + + udev_tags = evdev_device_get_udev_tags(device, device->udev_device); + has_joystick_tags = (udev_tags & EVDEV_UDEV_TAG_JOYSTICK) && + !(udev_tags & EVDEV_UDEV_TAG_TABLET) && + !(udev_tags & EVDEV_UDEV_TAG_TABLET_PAD); + + if (!has_joystick_tags) + return false; + + + for (code = BTN_JOYSTICK; code < BTN_DIGI; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code)) + num_joystick_btns++; + } + + for (code = BTN_TRIGGER_HAPPY; code <= BTN_TRIGGER_HAPPY40; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code)) + num_joystick_btns++; + } + + if (num_joystick_btns < 2) /* require at least 2 joystick buttons */ + return false; + + + for (code = KEY_ESC; code <= KEY_MICMUTE; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code) ) + num_keys++; + } + + for (code = KEY_OK; code <= KEY_LIGHTS_TOGGLE; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code) ) + num_keys++; + } + + for (code = KEY_ALS_TOGGLE; code < BTN_TRIGGER_HAPPY; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code) ) + num_keys++; + } + + if (num_keys >= 10) /* should not have 10 keyboard keys */ + return false; + + return true; +} + static struct evdev_dispatch * evdev_configure_device(struct evdev_device *device) { @@ -1893,9 +1958,9 @@ evdev_disable_accelerometer_axes(device); } - if (udev_tags == (EVDEV_UDEV_TAG_INPUT|EVDEV_UDEV_TAG_JOYSTICK)) { + if (evdev_device_is_joystick_or_gamepad(device)) { evdev_log_info(device, - "device is a joystick, ignoring\n"); + "device is a joystick or a gamepad, ignoring\n"); return NULL; } diff -Nru libinput-1.19.3/src/evdev-fallback.c libinput-1.20.0/src/evdev-fallback.c --- libinput-1.19.3/src/evdev-fallback.c 2021-12-13 03:43:13.884429200 +0000 +++ libinput-1.20.0/src/evdev-fallback.c 2022-02-19 12:32:09.000000000 +0000 @@ -68,18 +68,6 @@ int button, enum libinput_button_state state) { - if (button == BTN_MIDDLE) - dispatch->wheel.is_inhibited = (state == LIBINPUT_BUTTON_STATE_PRESSED); - - /* Lenovo TrackPoint Keyboard II sends its own scroll events when its - * trackpoint is moved while the middle button is pressed. - * Do not inhibit the scroll events. - * https://gitlab.freedesktop.org/libinput/libinput/-/issues/651 - */ - if (evdev_device_has_model_quirk(device, - QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2)) - dispatch->wheel.is_inhibited = false; - evdev_pointer_notify_physical_button(device, time, button, state); } @@ -102,10 +90,10 @@ LIBINPUT_SWITCH_STATE_OFF; } -static inline void -normalize_delta(struct evdev_device *device, - const struct device_coords *delta, - struct normalized_coords *normalized) +void +fallback_normalize_delta(struct evdev_device *device, + const struct device_coords *delta, + struct normalized_coords *normalized) { normalized->x = delta->x * DEFAULT_MOUSE_DPI / (double)device->dpi; normalized->y = delta->y * DEFAULT_MOUSE_DPI / (double)device->dpi; @@ -195,7 +183,7 @@ fallback_rotate_relative(dispatch, device); - normalize_delta(device, &dispatch->rel, &unaccel); + fallback_normalize_delta(device, &dispatch->rel, &unaccel); raw.x = dispatch->rel.x; raw.y = dispatch->rel.y; dispatch->rel.x = 0; @@ -224,110 +212,6 @@ } static void -fallback_flush_wheels(struct fallback_dispatch *dispatch, - struct evdev_device *device, - uint64_t time) -{ - struct normalized_coords wheel_degrees = { 0.0, 0.0 }; - struct discrete_coords discrete = { 0.0, 0.0 }; - struct wheel_v120 v120 = { 0.0, 0.0 }; - - if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) - return; - - if (!dispatch->wheel.emulate_hi_res_wheel && - !dispatch->wheel.hi_res_event_received && - (dispatch->wheel.lo_res.x != 0 || dispatch->wheel.lo_res.y != 0)) { - evdev_log_bug_kernel(device, - "device supports high-resolution scroll but only low-resolution events have been received.\n" - "See %s/incorrectly-enabled-hires.html for details\n", - HTTP_DOC_LINK); - dispatch->wheel.emulate_hi_res_wheel = true; - dispatch->wheel.hi_res.x = dispatch->wheel.lo_res.x * 120; - dispatch->wheel.hi_res.y = dispatch->wheel.lo_res.y * 120; - } - - if (dispatch->wheel.is_inhibited) { - dispatch->wheel.hi_res.x = 0; - dispatch->wheel.hi_res.y = 0; - dispatch->wheel.lo_res.x = 0; - dispatch->wheel.lo_res.y = 0; - return; - } - - if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) { - struct normalized_coords unaccel = { 0.0, 0.0 }; - - dispatch->wheel.hi_res.y *= -1; - normalize_delta(device, &dispatch->wheel.hi_res, &unaccel); - evdev_post_scroll(device, - time, - LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, - &unaccel); - dispatch->wheel.hi_res.x = 0; - dispatch->wheel.hi_res.y = 0; - - return; - } - - if (dispatch->wheel.hi_res.y != 0) { - int value = dispatch->wheel.hi_res.y; - - v120.y = -1 * value; - wheel_degrees.y = -1 * value/120.0 * device->scroll.wheel_click_angle.y; - evdev_notify_axis_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL), - &wheel_degrees, - &v120); - dispatch->wheel.hi_res.y = 0; - } - - if (dispatch->wheel.lo_res.y != 0) { - int value = dispatch->wheel.lo_res.y; - - wheel_degrees.y = -1 * value * device->scroll.wheel_click_angle.y; - discrete.y = -1 * value; - evdev_notify_axis_legacy_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL), - &wheel_degrees, - &discrete); - dispatch->wheel.lo_res.y = 0; - } - - if (dispatch->wheel.hi_res.x != 0) { - int value = dispatch->wheel.hi_res.x; - - v120.x = value; - wheel_degrees.x = value/120.0 * device->scroll.wheel_click_angle.x; - evdev_notify_axis_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL), - &wheel_degrees, - &v120); - dispatch->wheel.hi_res.x = 0; - } - - if (dispatch->wheel.lo_res.x != 0) { - int value = dispatch->wheel.lo_res.x; - - wheel_degrees.x = value * device->scroll.wheel_click_angle.x; - discrete.x = value; - evdev_notify_axis_legacy_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL), - &wheel_degrees, - &discrete); - dispatch->wheel.lo_res.x = 0; - } -} - -static void fallback_flush_absolute_motion(struct fallback_dispatch *dispatch, struct evdev_device *device, uint64_t time) @@ -895,29 +779,9 @@ dispatch->rel.y += e->value; dispatch->pending_event |= EVDEV_RELATIVE_MOTION; break; - case REL_WHEEL: - dispatch->wheel.lo_res.y += e->value; - if (dispatch->wheel.emulate_hi_res_wheel) - dispatch->wheel.hi_res.y += e->value * 120; - dispatch->pending_event |= EVDEV_WHEEL; - break; - case REL_HWHEEL: - dispatch->wheel.lo_res.x += e->value; - if (dispatch->wheel.emulate_hi_res_wheel) - dispatch->wheel.hi_res.x += e->value * 120; - dispatch->pending_event |= EVDEV_WHEEL; - break; - case REL_WHEEL_HI_RES: - dispatch->wheel.hi_res.y += e->value; - dispatch->wheel.hi_res_event_received = true; - dispatch->pending_event |= EVDEV_WHEEL; - break; - case REL_HWHEEL_HI_RES: - dispatch->wheel.hi_res.x += e->value; - dispatch->wheel.hi_res_event_received = true; - dispatch->pending_event |= EVDEV_WHEEL; - break; } + + fallback_wheel_process_relative(dispatch, device, e, time); } static inline void @@ -1079,7 +943,7 @@ if (need_touch_frame) touch_notify_frame(&device->base, time); - fallback_flush_wheels(dispatch, device, time); + fallback_wheel_handle_state(dispatch, device, time); /* Buttons and keys */ if (dispatch->pending_event & EVDEV_KEY) { @@ -1243,6 +1107,7 @@ struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); struct evdev_paired_keyboard *kbd; + libinput_timer_cancel(&dispatch->wheel.scroll_timer); libinput_timer_cancel(&dispatch->debounce.timer); libinput_timer_cancel(&dispatch->debounce.timer_short); libinput_timer_cancel(&dispatch->arbitration.arbitration_timer); @@ -1356,6 +1221,7 @@ { struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); + libinput_timer_destroy(&dispatch->wheel.scroll_timer); libinput_timer_destroy(&dispatch->arbitration.arbitration_timer); libinput_timer_destroy(&dispatch->debounce.timer); libinput_timer_destroy(&dispatch->debounce.timer_short); @@ -1827,22 +1693,7 @@ want_config); } - /* On kernel < 5.0 we need to emulate high-resolution - wheel scroll events */ - if ((libevdev_has_event_code(device->evdev, - EV_REL, - REL_WHEEL) && - !libevdev_has_event_code(device->evdev, - EV_REL, - REL_WHEEL_HI_RES)) || - (libevdev_has_event_code(device->evdev, - EV_REL, - REL_HWHEEL) && - !libevdev_has_event_code(device->evdev, - EV_REL, - REL_HWHEEL_HI_RES))) - dispatch->wheel.emulate_hi_res_wheel = true; - + fallback_init_wheel(dispatch, device); fallback_init_debounce(dispatch); fallback_init_arbitration(dispatch, device); diff -Nru libinput-1.19.3/src/evdev-fallback.h libinput-1.20.0/src/evdev-fallback.h --- libinput-1.19.3/src/evdev-fallback.h 2021-12-13 03:43:13.884429200 +0000 +++ libinput-1.20.0/src/evdev-fallback.h 2022-02-19 12:32:09.000000000 +0000 @@ -59,6 +59,20 @@ PALM_WAS_PALM, /* this touch sequence was a palm but isn't now */ }; +enum wheel_state { + WHEEL_STATE_NONE, + WHEEL_STATE_ACCUMULATING_SCROLL, + WHEEL_STATE_SCROLLING, +}; + +enum wheel_direction { + WHEEL_DIR_UNKNOW, + WHEEL_DIR_VPOS, + WHEEL_DIR_VNEG, + WHEEL_DIR_HPOS, + WHEEL_DIR_HNEG, +}; + struct mt_slot { bool dirty; enum mt_slot_state state; @@ -98,11 +112,13 @@ struct device_coords rel; struct { + enum wheel_state state; struct device_coords lo_res; struct device_coords hi_res; bool emulate_hi_res_wheel; - bool is_inhibited; bool hi_res_event_received; + struct libinput_timer scroll_timer; + enum wheel_direction dir; } wheel; struct { @@ -254,5 +270,23 @@ uint64_t time, int button, enum libinput_button_state state); +void +fallback_normalize_delta(struct evdev_device *device, + const struct device_coords *delta, + struct normalized_coords *normalized); + +void +fallback_init_wheel(struct fallback_dispatch *dispatch, + struct evdev_device *device); + +void +fallback_wheel_process_relative(struct fallback_dispatch *dispatch, + struct evdev_device *device, + struct input_event *e, uint64_t time); + +void +fallback_wheel_handle_state(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time); #endif diff -Nru libinput-1.19.3/src/evdev-middle-button.c libinput-1.20.0/src/evdev-middle-button.c --- libinput-1.19.3/src/evdev-middle-button.c 2021-12-13 03:43:13.884429200 +0000 +++ libinput-1.20.0/src/evdev-middle-button.c 2022-02-19 12:32:09.000000000 +0000 @@ -583,7 +583,7 @@ enum evdev_middlebutton_event event; bool is_press = state == LIBINPUT_BUTTON_STATE_PRESSED; int rc; - unsigned int bit = (button - BTN_LEFT); + unsigned int btnbit = (button - BTN_LEFT); uint32_t old_mask = 0; if (!device->middlebutton.enabled) @@ -612,7 +612,7 @@ } if (button < BTN_LEFT || - bit >= sizeof(device->middlebutton.button_mask) * 8) { + btnbit >= sizeof(device->middlebutton.button_mask) * 8) { evdev_log_bug_libinput(device, "Button mask too small for %s\n", libevdev_event_code_get_name(EV_KEY, @@ -624,9 +624,9 @@ old_mask = device->middlebutton.button_mask; if (is_press) - device->middlebutton.button_mask |= 1 << bit; + device->middlebutton.button_mask |= bit(btnbit); else - device->middlebutton.button_mask &= ~(1 << bit); + device->middlebutton.button_mask &= ~bit(btnbit); if (old_mask != device->middlebutton.button_mask && device->middlebutton.button_mask == 0) { diff -Nru libinput-1.19.3/src/evdev-mt-touchpad-buttons.c libinput-1.20.0/src/evdev-mt-touchpad-buttons.c --- libinput-1.19.3/src/evdev-mt-touchpad-buttons.c 2021-12-13 03:43:13.884429200 +0000 +++ libinput-1.20.0/src/evdev-mt-touchpad-buttons.c 2022-02-19 12:32:09.000000000 +0000 @@ -592,7 +592,7 @@ const struct input_event *e, uint64_t time) { - uint32_t mask = 1 << (e->code - BTN_LEFT); + uint32_t mask = bit(e->code - BTN_LEFT); /* Ignore other buttons on clickpads */ if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { @@ -923,6 +923,7 @@ { bool is_clickpad; bool has_left = libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT), + has_middle = libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE), has_right = libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT); is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD); @@ -934,19 +935,24 @@ * single physical button * - Wacom touch devices have neither left nor right buttons */ - if (is_clickpad) { - if (has_right) { - evdev_log_bug_kernel(device, - "clickpad with right button, assuming it is not a clickpad\n"); - is_clickpad = false; - } - } else if (has_left && !has_right && - (tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) == 0) { + if (!is_clickpad && has_left && !has_right && + (tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) == 0) { evdev_log_bug_kernel(device, "missing right button, assuming it is a clickpad.\n"); is_clickpad = true; } + if (has_middle || has_right) { + if (is_clickpad) + evdev_log_bug_kernel(device, + "clickpad advertising right button\n"); + } else if (has_left & + !is_clickpad && + libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) { + evdev_log_bug_kernel(device, + "non clickpad without right button?\n"); + } + return is_clickpad; } diff -Nru libinput-1.19.3/src/evdev-mt-touchpad.c libinput-1.20.0/src/evdev-mt-touchpad.c --- libinput-1.19.3/src/evdev-mt-touchpad.c 2021-12-13 03:43:13.885429400 +0000 +++ libinput-1.20.0/src/evdev-mt-touchpad.c 2022-02-19 12:32:09.000000000 +0000 @@ -39,7 +39,7 @@ #define DEFAULT_TRACKPOINT_EVENT_TIMEOUT ms2us(40) #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 ms2us(200) #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 ms2us(500) -#define FAKE_FINGER_OVERFLOW (1 << 7) +#define FAKE_FINGER_OVERFLOW bit(7) #define THUMB_IGNORE_SPEED_THRESHOLD 20 /* mm/s */ enum notify { @@ -198,7 +198,7 @@ if (dx > 0) { /* right move */ static const char r_l_r = 0x5; /* {Right, Left, Right} */ - t->hysteresis.x_motion_history |= (1 << 2); + t->hysteresis.x_motion_history |= bit(2); if (t->hysteresis.x_motion_history == r_l_r) { tp->hysteresis.enabled = true; evdev_log_debug(tp->device, @@ -303,10 +303,10 @@ if (is_press) { tp->fake_touches &= ~FAKE_FINGER_OVERFLOW; - tp->fake_touches |= 1 << shift; + tp->fake_touches |= bit(shift); } else { - tp->fake_touches &= ~(0x1 << shift); + tp->fake_touches &= ~bit(shift); } } @@ -1916,6 +1916,7 @@ tp_apply_rotation(tp->device); } +LIBINPUT_UNUSED static inline void tp_debug_touch_state(struct tp_dispatch *tp, struct evdev_device *device) diff -Nru libinput-1.19.3/src/evdev-mt-touchpad-gestures.c libinput-1.20.0/src/evdev-mt-touchpad-gestures.c --- libinput-1.19.3/src/evdev-mt-touchpad-gestures.c 2021-12-13 03:43:13.884429200 +0000 +++ libinput-1.20.0/src/evdev-mt-touchpad-gestures.c 2022-02-19 12:32:09.000000000 +0000 @@ -555,9 +555,9 @@ } static void -tp_gesture_none_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_none(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -584,9 +584,9 @@ } static void -tp_gesture_unknown_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_unknown(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -624,9 +624,9 @@ } static void -tp_gesture_hold_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_hold(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -662,9 +662,9 @@ } static void -tp_gesture_hold_and_motion_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_hold_and_motion(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -687,9 +687,9 @@ } static void -tp_gesture_pointer_motion_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_pointer_motion(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { struct tp_touch *first; struct phys_coords first_moved; @@ -725,31 +725,35 @@ } static void -tp_gesture_scroll_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_scroll(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: libinput_timer_cancel(&tp->gesture.hold_timer); tp->gesture.state = GESTURE_STATE_NONE; break; + case GESTURE_EVENT_PINCH: + tp_gesture_init_pinch(tp); + tp_gesture_cancel(tp, time); + tp->gesture.state = GESTURE_STATE_PINCH; + break; case GESTURE_EVENT_HOLD_AND_MOTION: case GESTURE_EVENT_FINGER_DETECTED: case GESTURE_EVENT_HOLD_TIMEOUT: case GESTURE_EVENT_POINTER_MOTION: case GESTURE_EVENT_SCROLL: case GESTURE_EVENT_SWIPE: - case GESTURE_EVENT_PINCH: log_gesture_bug(tp, event); break; } } static void -tp_gesture_pinch_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_pinch(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -769,9 +773,9 @@ } static void -tp_gesture_swipe_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_swipe(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -801,28 +805,28 @@ switch(tp->gesture.state) { case GESTURE_STATE_NONE: - tp_gesture_none_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_none(tp, event, time); break; case GESTURE_STATE_UNKNOWN: - tp_gesture_unknown_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_unknown(tp, event, time); break; case GESTURE_STATE_HOLD: - tp_gesture_hold_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_hold(tp, event, time); break; case GESTURE_STATE_HOLD_AND_MOTION: - tp_gesture_hold_and_motion_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_hold_and_motion(tp, event, time); break; case GESTURE_STATE_POINTER_MOTION: - tp_gesture_pointer_motion_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_pointer_motion(tp, event, time); break; case GESTURE_STATE_SCROLL: - tp_gesture_scroll_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_scroll(tp, event, time); break; case GESTURE_STATE_PINCH: - tp_gesture_pinch_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_pinch(tp, event, time); break; case GESTURE_STATE_SWIPE: - tp_gesture_swipe_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_swipe(tp, event, time); break; } @@ -1166,7 +1170,6 @@ */ if (time < (tp->gesture.initial_time + DEFAULT_GESTURE_PINCH_TIMEOUT) && tp_gesture_is_pinch(tp)) { - tp_gesture_cancel(tp, time); tp_gesture_handle_event(tp, GESTURE_EVENT_PINCH, time); return; } @@ -1283,6 +1286,9 @@ if (!thumb) return false; + if (!tp_touch_active_for_gesture(tp, thumb)) + return false; + thumb_moved = tp_gesture_mm_moved(tp, thumb); thumb_mm = hypot(thumb_moved.x, thumb_moved.y); return thumb_mm >= PINCH_DISAMBIGUATION_MOVE_THRESHOLD; diff -Nru libinput-1.19.3/src/evdev-mt-touchpad-tap.c libinput-1.20.0/src/evdev-mt-touchpad-tap.c --- libinput-1.19.3/src/evdev-mt-touchpad-tap.c 2021-12-13 03:43:13.884429200 +0000 +++ libinput-1.20.0/src/evdev-mt-touchpad-tap.c 2022-02-19 12:32:09.000000000 +0000 @@ -139,9 +139,9 @@ button = button_map[tp->tap.map][nfingers - 1]; if (state == LIBINPUT_BUTTON_STATE_PRESSED) - tp->tap.buttons_pressed |= (1 << nfingers); + tp->tap.buttons_pressed |= bit(nfingers); else - tp->tap.buttons_pressed &= ~(1 << nfingers); + tp->tap.buttons_pressed &= ~bit(nfingers); evdev_pointer_notify_button(tp->device, time, @@ -1603,7 +1603,7 @@ int i; for (i = 1; i <= 3; i++) { - if (tp->tap.buttons_pressed & (1 << i)) + if (tp->tap.buttons_pressed & bit(i)) tp_tap_notify(tp, now, i, LIBINPUT_BUTTON_STATE_RELEASED); } diff -Nru libinput-1.19.3/src/evdev-tablet.c libinput-1.20.0/src/evdev-tablet.c --- libinput-1.19.3/src/evdev-tablet.c 2021-12-13 03:43:13.885429400 +0000 +++ libinput-1.20.0/src/evdev-tablet.c 2022-02-19 12:32:09.000000000 +0000 @@ -1810,20 +1810,35 @@ if (tablet->tool_state == tablet->prev_tool_state) return false; - /* Kernel tools are supposed to be mutually exclusive, if we have - * two, we force a proximity out for the older tool and handle the - * new tool as separate proximity in event. + /* Kernel tools are supposed to be mutually exclusive, but we may have + * two bits set due to firmware/kernel bugs. + * Two cases that have been seen in the wild: + * - BTN_TOOL_PEN on proximity in, followed by + * BTN_TOOL_RUBBER later, see #259 + * -> We force a prox-out of the pen, trigger prox-in for eraser + * - BTN_TOOL_RUBBER on proximity in, but BTN_TOOL_PEN when + * the tip is down, see #702. + * -> We ignore BTN_TOOL_PEN + * In both cases the eraser is what we want, so we bias + * towards that. */ if (tablet->tool_state & (tablet->tool_state - 1)) { - /* tool_state has 2 bits set. We set the current tool state - * to zero, thus setting everything up for a prox out on the - * tool. Once that is set up, we change the tool state to be - * the new one we just got so when we re-process this - * function we now get the new tool as prox in. - * Importantly, we basically rely on nothing else happening - * in the meantime. - */ doubled_up_new_tool_bit = tablet->tool_state ^ tablet->prev_tool_state; + + /* The new tool is the pen. Ignore it */ + if (doubled_up_new_tool_bit == bit(LIBINPUT_TABLET_TOOL_TYPE_PEN)) { + tablet->tool_state &= ~bit(LIBINPUT_TABLET_TOOL_TYPE_PEN); + return false; + } + + /* The new tool is some tool other than pen (usually eraser). + * We set the current tool state to zero, thus setting + * everything up for a prox out on the tool. Once that is set + * up, we change the tool state to be the new one we just got. + * When we re-process this function we now get the new tool + * as prox in. Importantly, we basically rely on nothing else + * happening in the meantime. + */ tablet->tool_state = 0; } diff -Nru libinput-1.19.3/src/evdev-tablet-pad.c libinput-1.20.0/src/evdev-tablet-pad.c --- libinput-1.19.3/src/evdev-tablet-pad.c 2021-12-13 03:43:13.885429400 +0000 +++ libinput-1.20.0/src/evdev-tablet-pad.c 2022-02-19 12:32:09.000000000 +0000 @@ -556,15 +556,27 @@ WacomDevice *tablet = NULL; int num_buttons; int map = 0; + char event_path[64]; db = libinput_libwacom_ref(li); if (!db) goto out; - tablet = libwacom_new_from_usbid(db, - evdev_device_get_id_vendor(device), - evdev_device_get_id_product(device), - NULL); + snprintf(event_path, + sizeof(event_path), + "/dev/input/%s", + evdev_device_get_sysname(device)); + tablet = libwacom_new_from_path(db, + event_path, + WFALLBACK_NONE, + NULL); + if (!tablet) { + tablet = libwacom_new_from_usbid(db, + evdev_device_get_id_vendor(device), + evdev_device_get_id_product(device), + NULL); + } + if (!tablet) goto out; diff -Nru libinput-1.19.3/src/evdev-tablet-pad-leds.c libinput-1.20.0/src/evdev-tablet-pad-leds.c --- libinput-1.19.3/src/evdev-tablet-pad-leds.c 2021-12-13 03:43:13.885429400 +0000 +++ libinput-1.20.0/src/evdev-tablet-pad-leds.c 2022-02-19 12:32:09.000000000 +0000 @@ -412,7 +412,7 @@ return 1; } - group->button_mask |= 1 << i; + group->button_mask |= bit(i); if (flags & WACOM_BUTTON_MODESWITCH) { struct pad_mode_toggle_button *b; @@ -423,7 +423,7 @@ return 1; g = (struct pad_led_group*)group; list_insert(&g->toggle_button_list, &b->link); - group->toggle_button_mask |= 1 << i; + group->toggle_button_mask |= bit(i); } } diff -Nru libinput-1.19.3/src/evdev-wheel.c libinput-1.20.0/src/evdev-wheel.c --- libinput-1.19.3/src/evdev-wheel.c 1970-01-01 00:00:00.000000000 +0000 +++ libinput-1.20.0/src/evdev-wheel.c 2022-02-19 12:32:09.000000000 +0000 @@ -0,0 +1,430 @@ +/* + * Copyright © 2010 Intel Corporation + * Copyright © 2013 Jonas Ådahl + * Copyright © 2013-2017 Red Hat, Inc. + * Copyright © 2017 James Ye + * Copyright © 2021 José Expósito + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "evdev-fallback.h" +#include "util-input-event.h" + +#define ACC_V120_THRESHOLD 60 +#define WHEEL_SCROLL_TIMEOUT ms2us(500) + +enum wheel_event { + WHEEL_EVENT_SCROLL_ACCUMULATED, + WHEEL_EVENT_SCROLL, + WHEEL_EVENT_SCROLL_TIMEOUT, + WHEEL_EVENT_SCROLL_DIR_CHANGED, +}; + +static inline const char * +wheel_state_to_str(enum wheel_state state) +{ + switch(state) { + CASE_RETURN_STRING(WHEEL_STATE_NONE); + CASE_RETURN_STRING(WHEEL_STATE_ACCUMULATING_SCROLL); + CASE_RETURN_STRING(WHEEL_STATE_SCROLLING); + } + return NULL; +} + +static inline const char* +wheel_event_to_str(enum wheel_event event) +{ + switch(event) { + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL_ACCUMULATED); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL_TIMEOUT); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL_DIR_CHANGED); + } + return NULL; +} + +static inline void +log_wheel_bug(struct fallback_dispatch *dispatch, enum wheel_event event) +{ + evdev_log_bug_libinput(dispatch->device, + "invalid wheel event %s in state %s\n", + wheel_event_to_str(event), + wheel_state_to_str(dispatch->wheel.state)); +} + +static inline void +wheel_set_scroll_timer(struct fallback_dispatch *dispatch, uint64_t time) +{ + libinput_timer_set(&dispatch->wheel.scroll_timer, + time + WHEEL_SCROLL_TIMEOUT); +} + +static inline void +wheel_cancel_scroll_timer(struct fallback_dispatch *dispatch) +{ + libinput_timer_cancel(&dispatch->wheel.scroll_timer); +} + +static void +wheel_handle_event_on_state_none(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_SCROLL: + dispatch->wheel.state = WHEEL_STATE_ACCUMULATING_SCROLL; + break; + case WHEEL_EVENT_SCROLL_DIR_CHANGED: + break; + case WHEEL_EVENT_SCROLL_ACCUMULATED: + case WHEEL_EVENT_SCROLL_TIMEOUT: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event_on_state_accumulating_scroll(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_SCROLL_ACCUMULATED: + dispatch->wheel.state = WHEEL_STATE_SCROLLING; + wheel_set_scroll_timer(dispatch, time); + break; + case WHEEL_EVENT_SCROLL: + /* Ignore scroll while accumulating deltas */ + break; + case WHEEL_EVENT_SCROLL_DIR_CHANGED: + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL_TIMEOUT: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event_on_state_scrolling(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_SCROLL: + wheel_cancel_scroll_timer(dispatch); + wheel_set_scroll_timer(dispatch, time); + break; + case WHEEL_EVENT_SCROLL_TIMEOUT: + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL_DIR_CHANGED: + wheel_cancel_scroll_timer(dispatch); + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL_ACCUMULATED: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + enum wheel_state oldstate = dispatch->wheel.state; + + switch (oldstate) { + case WHEEL_STATE_NONE: + wheel_handle_event_on_state_none(dispatch, event, time); + break; + case WHEEL_STATE_ACCUMULATING_SCROLL: + wheel_handle_event_on_state_accumulating_scroll(dispatch, + event, + time); + break; + case WHEEL_STATE_SCROLLING: + wheel_handle_event_on_state_scrolling(dispatch, event, time); + break; + } + + if (oldstate != dispatch->wheel.state) { + evdev_log_debug(dispatch->device, + "wheel state %s → %s → %s\n", + wheel_state_to_str(oldstate), + wheel_event_to_str(event), + wheel_state_to_str(dispatch->wheel.state)); + } +} + +static void +wheel_flush_scroll(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + struct normalized_coords wheel_degrees = { 0.0, 0.0 }; + struct discrete_coords discrete = { 0.0, 0.0 }; + struct wheel_v120 v120 = { 0.0, 0.0 }; + + if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) { + struct normalized_coords unaccel = { 0.0, 0.0 }; + + dispatch->wheel.hi_res.y *= -1; + fallback_normalize_delta(device, &dispatch->wheel.hi_res, &unaccel); + evdev_post_scroll(device, + time, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, + &unaccel); + dispatch->wheel.hi_res.x = 0; + dispatch->wheel.hi_res.y = 0; + + return; + } + + if (dispatch->wheel.hi_res.y != 0) { + int value = dispatch->wheel.hi_res.y; + + v120.y = -1 * value; + wheel_degrees.y = -1 * value/120.0 * device->scroll.wheel_click_angle.y; + evdev_notify_axis_wheel( + device, + time, + bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL), + &wheel_degrees, + &v120); + dispatch->wheel.hi_res.y = 0; + } + + if (dispatch->wheel.lo_res.y != 0) { + int value = dispatch->wheel.lo_res.y; + + wheel_degrees.y = -1 * value * device->scroll.wheel_click_angle.y; + discrete.y = -1 * value; + evdev_notify_axis_legacy_wheel( + device, + time, + bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL), + &wheel_degrees, + &discrete); + dispatch->wheel.lo_res.y = 0; + } + + if (dispatch->wheel.hi_res.x != 0) { + int value = dispatch->wheel.hi_res.x; + + v120.x = value; + wheel_degrees.x = value/120.0 * device->scroll.wheel_click_angle.x; + evdev_notify_axis_wheel( + device, + time, + bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL), + &wheel_degrees, + &v120); + dispatch->wheel.hi_res.x = 0; + } + + if (dispatch->wheel.lo_res.x != 0) { + int value = dispatch->wheel.lo_res.x; + + wheel_degrees.x = value * device->scroll.wheel_click_angle.x; + discrete.x = value; + evdev_notify_axis_legacy_wheel( + device, + time, + bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL), + &wheel_degrees, + &discrete); + dispatch->wheel.lo_res.x = 0; + } +} + +static void +wheel_handle_state_none(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + +} + +static void +wheel_handle_state_accumulating_scroll(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + if (abs(dispatch->wheel.hi_res.x) >= ACC_V120_THRESHOLD || + abs(dispatch->wheel.hi_res.y) >= ACC_V120_THRESHOLD) { + wheel_handle_event(dispatch, + WHEEL_EVENT_SCROLL_ACCUMULATED, + time); + wheel_flush_scroll(dispatch, device, time); + } +} + +static void +wheel_handle_state_scrolling(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + wheel_flush_scroll(dispatch, device, time); +} + +static void +wheel_handle_direction_change(struct fallback_dispatch *dispatch, + struct input_event *e, + uint64_t time) +{ + enum wheel_direction new_dir = WHEEL_DIR_UNKNOW; + + switch (e->code) { + case REL_WHEEL_HI_RES: + new_dir = (e->value > 0) ? WHEEL_DIR_VPOS : WHEEL_DIR_VNEG; + break; + case REL_HWHEEL_HI_RES: + new_dir = (e->value > 0) ? WHEEL_DIR_HPOS : WHEEL_DIR_HNEG; + break; + } + + if (new_dir != WHEEL_DIR_UNKNOW && new_dir != dispatch->wheel.dir) { + dispatch->wheel.dir = new_dir; + wheel_handle_event(dispatch, + WHEEL_EVENT_SCROLL_DIR_CHANGED, + time); + } +} + +void +fallback_wheel_process_relative(struct fallback_dispatch *dispatch, + struct evdev_device *device, + struct input_event *e, uint64_t time) +{ + switch (e->code) { + case REL_WHEEL: + dispatch->wheel.lo_res.y += e->value; + if (dispatch->wheel.emulate_hi_res_wheel) + dispatch->wheel.hi_res.y += e->value * 120; + dispatch->pending_event |= EVDEV_WHEEL; + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); + break; + case REL_HWHEEL: + dispatch->wheel.lo_res.x += e->value; + if (dispatch->wheel.emulate_hi_res_wheel) + dispatch->wheel.hi_res.x += e->value * 120; + dispatch->pending_event |= EVDEV_WHEEL; + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); + break; + case REL_WHEEL_HI_RES: + dispatch->wheel.hi_res.y += e->value; + dispatch->wheel.hi_res_event_received = true; + dispatch->pending_event |= EVDEV_WHEEL; + wheel_handle_direction_change(dispatch, e, time); + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); + break; + case REL_HWHEEL_HI_RES: + dispatch->wheel.hi_res.x += e->value; + dispatch->wheel.hi_res_event_received = true; + dispatch->pending_event |= EVDEV_WHEEL; + wheel_handle_direction_change(dispatch, e, time); + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); + break; + } +} + +void +fallback_wheel_handle_state(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) + return; + + if (!dispatch->wheel.emulate_hi_res_wheel && + !dispatch->wheel.hi_res_event_received && + (dispatch->wheel.lo_res.x != 0 || dispatch->wheel.lo_res.y != 0)) { + evdev_log_bug_kernel(device, + "device supports high-resolution scroll but only low-resolution events have been received.\n" + "See %s/incorrectly-enabled-hires.html for details\n", + HTTP_DOC_LINK); + dispatch->wheel.emulate_hi_res_wheel = true; + dispatch->wheel.hi_res.x = dispatch->wheel.lo_res.x * 120; + dispatch->wheel.hi_res.y = dispatch->wheel.lo_res.y * 120; + } + + switch (dispatch->wheel.state) { + case WHEEL_STATE_NONE: + wheel_handle_state_none(dispatch, device, time); + break; + case WHEEL_STATE_ACCUMULATING_SCROLL: + wheel_handle_state_accumulating_scroll(dispatch, device, time); + break; + case WHEEL_STATE_SCROLLING: + wheel_handle_state_scrolling(dispatch, device, time); + break; + } +} + +static void +wheel_init_scroll_timer(uint64_t now, void *data) +{ + struct evdev_device *device = data; + struct fallback_dispatch *dispatch = + fallback_dispatch(device->dispatch); + + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL_TIMEOUT, now); +} + +void +fallback_init_wheel(struct fallback_dispatch *dispatch, + struct evdev_device *device) +{ + char timer_name[64]; + + dispatch->wheel.state = WHEEL_STATE_NONE; + dispatch->wheel.dir = WHEEL_DIR_UNKNOW; + + /* On kernel < 5.0 we need to emulate high-resolution + wheel scroll events */ + if ((libevdev_has_event_code(device->evdev, + EV_REL, + REL_WHEEL) && + !libevdev_has_event_code(device->evdev, + EV_REL, + REL_WHEEL_HI_RES)) || + (libevdev_has_event_code(device->evdev, + EV_REL, + REL_HWHEEL) && + !libevdev_has_event_code(device->evdev, + EV_REL, + REL_HWHEEL_HI_RES))) + dispatch->wheel.emulate_hi_res_wheel = true; + + snprintf(timer_name, + sizeof(timer_name), + "%s wheel scroll", + evdev_device_get_sysname(device)); + libinput_timer_init(&dispatch->wheel.scroll_timer, + evdev_libinput_context(device), + timer_name, + wheel_init_scroll_timer, + device); +} diff -Nru libinput-1.19.3/src/libinput.c libinput-1.20.0/src/libinput.c --- libinput-1.19.3/src/libinput.c 2021-12-13 03:43:13.887429200 +0000 +++ libinput-1.20.0/src/libinput.c 2022-02-19 12:32:09.000000000 +0000 @@ -3427,7 +3427,7 @@ libinput_device_tablet_pad_get_num_buttons(group->device)) return 0; - return !!(group->button_mask & (1 << button)); + return !!(group->button_mask & bit(button)); } LIBINPUT_EXPORT int @@ -3438,7 +3438,7 @@ libinput_device_tablet_pad_get_num_rings(group->device)) return 0; - return !!(group->ring_mask & (1 << ring)); + return !!(group->ring_mask & bit(ring)); } LIBINPUT_EXPORT int @@ -3449,7 +3449,7 @@ libinput_device_tablet_pad_get_num_strips(group->device)) return 0; - return !!(group->strip_mask & (1 << strip)); + return !!(group->strip_mask & bit(strip)); } LIBINPUT_EXPORT int @@ -3460,7 +3460,7 @@ libinput_device_tablet_pad_get_num_buttons(group->device)) return 0; - return !!(group->toggle_button_mask & (1 << button)); + return !!(group->toggle_button_mask & bit(button)); } LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group * diff -Nru libinput-1.19.3/src/libinput-private.h libinput-1.20.0/src/libinput-private.h --- libinput-1.19.3/src/libinput-private.h 2021-12-13 03:43:13.887429200 +0000 +++ libinput-1.20.0/src/libinput-private.h 2022-02-19 12:32:09.000000000 +0000 @@ -136,6 +136,8 @@ struct libinput_source *source; int fd; uint64_t next_expiry; + + struct ratelimit expiry_in_past_limit; } timer; struct libinput_event **events; @@ -865,7 +867,7 @@ d1 = (int)(r + 0.9) % 8; d2 = (int)(r + 0.1) % 8; - dir = (1 << d1) | (1 << d2); + dir = bit(d1) | bit(d2); } return dir; diff -Nru libinput-1.19.3/src/libinput-util.h libinput-1.20.0/src/libinput-util.h --- libinput-1.19.3/src/libinput-util.h 2021-12-13 03:43:13.887429200 +0000 +++ libinput-1.20.0/src/libinput-util.h 2022-02-19 12:32:09.000000000 +0000 @@ -65,5 +65,6 @@ } while (0) #define LIBINPUT_EXPORT __attribute__ ((visibility("default"))) +#define LIBINPUT_UNUSED __attribute__ ((unused)) #endif /* LIBINPUT_UTIL_H */ diff -Nru libinput-1.19.3/src/quirks.c libinput-1.20.0/src/quirks.c --- libinput-1.19.3/src/quirks.c 2021-12-13 03:43:13.890429300 +0000 +++ libinput-1.20.0/src/quirks.c 2022-02-19 12:32:09.000000000 +0000 @@ -254,7 +254,6 @@ case QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING: return "ModelInvertHorizontalScrolling"; case QUIRK_MODEL_LENOVO_SCROLLPOINT: return "ModelLenovoScrollPoint"; case QUIRK_MODEL_LENOVO_T450_TOUCHPAD: return "ModelLenovoT450Touchpad"; - case QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2: return "ModelLenovoTrackpointKeyboard2"; case QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD: return "ModelLenovoX1Gen6Touchpad"; case QUIRK_MODEL_LENOVO_X230: return "ModelLenovoX230"; case QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD: return "ModelSynapticsSerialTouchpad"; diff -Nru libinput-1.19.3/src/quirks.h libinput-1.20.0/src/quirks.h --- libinput-1.19.3/src/quirks.h 2021-12-13 03:43:13.890429300 +0000 +++ libinput-1.20.0/src/quirks.h 2022-02-19 12:32:09.000000000 +0000 @@ -74,7 +74,6 @@ QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING, QUIRK_MODEL_LENOVO_SCROLLPOINT, QUIRK_MODEL_LENOVO_T450_TOUCHPAD, - QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2, QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD, QUIRK_MODEL_LENOVO_X230, QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD, diff -Nru libinput-1.19.3/src/timer.c libinput-1.20.0/src/timer.c --- libinput-1.19.3/src/timer.c 2021-12-13 03:43:13.890429300 +0000 +++ libinput-1.20.0/src/timer.c 2022-02-19 12:32:09.000000000 +0000 @@ -43,6 +43,9 @@ timer->timer_name = safe_strdup(timer_name); timer->timer_func = timer_func; timer->timer_func_data = timer_func_data; + /* at most 5 "expiry in the past" log messages per hour */ + ratelimit_init(&libinput->timer.expiry_in_past_limit, + s2us(60 * 60), 5); } void @@ -89,13 +92,17 @@ uint32_t flags) { #ifndef NDEBUG + /* We only warn if we're more than 20ms behind */ + const uint64_t timer_warning_limit = ms2us(20); uint64_t now = libinput_now(timer->libinput); if (expire < now) { - if ((flags & TIMER_FLAG_ALLOW_NEGATIVE) == 0) - log_bug_client(timer->libinput, - "timer %s: scheduled expiry is in the past (-%dms), your system is too slow\n", - timer->timer_name, - us2ms(now - expire)); + if ((flags & TIMER_FLAG_ALLOW_NEGATIVE) == 0 && + now - expire > timer_warning_limit) + log_bug_client_ratelimit(timer->libinput, + &timer->libinput->timer.expiry_in_past_limit, + "timer %s: scheduled expiry is in the past (-%dms), your system is too slow\n", + timer->timer_name, + us2ms(now - expire)); } else if ((expire - now) > ms2us(5000)) { log_bug_libinput(timer->libinput, "timer %s: offset more than 5s, now %d expire %d\n", diff -Nru libinput-1.19.3/src/timer.h libinput-1.20.0/src/timer.h --- libinput-1.19.3/src/timer.h 2021-12-13 03:43:13.890429300 +0000 +++ libinput-1.20.0/src/timer.h 2022-02-19 12:32:09.000000000 +0000 @@ -54,7 +54,7 @@ enum timer_flags { TIMER_FLAG_NONE = 0, - TIMER_FLAG_ALLOW_NEGATIVE = (1 << 0), + TIMER_FLAG_ALLOW_NEGATIVE = bit(0), }; void diff -Nru libinput-1.19.3/test/litest.c libinput-1.20.0/test/litest.c --- libinput-1.19.3/test/litest.c 2021-12-13 03:43:13.896429300 +0000 +++ libinput-1.20.0/test/litest.c 2022-02-19 12:32:09.000000000 +0000 @@ -2542,6 +2542,36 @@ } void +litest_tablet_tip_down(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + /* If the test device overrides tip_down and says it didn't + * handle the event, let's continue normally */ + if (d->interface->tablet_tip_down && + d->interface->tablet_tip_down(d, x, y, axes)) + return; + + litest_event(d, EV_KEY, BTN_TOUCH, 1); + litest_tablet_motion(d, x, y, axes); +} + +void +litest_tablet_tip_up(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + /* If the test device overrides tip_down and says it didn't + * handle the event, let's continue normally */ + if (d->interface->tablet_tip_up && + d->interface->tablet_tip_up(d, x, y, axes)) + return; + + litest_event(d, EV_KEY, BTN_TOUCH, 0); + litest_tablet_motion(d, x, y, axes); +} + +void litest_touch_move_two_touches(struct litest_device *d, double x0, double y0, double x1, double y1, @@ -4300,6 +4330,12 @@ } void +litest_timeout_wheel_scroll(void) +{ + msleep(600); +} + +void litest_timeout_edgescroll(void) { msleep(300); diff -Nru libinput-1.19.3/test/litest-device-aiptek-tablet.c libinput-1.20.0/test/litest-device-aiptek-tablet.c --- libinput-1.19.3/test/litest-device-aiptek-tablet.c 2021-12-13 03:43:13.892429400 +0000 +++ libinput-1.20.0/test/litest-device-aiptek-tablet.c 2022-02-19 12:32:09.000000000 +0000 @@ -32,6 +32,7 @@ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, /* Note: this device does not send tilt, despite claiming it has it */ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_KEY, .code = LITEST_BTN_TOOL_AUTO, .value = LITEST_AUTO_ASSIGN }, { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, { .type = -1, .code = -1 }, }; diff -Nru libinput-1.19.3/test/litest-device-wacom-isdv4-524c-pen.c libinput-1.20.0/test/litest-device-wacom-isdv4-524c-pen.c --- libinput-1.19.3/test/litest-device-wacom-isdv4-524c-pen.c 1970-01-01 00:00:00.000000000 +0000 +++ libinput-1.20.0/test/litest-device-wacom-isdv4-524c-pen.c 2022-02-19 12:32:09.000000000 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright © 2019 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "litest.h" +#include "litest-int.h" + +struct priv { + unsigned int tool; +}; + +static bool +create(struct litest_device *d) +{ + d->private = zalloc(sizeof(struct priv)); + return true; /* we want litest to create our device */ +} + +static struct input_event proximity_in[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_KEY, .code = LITEST_BTN_TOOL_AUTO, .value = 1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct input_event proximity_out[] = { + { .type = EV_KEY, .code = LITEST_BTN_TOOL_AUTO, .value = 0 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct input_event motion[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + *value = 4000; + return 0; + case ABS_TILT_X: + case ABS_TILT_Y: + abort(); + } + return 1; +} + +static bool prox_in(struct litest_device *d, + unsigned int tool_type, + double x, double y, + struct axis_replacement *axes) +{ + struct priv *priv = d->private; + priv->tool = tool_type; + + return false; +} + +static bool prox_out(struct litest_device *d, unsigned int tool_type) +{ + struct priv *priv = d->private; + priv->tool = 0; + + return false; +} + +static bool +tip_down(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + litest_event(d, EV_KEY, BTN_TOOL_PEN, 1); + return false; /* use the default behavior otherwise */ +} + +static bool +tip_up(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + struct priv *priv = d->private; + if (priv->tool != BTN_TOOL_PEN) + litest_event(d, EV_KEY, BTN_TOOL_PEN, 0); + return false; /* use the default behavior otherwise */ +} + +static struct litest_device_interface interface = { + .tablet_proximity_in_events = proximity_in, + .tablet_proximity_out_events = proximity_out, + .tablet_motion_events = motion, + + .tablet_proximity_in = prox_in, + .tablet_proximity_out = prox_out, + .tablet_tip_down = tip_down, + .tablet_tip_up = tip_up, + + .get_axis_default = get_axis_default, +}; + +static struct input_absinfo absinfo[] = { + { ABS_X, 0, 30931, 0, 0, 100 }, + { ABS_Y, 0, 17399, 0, 0, 100 }, + /* This pen has tilt, but doesn't send events */ + { ABS_TILT_X, -90, 90, 0, 0, 57 }, + { ABS_TILT_Y, -90, 90, 0, 0, 57 }, + { ABS_PRESSURE, 0, 4095, 0, 0, 0 }, + { .value = -1 }, +}; + +static struct input_id input_id = { + .bustype = 0x3, + .vendor = 0x2d1f, /* Note: this is Wacom's Android VID */ + .product = 0x524c, +}; + +static int events[] = { + EV_KEY, BTN_TOOL_PEN, + EV_KEY, BTN_TOOL_RUBBER, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_STYLUS, + EV_KEY, BTN_STYLUS2, + INPUT_PROP_MAX, INPUT_PROP_DIRECT, + -1, -1, +}; + +TEST_DEVICE("wacom-isdv4-524c-tablet", + .type = LITEST_WACOM_ISDV4_524C_PEN, + .features = LITEST_TABLET|LITEST_HOVER, + .interface = &interface, + + .name = "Wacom Co.,Ltd. Pen and multitouch sensor Stylus", + .id = &input_id, + .events = events, + .absinfo = absinfo, + .create = create, +) diff -Nru libinput-1.19.3/test/litest.h libinput-1.20.0/test/litest.h --- libinput-1.19.3/test/litest.h 2021-12-13 03:43:13.896429300 +0000 +++ libinput-1.20.0/test/litest.h 2022-02-19 12:32:09.000000000 +0000 @@ -320,6 +320,7 @@ LITEST_KEYBOARD_QUIRKED, LITEST_SYNAPTICS_PRESSUREPAD, LITEST_GENERIC_PRESSUREPAD, + LITEST_WACOM_ISDV4_524C_PEN, }; #define LITEST_DEVICELESS -2 @@ -630,6 +631,16 @@ litest_tablet_proximity_out(struct litest_device *d); void +litest_tablet_tip_down(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); + +void +litest_tablet_tip_up(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); + +void litest_tablet_motion(struct litest_device *d, int x, int y, struct axis_replacement *axes); @@ -895,6 +906,9 @@ litest_timeout_buttonscroll(void); void +litest_timeout_wheel_scroll(void); + +void litest_timeout_edgescroll(void); void diff -Nru libinput-1.19.3/test/litest-int.h libinput-1.20.0/test/litest-int.h --- libinput-1.19.3/test/litest-int.h 2021-12-13 03:43:13.896429300 +0000 +++ libinput-1.20.0/test/litest-int.h 2022-02-19 12:32:09.000000000 +0000 @@ -119,6 +119,12 @@ double x, double y, struct axis_replacement *axes); bool (*tablet_proximity_out)(struct litest_device *d, unsigned int tool_type); + bool (*tablet_tip_down)(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); + bool (*tablet_tip_up)(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); /** * Pad events, LITEST_AUTO_ASSIGN is allowed on event values diff -Nru libinput-1.19.3/test/test-device.c libinput-1.20.0/test/test-device.c --- libinput-1.19.3/test/test-device.c 2021-12-13 03:43:13.897429200 +0000 +++ libinput-1.20.0/test/test-device.c 2022-02-19 12:32:09.000000000 +0000 @@ -56,7 +56,7 @@ device = dev->libinput_device; status = libinput_device_config_send_events_set_mode(device, - LIBINPUT_CONFIG_SEND_EVENTS_DISABLED | (1 << 4)); + LIBINPUT_CONFIG_SEND_EVENTS_DISABLED | bit(4)); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); } END_TEST diff -Nru libinput-1.19.3/test/test-misc.c libinput-1.20.0/test/test-misc.c --- libinput-1.19.3/test/test-misc.c 2021-12-13 03:43:13.897429200 +0000 +++ libinput-1.20.0/test/test-misc.c 2022-02-19 12:32:09.000000000 +0000 @@ -721,7 +721,7 @@ for (int i = 0; i < 20; i++) { litest_event(dev, EV_REL, REL_X, -1); litest_event(dev, EV_SYN, SYN_REPORT, 0); - msleep(11); + msleep(21); libinput_dispatch(li); } diff -Nru libinput-1.19.3/test/test-pointer.c libinput-1.20.0/test/test-pointer.c --- libinput-1.19.3/test/test-pointer.c 2021-12-13 03:43:13.898429400 +0000 +++ libinput-1.20.0/test/test-pointer.c 2022-02-19 12:32:09.000000000 +0000 @@ -701,54 +701,6 @@ } END_TEST -START_TEST(pointer_scroll_wheel_pressed_noscroll) -{ - struct litest_device *dev = litest_current_device(); - struct libinput *li = dev->libinput; - - litest_drain_events(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, true); - litest_drain_events(li); - - for (int i = 0; i < 10; i++) { - litest_event(dev, EV_REL, REL_WHEEL, 1); - litest_event(dev, EV_REL, REL_HWHEEL, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - } - - libinput_dispatch(li); - - litest_assert_empty_queue(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, false); -} -END_TEST - -START_TEST(pointer_scroll_hi_res_wheel_pressed_noscroll) -{ - struct litest_device *dev = litest_current_device(); - struct libinput *li = dev->libinput; - - litest_drain_events(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, true); - litest_drain_events(li); - - for (int i = 0; i < 10; i++) { - litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 12); - litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 12); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - } - - libinput_dispatch(li); - - litest_assert_empty_queue(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, false); -} -END_TEST - static void test_hi_res_wheel_event(struct litest_device *dev, int which, int v120_amount) { @@ -796,8 +748,8 @@ test_hi_res_wheel_event(dev, axis, 6 * 120); test_hi_res_wheel_event(dev, axis, 30); - test_hi_res_wheel_event(dev, axis, -40); test_hi_res_wheel_event(dev, axis, -60); + test_hi_res_wheel_event(dev, axis, -40); test_hi_res_wheel_event(dev, axis, 180); } } @@ -867,6 +819,91 @@ } END_TEST +START_TEST(pointer_scroll_wheel_inhibit_small_deltas) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES) && + !libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES)) + return; + + litest_drain_events(dev->libinput); + + /* Scroll deltas bellow the threshold (60) must be ignored */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 15); + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_assert_empty_queue(li); + + /* The accumulated scroll is 30, add 30 to trigger scroll */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 30); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -60); + + /* Once the threshold is reached, small scroll deltas are reported */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 5); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -5); + + /* When the scroll timeout is triggered, ignore small deltas again */ + litest_timeout_wheel_scroll(); + + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, -15); + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, -15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_assert_empty_queue(li); + + litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 15); + litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(pointer_scroll_wheel_inhibit_dir_change) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES) && + !libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES)) + return; + + litest_drain_events(dev->libinput); + + /* Scroll one detent and a bit */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 120); + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 30); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -150); + + /* Scroll below the threshold in the oposite direction should be ignored */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, -30); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_assert_empty_queue(li); + + /* But should be triggered if the scroll continues in the same direction */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, -120); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, 150); + + /* Scroll above the threshold in the same dir should be triggered */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 80); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -80); +} +END_TEST + START_TEST(pointer_scroll_natural_defaults) { struct litest_device *dev = litest_current_device(); @@ -3490,11 +3527,11 @@ litest_add_for_device(pointer_button_has_no_button, LITEST_KEYBOARD); litest_add(pointer_recover_from_lost_button_count, LITEST_BUTTON, LITEST_CLICKPAD); litest_add(pointer_scroll_wheel, LITEST_WHEEL, LITEST_TABLET); - litest_add_for_device(pointer_scroll_wheel_pressed_noscroll, LITEST_MOUSE); - litest_add_for_device(pointer_scroll_hi_res_wheel_pressed_noscroll, LITEST_MOUSE); litest_add(pointer_scroll_wheel_hires, LITEST_WHEEL, LITEST_TABLET); litest_add(pointer_scroll_wheel_hires_send_only_lores_vertical, LITEST_WHEEL, LITEST_TABLET); litest_add(pointer_scroll_wheel_hires_send_only_lores_horizontal, LITEST_WHEEL, LITEST_TABLET); + litest_add(pointer_scroll_wheel_inhibit_small_deltas, LITEST_WHEEL, LITEST_TABLET); + litest_add(pointer_scroll_wheel_inhibit_dir_change, LITEST_WHEEL, LITEST_TABLET); litest_add(pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY); litest_add(pointer_scroll_button_noscroll, LITEST_ABSOLUTE|LITEST_BUTTON, LITEST_RELATIVE); litest_add(pointer_scroll_button_noscroll, LITEST_ANY, LITEST_RELATIVE|LITEST_BUTTON); diff -Nru libinput-1.19.3/test/test-tablet.c libinput-1.20.0/test/test-tablet.c --- libinput-1.19.3/test/test-tablet.c 2021-12-13 03:43:13.899429300 +0000 +++ libinput-1.20.0/test/test-tablet.c 2022-02-19 12:32:09.000000000 +0000 @@ -223,10 +223,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); libinput_dispatch(li); @@ -240,10 +237,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 10); litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 10, 10, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -258,6 +252,62 @@ } END_TEST +START_TEST(tip_down_up_eraser) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_tablet_tool *tablet_event; + struct libinput_tablet_tool *tool; + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { ABS_PRESSURE, 0 }, + { -1, -1 } + }; + + if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_RUBBER)) + return; + + litest_tablet_set_tool_type(dev, BTN_TOOL_RUBBER); + + litest_tablet_proximity_in(dev, 10, 10, axes); + litest_drain_events(li); + + litest_axis_set_value(axes, ABS_DISTANCE, 0); + litest_axis_set_value(axes, ABS_PRESSURE, 30); + litest_tablet_tip_down(dev, 10, 10, axes); + + libinput_dispatch(li); + + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_TIP); + ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event), + LIBINPUT_TABLET_TOOL_TIP_DOWN); + tool = libinput_event_tablet_tool_get_tool(tablet_event); + ck_assert_int_eq(libinput_tablet_tool_get_type(tool), LIBINPUT_TABLET_TOOL_TYPE_ERASER); + libinput_event_destroy(event); + litest_assert_empty_queue(li); + + litest_axis_set_value(axes, ABS_DISTANCE, 10); + litest_axis_set_value(axes, ABS_PRESSURE, 0); + litest_tablet_tip_up(dev, 10, 10, axes); + + libinput_dispatch(li); + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_TIP); + ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event), + LIBINPUT_TABLET_TOOL_TIP_UP); + tool = libinput_event_tablet_tool_get_tool(tablet_event); + ck_assert_int_eq(libinput_tablet_tool_get_type(tool), LIBINPUT_TABLET_TOOL_TYPE_ERASER); + libinput_event_destroy(event); + + litest_assert_empty_queue(li); + +} +END_TEST + START_TEST(tip_down_prox_in) { struct litest_device *dev = litest_current_device(); @@ -274,8 +324,7 @@ litest_push_event_frame(dev); litest_tablet_proximity_in(dev, 10, 10, axes); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_tablet_tip_down(dev, 10, 10, axes); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -311,15 +360,13 @@ }; litest_tablet_proximity_in(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_tablet_tip_up(dev, 10, 10, axes); litest_tablet_proximity_out(dev); litest_pop_event_frame(dev); @@ -357,19 +404,15 @@ { -1, -1 } }; - litest_push_event_frame(dev); litest_tablet_proximity_in(dev, 10, 10, axes); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); + litest_tablet_tip_up(dev, 10, 20, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 1); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -394,18 +437,14 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); /* same thing with a release at tip-up */ litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_tablet_tip_up(dev, 10, 10, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 0); litest_pop_event_frame(dev); @@ -449,9 +488,8 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); + litest_tablet_tip_down(dev, 10, 20, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 1); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -477,18 +515,14 @@ litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 10, 20, axes); litest_drain_events(li); /* same thing with a release at tip-down */ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_tablet_tip_down(dev, 10, 20, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 0); litest_pop_event_frame(dev); @@ -542,11 +576,7 @@ /* move x/y on tip down, make sure x/y changed */ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 20); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -583,11 +613,7 @@ litest_drain_events(li); litest_axis_set_value(axes, ABS_PRESSURE, 20); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -599,10 +625,7 @@ /* move x/y on tip up, make sure x/y changed */ litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 40, 40, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 40, 40, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -656,11 +679,7 @@ litest_tablet_proximity_in(dev, start_x, start_y, axes); litest_axis_set_value(axes, ABS_PRESSURE, 20); for (int i = 0; i < 5; i++) { - litest_push_event_frame(dev); - litest_tablet_motion(dev, start_x, start_y, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, start_x, start_y, axes); switch (axis) { case ABS_X: @@ -685,17 +704,14 @@ /* move x on tip up, make sure x/y changed */ litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); switch (axis) { case ABS_X: - litest_tablet_motion(dev, 40, 20, axes); + litest_tablet_tip_up(dev, 40, 20, axes); break; case ABS_Y: - litest_tablet_motion(dev, 20, 40, axes); + litest_tablet_tip_up(dev, 20, 40, axes); break; } - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); libinput_dispatch(li); event = libinput_get_event(li); @@ -753,17 +769,11 @@ litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_axis_set_value(axes, ABS_DISTANCE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_axis_set_value(axes, ABS_DISTANCE, 10); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 10, 10, axes); litest_drain_events(li); @@ -809,10 +819,7 @@ litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_axis_set_value(axes, ABS_DISTANCE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 40, 40, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 40, 40, axes); litest_drain_events(li); litest_tablet_motion(dev, 30, 30, axes); @@ -827,10 +834,7 @@ litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_axis_set_value(axes, ABS_DISTANCE, 10); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 40, 40, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 40, 40, axes); litest_drain_events(li); litest_tablet_motion(dev, 40, 80, axes); @@ -875,10 +879,7 @@ litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_axis_set_value(axes, ABS_DISTANCE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 40, 40, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 40, 40, axes); litest_drain_events(li); litest_button_click(dev, button, false); @@ -893,10 +894,7 @@ litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_axis_set_value(axes, ABS_DISTANCE, 10); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 40, 40, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 40, 40, axes); litest_drain_events(li); litest_button_click(dev, button, true); @@ -940,10 +938,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); litest_delete_device(dev); @@ -3834,10 +3829,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 25); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes); libinput_dispatch(li); litest_drain_events(li); @@ -3928,10 +3920,7 @@ /* trigger the pressure threshold */ litest_axis_set_value(axes, ABS_PRESSURE, 15); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -3972,10 +3961,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 31); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes); libinput_dispatch(li); litest_drain_events(li); @@ -4162,7 +4148,7 @@ * offset the pressure here */ litest_push_event_frame(dev); litest_tablet_proximity_in(dev, 5, 100, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_tablet_tip_down(dev, 5, 100, axes); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -4197,10 +4183,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 21); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes); litest_drain_events(li); litest_axis_set_value(axes, ABS_PRESSURE, 20); @@ -4626,10 +4609,7 @@ /* tip down */ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 30, 20, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 30, 20, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -4658,10 +4638,7 @@ /* tip up */ litest_axis_set_value(axes, ABS_DISTANCE, 10); litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 50, 40, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 50, 40, axes); libinput_dispatch(li); event = libinput_get_event(li); tev = litest_is_tablet_event(event, @@ -5415,7 +5392,13 @@ litest_touch_move_to(finger, 0, x + 1, y - 1, x + 20, y - 20, 10); libinput_dispatch(li); + /* Allow for optional hold gesture to end */ event = libinput_get_event(li); + if (libinput_event_get_type(event) == LIBINPUT_EVENT_GESTURE_HOLD_END) { + libinput_event_destroy(event); + event = libinput_get_event(li); + } + ck_assert_notnull(event); while (event) { @@ -6139,6 +6122,7 @@ litest_add(tip_up_btn_change, LITEST_TABLET|LITEST_HOVER, LITEST_ANY); litest_add(tip_down_motion, LITEST_TABLET|LITEST_HOVER, LITEST_ANY); litest_add(tip_up_motion, LITEST_TABLET|LITEST_HOVER, LITEST_ANY); + litest_add(tip_down_up_eraser, LITEST_TABLET|LITEST_HOVER, LITEST_ANY); litest_add_ranged(tip_up_motion_one_axis, LITEST_TABLET|LITEST_HOVER, LITEST_ANY, &xyaxes); litest_add(tip_state_proximity, LITEST_TABLET|LITEST_HOVER, LITEST_ANY); litest_add(tip_state_axis, LITEST_TABLET|LITEST_HOVER, LITEST_ANY); diff -Nru libinput-1.19.3/test/test-touchpad-buttons.c libinput-1.20.0/test/test-touchpad-buttons.c --- libinput-1.19.3/test/test-touchpad-buttons.c 2021-12-13 03:43:13.899429300 +0000 +++ libinput-1.20.0/test/test-touchpad-buttons.c 2022-02-19 12:32:09.000000000 +0000 @@ -2098,29 +2098,6 @@ } END_TEST -START_TEST(touchpad_clickpad_detection) -{ - struct litest_device *dev; - uint32_t methods; - int codes[] = { - INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD, - -1, -1, - }; - - /* Create a device with LR buttons and INPUT_PROP_BUTTONPAD set - we - * should ignore the property and assume it's a non-clickpad. - * Only way to check that is to verify no click methods are set. - */ - dev = litest_create_device_with_overrides(LITEST_SYNAPTICS_TOUCHPAD, - "litest Fake Clickpad", - NULL, NULL, codes); - - methods = libinput_device_config_click_get_methods(dev->libinput_device); - ck_assert(methods == 0); - litest_delete_device(dev); -} -END_TEST - TEST_COLLECTION(touchpad_buttons) { struct range finger_count = {1, 4}; @@ -2191,6 +2168,5 @@ litest_add(clickpad_middleemulation_click_enable_while_down, LITEST_CLICKPAD, LITEST_ANY); litest_add(clickpad_middleemulation_click_disable_while_down, LITEST_CLICKPAD, LITEST_ANY); - litest_add_no_device(touchpad_clickpad_detection); litest_add_no_device(touchpad_non_clickpad_detection); } diff -Nru libinput-1.19.3/tools/libinput-record.c libinput-1.20.0/tools/libinput-record.c --- libinput-1.19.3/tools/libinput-record.c 2021-12-13 03:43:13.905429400 +0000 +++ libinput-1.20.0/tools/libinput-record.c 2022-02-19 12:32:09.000000000 +0000 @@ -48,6 +48,7 @@ #include "libinput-git-version.h" #include "shared.h" #include "builddir.h" +#include "util-bits.h" #include "util-list.h" #include "util-time.h" #include "util-input-event.h" @@ -391,9 +392,9 @@ assert(slot < sizeof(d->touch.slot_state) * 8); if (e.value != -1) - d->touch.slot_state |= 1 << slot; + d->touch.slot_state |= bit(slot); else - d->touch.slot_state &= ~(1 << slot); + d->touch.slot_state &= ~bit(slot); } if (e.type == EV_SYN && e.code == SYN_REPORT) diff -Nru libinput-1.19.3/tools/shared.c libinput-1.20.0/tools/shared.c --- libinput-1.19.3/tools/shared.c 2021-12-13 03:43:13.905429400 +0000 +++ libinput-1.20.0/tools/shared.c 2022-02-19 12:32:09.000000000 +0000 @@ -693,6 +693,7 @@ uint32_t v; char *s; double d; + bool b; name = quirk_get_name(q); @@ -733,7 +734,8 @@ break; case QUIRK_ATTR_USE_VELOCITY_AVERAGING: case QUIRK_ATTR_TABLET_SMOOTHING: - snprintf(buf, sizeof(buf), "%s=1", name); + quirks_get_bool(quirks, q, &b); + snprintf(buf, sizeof(buf), "%s=%d", name, b); callback(userdata, buf); break; case QUIRK_ATTR_EVENT_CODE_DISABLE: