Timo Aaltonen pushed to branch upstream-unstable at X Strike Force / lib / libinput
Commits:
- 
535cc987
by RussianNeuroMancer at 2019-10-16T03:36:41Z
- 
b9ba9e72
by RussianNeuroMancer at 2019-10-16T03:36:42Z
- 
b927b422
by Richard McIntosh at 2019-10-16T03:36:45Z
- 
ad7708f6
by Serhii Chaplia at 2019-10-16T03:37:30Z
- 
093a8789
by Peter Hutterer at 2019-10-16T03:37:43Z
- 
c8daa2c0
by Peter Hutterer at 2019-10-16T03:37:50Z
- 
a7d2b749
by John Chadwick at 2019-10-16T03:38:11Z
- 
62382f7d
by Jakub Schmidtke at 2019-10-16T03:38:23Z
- 
34a73652
by yy at 2019-10-16T03:38:25Z
- 
fa104590
by Benjamin Tissoires at 2019-10-16T03:38:34Z
- 
6dc9de07
by Benjamin Tissoires at 2019-10-16T03:38:37Z
- 
f65b1a2e
by Peter Hutterer at 2019-10-17T00:15:28Z
13 changed files:
- .gitlab-ci.yml
- meson.build
- quirks/30-vendor-logitech.quirks
- quirks/50-system-hp.quirks
- quirks/50-system-lenovo.quirks
- src/evdev-mt-touchpad-gestures.c
- src/evdev-mt-touchpad-thumb.c
- src/evdev.c
- src/evdev.h
- src/quirks.c
- src/quirks.h
- test/litest-int.h
- test/test-gestures.c
Changes:
| ... | ... | @@ -24,18 +24,20 @@ | 
| 24 | 24 |  # <distribution>:<version>@activity:
 | 
| 25 | 25 |  #  e.g. fedora:29@build-default
 | 
| 26 | 26 |  | 
| 27 | +.templates_sha: &template_sha ff90ddcf059bfce35bd5f9b89a59d5d0c912b458 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
 | |
| 28 | + | |
| 27 | 29 |  include:
 | 
| 28 | 30 |    # Arch container builder template
 | 
| 29 | 31 |    - project: 'wayland/ci-templates'
 | 
| 30 | -    ref: 955e61e67cf29327cf907432f668df9eec4ca6a2 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
 | |
| 32 | +    ref: *template_sha
 | |
| 31 | 33 |      file: '/templates/arch.yml'
 | 
| 32 | 34 |    # Fedora container builder template
 | 
| 33 | 35 |    - project: 'wayland/ci-templates'
 | 
| 34 | -    ref: 955e61e67cf29327cf907432f668df9eec4ca6a2 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
 | |
| 36 | +    ref: *template_sha
 | |
| 35 | 37 |      file: '/templates/fedora.yml'
 | 
| 36 | 38 |    # Ubuntu container builder template
 | 
| 37 | 39 |    - project: 'wayland/ci-templates'
 | 
| 38 | -    ref: 955e61e67cf29327cf907432f668df9eec4ca6a2 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
 | |
| 40 | +    ref: *template_sha
 | |
| 39 | 41 |      file: '/templates/ubuntu.yml'
 | 
| 40 | 42 |  | 
| 41 | 43 |  stages:
 | 
| ... | ... | @@ -56,6 +58,7 @@ variables: | 
| 56 | 58 |    # https://wayland.freedesktop.org/libinput/doc/latest/building_libinput.html  #
 | 
| 57 | 59 |    ###############################################################################
 | 
| 58 | 60 |    FEDORA_RPMS:        'git gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark                          libwacom-devel cairo-devel   gtk3-devel   glib2-devel    mtdev-devel'
 | 
| 61 | +  FEDORA_QEMU_RPMS:   'git gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark                          libwacom-devel cairo-devel   gtk3-devel   glib2-devel    mtdev-devel diffutils valgrind'
 | |
| 59 | 62 |    UBUNTU_CUSTOM_DEBS: 'git gcc g++     pkg-config         meson check       libudev-dev   libevdev-dev   doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme libwacom-dev   libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev'
 | 
| 60 | 63 |    ARCH_PKGS:          'git gcc         pkgconfig          meson check       libsystemd    libevdev       doxygen graphviz  python-sphinx  python-recommonmark python-sphinx_rtd_theme  libwacom                     gtk3                        mtdev      diffutils'
 | 
| 61 | 64 |    FREEBSD_BUILD_PKGS: 'meson'
 | 
| ... | ... | @@ -70,6 +73,7 @@ variables: | 
| 70 | 73 |    UBUNTU_TAG: '2019-08-07.0'
 | 
| 71 | 74 |    ARCH_TAG: '2019-08-07.0'
 | 
| 72 | 75 |    FREEBSD_TAG: '2019-08-07.0'
 | 
| 76 | +  QEMU_TAG: 'qemu-vm-2019-10-04.0'
 | |
| 73 | 77 |  | 
| 74 | 78 |    UBUNTU_EXEC: "bash .gitlab-ci/ubuntu_install.sh $UBUNTU_CUSTOM_DEBS"
 | 
| 75 | 79 |  | 
| ... | ... | @@ -79,6 +83,7 @@ variables: | 
| 79 | 83 |    UBUNTU_CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/ubuntu/$UBUNTU_VERSION:$UBUNTU_TAG
 | 
| 80 | 84 |    ARCH_CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/archlinux/rolling:$ARCH_TAG
 | 
| 81 | 85 |    FREEBSD_CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/freebsd/11.2:$FREEBSD_TAG
 | 
| 86 | +  QEMU_CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/fedora/$FEDORA_VERSION:$QEMU_TAG
 | |
| 82 | 87 |  | 
| 83 | 88 |    MESON_BUILDDIR: "build dir"
 | 
| 84 | 89 |    NINJA_ARGS: ''
 | 
| ... | ... | @@ -137,6 +142,21 @@ variables: | 
| 137 | 142 |          skopeo inspect docker://$CI_REGISTRY_IMAGE/$IMAGE > /dev/null && exit 0 || true ;
 | 
| 138 | 143 |        fi
 | 
| 139 | 144 |  | 
| 145 | +fedora:30@qemu-prep:
 | |
| 146 | +  extends: .fedora@qemu-build
 | |
| 147 | +  stage: container_prep
 | |
| 148 | +  tags:
 | |
| 149 | +    - kvm
 | |
| 150 | +  variables:
 | |
| 151 | +    GIT_STRATEGY: none
 | |
| 152 | +    FEDORA_VERSION: 30
 | |
| 153 | +    FEDORA_TAG: $QEMU_TAG
 | |
| 154 | +    FEDORA_RPMS: $FEDORA_QEMU_RPMS
 | |
| 155 | +    DISTRIB_FLAVOR: fedora
 | |
| 156 | +    DISTRIB_VERSION: $FEDORA_VERSION
 | |
| 157 | +    TAG: $QEMU_TAG
 | |
| 158 | +  <<: *pull_upstream_or_rebuild
 | |
| 159 | + | |
| 140 | 160 |  fedora:30@container-prep:
 | 
| 141 | 161 |    extends: .fedora@container-build
 | 
| 142 | 162 |    stage: container_prep
 | 
| ... | ... | @@ -361,6 +381,64 @@ freebsd:11.2@container-clean: | 
| 361 | 381 |  # Fedora
 | 
| 362 | 382 |  #
 | 
| 363 | 383 |  | 
| 384 | +.check_tainted: &check_tainted |
 | |
| 385 | +  # make sure the kernel is not tainted
 | |
| 386 | +  if [[ "$(ssh localhost -p 5555 cat /proc/sys/kernel/tainted)" -gt 0 ]];
 | |
| 387 | +  then
 | |
| 388 | +    echo tainted kernel ;
 | |
| 389 | +    exit 1 ;
 | |
| 390 | +  fi
 | |
| 391 | + | |
| 392 | +fedora:30@test-suite-vm:
 | |
| 393 | +  stage: build
 | |
| 394 | +  image: $QEMU_CONTAINER_IMAGE
 | |
| 395 | +  tags:
 | |
| 396 | +    - kvm
 | |
| 397 | +  variables:
 | |
| 398 | +    FEDORA_VERSION: 30
 | |
| 399 | +    MESON_BUILDDIR: build_dir
 | |
| 400 | +  script:
 | |
| 401 | +    # start our vm, no args required
 | |
| 402 | +    - /app/start_vm.sh
 | |
| 403 | + | |
| 404 | +    - *check_tainted
 | |
| 405 | + | |
| 406 | +    - "scp -P 5555 -r $PWD localhost:"
 | |
| 407 | +    - ssh localhost -p 5555 rm -rf $CI_PROJECT_NAME/"$MESON_BUILDDIR"
 | |
| 408 | +    - ssh localhost -p 5555 "cd $CI_PROJECT_NAME ; meson \"$MESON_BUILDDIR\" $MESON_ARGS"
 | |
| 409 | +    - ssh localhost -p 5555 "cd $CI_PROJECT_NAME ; meson configure \"$MESON_BUILDDIR\" "
 | |
| 410 | +    - ssh localhost -p 5555 "cd $CI_PROJECT_NAME ; ninja -C \"$MESON_BUILDDIR\" $NINJA_ARGS"
 | |
| 411 | +    - ssh localhost -p 5555 "cd $CI_PROJECT_NAME ; meson test -C \"$MESON_BUILDDIR\" --print-errorlogs" && touch .success || true
 | |
| 412 | + | |
| 413 | +    # no matter the results of the tests, we want to fetch the logs
 | |
| 414 | +    - scp -P 5555 -r localhost:$CI_PROJECT_NAME/$MESON_BUILDDIR .
 | |
| 415 | + | |
| 416 | +    - *check_tainted
 | |
| 417 | + | |
| 418 | +    - ssh localhost -p 5555 halt || true
 | |
| 419 | +    - sleep 2
 | |
| 420 | +    - kill $(pgrep qemu)
 | |
| 421 | + | |
| 422 | +    - if [[ ! -e .success ]] ;
 | |
| 423 | +      then
 | |
| 424 | +        exit 1 ;
 | |
| 425 | +      fi
 | |
| 426 | + | |
| 427 | +  after_script:
 | |
| 428 | +    # no matter the results of the tests, we want to kill the VM
 | |
| 429 | +    - kill $(pgrep qemu)
 | |
| 430 | + | |
| 431 | +  artifacts:
 | |
| 432 | +    name: "qemu-meson-logs-$CI_JOB_NAME"
 | |
| 433 | +    when: always
 | |
| 434 | +    expire_in: 1 week
 | |
| 435 | +    paths:
 | |
| 436 | +      - $MESON_BUILDDIR/meson-logs
 | |
| 437 | +      - console.out
 | |
| 438 | + | |
| 439 | +  allow_failure: true
 | |
| 440 | + | |
| 441 | + | |
| 364 | 442 |  .fedora-build@template:
 | 
| 365 | 443 |    extends: .build@template
 | 
| 366 | 444 |    image: $FEDORA_CONTAINER_IMAGE
 | 
| 1 | 1 |  project('libinput', 'c',
 | 
| 2 | -	version : '1.14.1',
 | |
| 2 | +	version : '1.14.2',
 | |
| 3 | 3 |  	license : 'MIT/Expat',
 | 
| 4 | 4 |  	default_options : [ 'c_std=gnu99', 'warning_level=2' ],
 | 
| 5 | 5 |  	meson_version : '>= 0.41.0')
 | 
| ... | ... | @@ -45,3 +45,13 @@ MatchBus=usb | 
| 45 | 45 |  MatchVendor=0x046D
 | 
| 46 | 46 |  MatchProduct=0x4011
 | 
| 47 | 47 |  AttrPalmPressureThreshold=400
 | 
| 48 | + | |
| 49 | +[Logitech MX Master 2S]
 | |
| 50 | +MatchVendor=0x46D
 | |
| 51 | +MatchProduct=0x4069
 | |
| 52 | +ModelInvertHorizontalScrolling=1
 | |
| 53 | + | |
| 54 | +[Logitech MX Master 3]
 | |
| 55 | +MatchVendor=0x46D
 | |
| 56 | +MatchProduct=0x4082
 | |
| 57 | +ModelInvertHorizontalScrolling=1 | 
| ... | ... | @@ -41,3 +41,21 @@ MatchDMIModalias=dmi:*svnHP:pnHPSpectrex360Convertible15-bl1XX:* | 
| 41 | 41 |  AttrPressureRange=55:40
 | 
| 42 | 42 |  AttrThumbPressureThreshold=90
 | 
| 43 | 43 |  AttrPalmPressureThreshold=100
 | 
| 44 | + | |
| 45 | +[HP Elite x2 1013 G3 Tablet Mode Switch]
 | |
| 46 | +MatchName=*Intel Virtual Button*
 | |
| 47 | +MatchDMIModalias=dmi:*svnHP:pnHPElitex21013G3:*
 | |
| 48 | +ModelTabletModeSwitchUnreliable=1
 | |
| 49 | + | |
| 50 | +[HP Elite x2 1013 G3 Touchpad]
 | |
| 51 | +MatchUdevType=touchpad
 | |
| 52 | +MatchBus=usb
 | |
| 53 | +MatchVendor=0x044E
 | |
| 54 | +MatchProduct=0x1221
 | |
| 55 | +AttrTPKComboLayout=below
 | |
| 56 | + | |
| 57 | +[HP Elite x2 1013 G3 Keyboard]
 | |
| 58 | +MatchUdevType=keyboard
 | |
| 59 | +MatchBus=ps2
 | |
| 60 | +MatchDMIModalias=dmi:*svnHP:pnHPElitex21013G3:*
 | |
| 61 | +AttrKeyboardIntegration=external | |
| \ No newline at end of file | 
| ... | ... | @@ -5,6 +5,12 @@ MatchName=*Synaptics* | 
| 5 | 5 |  MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPad*:*
 | 
| 6 | 6 |  AttrThumbPressureThreshold=100
 | 
| 7 | 7 |  | 
| 8 | +[Lenovo ThinkPad 13 2nd Generation TrackPoint]
 | |
| 9 | +MatchUdevType=pointingstick
 | |
| 10 | +MatchName=*ETPS/2 Elantech TrackPoint*
 | |
| 11 | +MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPad132ndGen*
 | |
| 12 | +AttrTrackpointMultiplier=1.75
 | |
| 13 | + | |
| 8 | 14 |  [Lenovo x230 Touchpad]
 | 
| 9 | 15 |  MatchName=*SynPS/2 Synaptics TouchPad
 | 
| 10 | 16 |  MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX230*
 | 
| ... | ... | @@ -30,6 +36,16 @@ MatchName=Elan Touchpad | 
| 30 | 36 |  MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT480s*
 | 
| 31 | 37 |  ModelLenovoT480sTouchpad=1
 | 
| 32 | 38 |  | 
| 39 | +[Lenovo T490s Touchpad]
 | |
| 40 | +MatchName=Elan Touchpad
 | |
| 41 | +MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT490s*
 | |
| 42 | +ModelLenovoT490sTouchpad=1
 | |
| 43 | + | |
| 44 | +[Lenovo T490s Trackpoint]
 | |
| 45 | +MatchName=*TPPS/2 IBM TrackPoint
 | |
| 46 | +MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT490s:*
 | |
| 47 | +AttrTrackpointMultiplier=0.4
 | |
| 48 | + | |
| 33 | 49 |  [Lenovo L380 Touchpad]
 | 
| 34 | 50 |  MatchName=Elan Touchpad
 | 
| 35 | 51 |  MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadL380*
 | 
| ... | ... | @@ -146,6 +162,13 @@ MatchName=AT Translated Set 2 keyboard | 
| 146 | 162 |  MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX230Tablet:*
 | 
| 147 | 163 |  ModelTabletModeNoSuspend=1
 | 
| 148 | 164 |  | 
| 165 | +# Special bezel button deactivation with
 | |
| 166 | +# keyboard also applies to X200 Tablet
 | |
| 167 | +[Lenovo X200 Tablet]
 | |
| 168 | +MatchName=AT Translated Set 2 keyboard
 | |
| 169 | +MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX200Tablet:*
 | |
| 170 | +ModelTabletModeNoSuspend=1
 | |
| 171 | + | |
| 149 | 172 |  # Lenovo MIIX 720 comes with a detachable keyboard. We must not disable
 | 
| 150 | 173 |  # the keyboard because some keys are still accessible on the screen and
 | 
| 151 | 174 |  # volume rocker. See
 | 
| ... | ... | @@ -481,6 +481,12 @@ tp_gesture_handle_state_unknown(struct tp_dispatch *tp, uint64_t time) | 
| 481 | 481 |  	double inner = 1.5; /* inner threshold in mm - count this touch */
 | 
| 482 | 482 |  	double outer = 4.0; /* outer threshold in mm - ignore other touch */
 | 
| 483 | 483 |  | 
| 484 | +	/* If we have more fingers than slots, we don't know where the
 | |
| 485 | +	 * fingers are. Default to swipe */
 | |
| 486 | +	if (tp->gesture.enabled && tp->gesture.finger_count > 2 &&
 | |
| 487 | +	    tp->gesture.finger_count > tp->num_slots)
 | |
| 488 | +		return GESTURE_STATE_SWIPE;
 | |
| 489 | + | |
| 484 | 490 |  	/* Need more margin for error when there are more fingers */
 | 
| 485 | 491 |  	outer += 2.0 * (tp->gesture.finger_count - 2);
 | 
| 486 | 492 |  	inner += 0.5 * (tp->gesture.finger_count - 2);
 | 
| ... | ... | @@ -335,15 +335,18 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp) | 
| 335 | 335 |  | 
| 336 | 336 |  	/* Position-based thumb detection: When a new touch arrives, check the
 | 
| 337 | 337 |  	 * two lowest touches. If they qualify for 2-finger scrolling, clear
 | 
| 338 | -	 * thumb status. If not, mark the lower touch (based on pinch_eligible)
 | |
| 339 | -	 * as either PINCH or SUPPRESSED.
 | |
| 338 | +	 * thumb status.
 | |
| 339 | +	 *
 | |
| 340 | +	 * If they were in distinct diagonal position, then mark the lower
 | |
| 341 | +	 * touch (based on pinch_eligible) as either PINCH or SUPPRESSED. If
 | |
| 342 | +	 * we're too close together for a thumb, lift that.
 | |
| 340 | 343 |  	 */
 | 
| 341 | -	if (mm.y > SCROLL_MM_Y) {
 | |
| 344 | +	if (mm.y > SCROLL_MM_Y && mm.x > SCROLL_MM_X) {
 | |
| 342 | 345 |  		if (tp->thumb.pinch_eligible)
 | 
| 343 | 346 |  			tp_thumb_pinch(tp, first);
 | 
| 344 | 347 |  		else
 | 
| 345 | 348 |  			tp_thumb_suppress(tp, first);
 | 
| 346 | -	} else {
 | |
| 349 | +	} else if (mm.x < SCROLL_MM_X && mm.y < SCROLL_MM_Y) {
 | |
| 347 | 350 |  		tp_thumb_lift(tp);
 | 
| 348 | 351 |  	}
 | 
| 349 | 352 |  }
 | 
| ... | ... | @@ -357,6 +357,11 @@ evdev_notify_axis(struct evdev_device *device, | 
| 357 | 357 |  	struct normalized_coords delta = *delta_in;
 | 
| 358 | 358 |  	struct discrete_coords discrete = *discrete_in;
 | 
| 359 | 359 |  | 
| 360 | +	if (device->scroll.invert_horizontal_scrolling) {
 | |
| 361 | +		delta.x *= -1;
 | |
| 362 | +		discrete.x *= -1;
 | |
| 363 | +	}
 | |
| 364 | + | |
| 360 | 365 |  	if (device->scroll.natural_scrolling_enabled) {
 | 
| 361 | 366 |  		delta.x *= -1;
 | 
| 362 | 367 |  		delta.y *= -1;
 | 
| ... | ... | @@ -1841,6 +1846,10 @@ evdev_configure_device(struct evdev_device *device) | 
| 1841 | 1846 |  		return NULL;
 | 
| 1842 | 1847 |  	}
 | 
| 1843 | 1848 |  | 
| 1849 | +	if (evdev_device_has_model_quirk(device, QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING)) {
 | |
| 1850 | +		device->scroll.invert_horizontal_scrolling = true;
 | |
| 1851 | +	}
 | |
| 1852 | + | |
| 1844 | 1853 |  	return fallback_dispatch_create(&device->base);
 | 
| 1845 | 1854 |  }
 | 
| 1846 | 1855 |  | 
| ... | ... | @@ -1953,6 +1962,7 @@ evdev_pre_configure_model_quirks(struct evdev_device *device) | 
| 1953 | 1962 |  	 * https://gitlab.freedesktop.org/libinput/libinput/issues/177 and
 | 
| 1954 | 1963 |  	 * https://gitlab.freedesktop.org/libinput/libinput/issues/234 */
 | 
| 1955 | 1964 |  	if (evdev_device_has_model_quirk(device, QUIRK_MODEL_LENOVO_T480S_TOUCHPAD) ||
 | 
| 1965 | +	    evdev_device_has_model_quirk(device, QUIRK_MODEL_LENOVO_T490S_TOUCHPAD) ||
 | |
| 1956 | 1966 |  	    evdev_device_has_model_quirk(device, QUIRK_MODEL_LENOVO_L380_TOUCHPAD))
 | 
| 1957 | 1967 |  		libevdev_enable_property(device->evdev,
 | 
| 1958 | 1968 |  					 INPUT_PROP_BUTTONPAD);
 | 
| ... | ... | @@ -216,6 +216,10 @@ struct evdev_device { | 
| 216 | 216 |  		 * used at runtime to enable/disable the feature */
 | 
| 217 | 217 |  		bool natural_scrolling_enabled;
 | 
| 218 | 218 |  | 
| 219 | +		/* set during device init to invert direction of
 | |
| 220 | +		 * horizontal scrolling */
 | |
| 221 | +		bool invert_horizontal_scrolling;
 | |
| 222 | + | |
| 219 | 223 |  		/* angle per REL_WHEEL click in degrees */
 | 
| 220 | 224 |  		struct wheel_angle wheel_click_angle;
 | 
| 221 | 225 |  | 
| ... | ... | @@ -239,10 +239,12 @@ quirk_get_name(enum quirk q) | 
| 239 | 239 |  	case QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD:	return "ModelHPPavilionDM4Touchpad";
 | 
| 240 | 240 |  	case QUIRK_MODEL_HP_STREAM11_TOUCHPAD:		return "ModelHPStream11Touchpad";
 | 
| 241 | 241 |  	case QUIRK_MODEL_HP_ZBOOK_STUDIO_G3:		return "ModelHPZBookStudioG3";
 | 
| 242 | +	case QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING:	return "ModelInvertHorizontalScrolling";
 | |
| 242 | 243 |  	case QUIRK_MODEL_LENOVO_L380_TOUCHPAD:		return "ModelLenovoL380Touchpad";
 | 
| 243 | 244 |  	case QUIRK_MODEL_LENOVO_SCROLLPOINT:		return "ModelLenovoScrollPoint";
 | 
| 244 | 245 |  	case QUIRK_MODEL_LENOVO_T450_TOUCHPAD:		return "ModelLenovoT450Touchpad";
 | 
| 245 | 246 |  	case QUIRK_MODEL_LENOVO_T480S_TOUCHPAD:		return "ModelLenovoT480sTouchpad";
 | 
| 247 | +	case QUIRK_MODEL_LENOVO_T490S_TOUCHPAD:		return "ModelLenovoT490sTouchpad";
 | |
| 246 | 248 |  	case QUIRK_MODEL_LENOVO_X230:			return "ModelLenovoX230";
 | 
| 247 | 249 |  	case QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD:	return "ModelSynapticsSerialTouchpad";
 | 
| 248 | 250 |  	case QUIRK_MODEL_SYSTEM76_BONOBO:		return "ModelSystem76Bonobo";
 | 
| ... | ... | @@ -71,10 +71,12 @@ enum quirk { | 
| 71 | 71 |  	QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD,
 | 
| 72 | 72 |  	QUIRK_MODEL_HP_STREAM11_TOUCHPAD,
 | 
| 73 | 73 |  	QUIRK_MODEL_HP_ZBOOK_STUDIO_G3,
 | 
| 74 | +	QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING,
 | |
| 74 | 75 |  	QUIRK_MODEL_LENOVO_L380_TOUCHPAD,
 | 
| 75 | 76 |  	QUIRK_MODEL_LENOVO_SCROLLPOINT,
 | 
| 76 | 77 |  	QUIRK_MODEL_LENOVO_T450_TOUCHPAD,
 | 
| 77 | 78 |  	QUIRK_MODEL_LENOVO_T480S_TOUCHPAD,
 | 
| 79 | +	QUIRK_MODEL_LENOVO_T490S_TOUCHPAD,
 | |
| 78 | 80 |  	QUIRK_MODEL_LENOVO_X230,
 | 
| 79 | 81 |  	QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD,
 | 
| 80 | 82 |  	QUIRK_MODEL_SYSTEM76_BONOBO,
 | 
| ... | ... | @@ -77,7 +77,7 @@ struct litest_test_device { | 
| 77 | 77 |  	const char *udev_rule;
 | 
| 78 | 78 |  	const char *quirk_file;
 | 
| 79 | 79 |  | 
| 80 | -	const struct key_value_str udev_properties[];
 | |
| 80 | +	const struct key_value_str udev_properties[32];
 | |
| 81 | 81 |  };
 | 
| 82 | 82 |  | 
| 83 | 83 |  struct litest_device_interface {
 | 
| ... | ... | @@ -259,6 +259,58 @@ START_TEST(gestures_swipe_3fg_btntool) | 
| 259 | 259 |  }
 | 
| 260 | 260 |  END_TEST
 | 
| 261 | 261 |  | 
| 262 | +START_TEST(gestures_swipe_3fg_btntool_pinch_like)
 | |
| 263 | +{
 | |
| 264 | +	struct litest_device *dev = litest_current_device();
 | |
| 265 | +	struct libinput *li = dev->libinput;
 | |
| 266 | +	struct libinput_event *event;
 | |
| 267 | +	struct libinput_event_gesture *gevent;
 | |
| 268 | + | |
| 269 | +	if (libevdev_get_num_slots(dev->evdev) > 2 ||
 | |
| 270 | +	    !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP) ||
 | |
| 271 | +	    !libinput_device_has_capability(dev->libinput_device,
 | |
| 272 | +					    LIBINPUT_DEVICE_CAP_GESTURE))
 | |
| 273 | +		return;
 | |
| 274 | + | |
| 275 | +	litest_drain_events(li);
 | |
| 276 | + | |
| 277 | +	/* Technically a pinch position + pinch movement, but expect swipe
 | |
| 278 | +	 * for nfingers > nslots */
 | |
| 279 | +	litest_touch_down(dev, 0, 20, 60);
 | |
| 280 | +	litest_touch_down(dev, 1, 50, 20);
 | |
| 281 | +	litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
 | |
| 282 | +	litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
 | |
| 283 | +	litest_event(dev, EV_SYN, SYN_REPORT, 0);
 | |
| 284 | + | |
| 285 | +	libinput_dispatch(li);
 | |
| 286 | +	litest_touch_move_to(dev, 0, 20, 60, 10, 80, 20);
 | |
| 287 | +	libinput_dispatch(li);
 | |
| 288 | + | |
| 289 | +	event = libinput_get_event(li);
 | |
| 290 | +	gevent = litest_is_gesture_event(event,
 | |
| 291 | +					 LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN,
 | |
| 292 | +					 3);
 | |
| 293 | +	libinput_event_destroy(event);
 | |
| 294 | + | |
| 295 | +	while ((event = libinput_get_event(li)) != NULL) {
 | |
| 296 | +		gevent = litest_is_gesture_event(event,
 | |
| 297 | +						 LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
 | |
| 298 | +						 3);
 | |
| 299 | +		libinput_event_destroy(event);
 | |
| 300 | +	}
 | |
| 301 | + | |
| 302 | +	litest_touch_up(dev, 0);
 | |
| 303 | +	litest_touch_up(dev, 1);
 | |
| 304 | +	libinput_dispatch(li);
 | |
| 305 | +	event = libinput_get_event(li);
 | |
| 306 | +	gevent = litest_is_gesture_event(event,
 | |
| 307 | +					 LIBINPUT_EVENT_GESTURE_SWIPE_END,
 | |
| 308 | +					 3);
 | |
| 309 | +	ck_assert(!libinput_event_gesture_get_cancelled(gevent));
 | |
| 310 | +	libinput_event_destroy(event);
 | |
| 311 | +}
 | |
| 312 | +END_TEST
 | |
| 313 | + | |
| 262 | 314 |  START_TEST(gestures_swipe_4fg)
 | 
| 263 | 315 |  {
 | 
| 264 | 316 |  	struct litest_device *dev = litest_current_device();
 | 
| ... | ... | @@ -1021,6 +1073,7 @@ TEST_COLLECTION(gestures) | 
| 1021 | 1073 |  | 
| 1022 | 1074 |  	litest_add_ranged("gestures:swipe", gestures_swipe_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
 | 
| 1023 | 1075 |  	litest_add_ranged("gestures:swipe", gestures_swipe_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
 | 
| 1076 | +	litest_add("gestures:swipe", gestures_swipe_3fg_btntool_pinch_like, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
 | |
| 1024 | 1077 |  	litest_add_ranged("gestures:swipe", gestures_swipe_4fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
 | 
| 1025 | 1078 |  	litest_add_ranged("gestures:swipe", gestures_swipe_4fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
 | 
| 1026 | 1079 |  	litest_add_ranged("gestures:pinch", gestures_pinch, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
 |