test-touchpad.c 205 KB
Newer Older
1 2 3
/*
 * Copyright © 2014 Red Hat, Inc.
 *
4 5 6 7 8 9
 * 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:
10
 *
11 12 13 14 15 16 17 18 19 20 21
 * 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.
22 23 24 25 26 27 28 29 30 31 32 33 34
 */

#include <config.h>

#include <check.h>
#include <errno.h>
#include <fcntl.h>
#include <libinput.h>
#include <unistd.h>

#include "libinput-util.h"
#include "litest.h"

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
static inline bool
has_disable_while_typing(struct litest_device *device)
{
	return libinput_device_config_dwt_is_available(device->libinput_device);
}

static inline struct litest_device *
dwt_init_paired_keyboard(struct libinput *li,
			 struct litest_device *touchpad)
{
	enum litest_device_type which = LITEST_KEYBOARD;

	if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_APPLE)
		which = LITEST_APPLE_KEYBOARD;

	if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_CHICONY)
		which = LITEST_ACER_HAWAII_KEYBOARD;

	return litest_add_device(li, which);
}

56 57 58 59 60 61 62
START_TEST(touchpad_1fg_motion)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;

63
	litest_disable_tap(dev->libinput_device);
64

65 66 67
	litest_drain_events(li);

	litest_touch_down(dev, 0, 50, 50);
68
	litest_touch_move_to(dev, 0, 50, 50, 80, 50, 20);
69 70 71 72 73
	litest_touch_up(dev, 0);

	libinput_dispatch(li);

	event = libinput_get_event(li);
74
	ck_assert_notnull(event);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

	while (event) {
		ck_assert_int_eq(libinput_event_get_type(event),
				 LIBINPUT_EVENT_POINTER_MOTION);

		ptrev = libinput_event_get_pointer_event(event);
		ck_assert_int_ge(libinput_event_pointer_get_dx(ptrev), 0);
		ck_assert_int_eq(libinput_event_pointer_get_dy(ptrev), 0);
		libinput_event_destroy(event);
		event = libinput_get_event(li);
	}
}
END_TEST

START_TEST(touchpad_2fg_no_motion)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;

95 96 97
	libinput_device_config_tap_set_enabled(dev->libinput_device,
					       LIBINPUT_CONFIG_TAP_DISABLED);

98 99
	litest_drain_events(li);

100 101
	litest_touch_down(dev, 0, 20, 20);
	litest_touch_down(dev, 1, 70, 20);
102
	litest_touch_move_two_touches(dev, 20, 20, 70, 20, 20, 30, 20);
103
	litest_touch_up(dev, 1);
104
	litest_touch_up(dev, 0);
105 106 107 108 109 110 111 112 113 114 115 116 117

	libinput_dispatch(li);

	event = libinput_get_event(li);
	while (event) {
		ck_assert_int_ne(libinput_event_get_type(event),
				 LIBINPUT_EVENT_POINTER_MOTION);
		libinput_event_destroy(event);
		event = libinput_get_event(li);
	}
}
END_TEST

118
static void
119
test_2fg_scroll(struct litest_device *dev, double dx, double dy, bool want_sleep)
120
{
121 122
	struct libinput *li = dev->libinput;

123 124
	litest_touch_down(dev, 0, 49, 50);
	litest_touch_down(dev, 1, 51, 50);
125

126
	litest_touch_move_two_touches(dev, 49, 50, 51, 50, dx, dy, 10);
127

128
	/* Avoid a small scroll being seen as a tap */
129
	if (want_sleep) {
130
		libinput_dispatch(li);
131
		litest_timeout_tap();
132 133 134
		libinput_dispatch(li);
	}

135 136
	litest_touch_up(dev, 1);
	litest_touch_up(dev, 0);
137 138

	libinput_dispatch(li);
139 140 141 142 143 144 145
}

START_TEST(touchpad_2fg_scroll)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

146
	if (!litest_has_2fg_scroll(dev))
147 148
		return;

149
	litest_enable_2fg_scroll(dev);
150 151
	litest_drain_events(li);

152
	test_2fg_scroll(dev, 0.1, 40, false);
153
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 9);
154
	test_2fg_scroll(dev, 0.1, -40, false);
155
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -9);
156
	test_2fg_scroll(dev, 40, 0.1, false);
157
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 9);
158
	test_2fg_scroll(dev, -40, 0.1, false);
159
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
160 161

	/* 2fg scroll smaller than the threshold should not generate events */
162
	test_2fg_scroll(dev, 0.1, 0.1, true);
163
	litest_assert_empty_queue(li);
164 165 166
}
END_TEST

167
START_TEST(touchpad_2fg_scroll_initially_diagonal)
168 169 170 171 172 173
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;
	int i;
174
	int expected_nevents;
175 176 177
	double w, h;
	double ratio;
	double ydelta;
178 179 180 181

	if (!litest_has_2fg_scroll(dev))
		return;

182 183
	ck_assert_int_eq(libinput_device_get_size(dev->libinput_device, &w, &h), 0);
	ratio = w/h;
184 185 186 187 188 189
	litest_enable_2fg_scroll(dev);
	litest_drain_events(li);

	litest_touch_down(dev, 0, 45, 30);
	litest_touch_down(dev, 1, 55, 30);

190
	/* start diagonally */
191 192
	ydelta = 15 * ratio;
	litest_touch_move_two_touches(dev, 45, 30, 55, 30, 15, ydelta, 10);
193 194 195 196 197 198 199 200
	libinput_dispatch(li);
	litest_wait_for_event_of_type(li,
				      LIBINPUT_EVENT_POINTER_AXIS,
				      -1);
	litest_drain_events(li);

	/* get rid of any touch history still adding x deltas sideways */
	for (i = 0; i < 5; i++)
201
		litest_touch_move(dev, 0, 60, 30 + ydelta + (i * ratio));
202 203
	litest_drain_events(li);

204
	/* scroll vertical only and make sure the horiz axis is never set */
205
	expected_nevents = 0;
206 207
	for (i = 6; i < 15; i++) {
		litest_touch_move(dev, 0, 60, 30 + ydelta + i * ratio);
208 209
		expected_nevents++;
	}
210

211 212 213 214
	libinput_dispatch(li);
	event = libinput_get_event(li);

	do {
215 216 217 218 219 220
		ptrev = litest_is_axis_event(event,
				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
				LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
		ck_assert(!libinput_event_pointer_has_axis(ptrev,
				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL));
		libinput_event_destroy(event);
221 222 223 224 225
		event = libinput_get_event(li);
		expected_nevents--;
	} while (event);

	ck_assert_int_eq(expected_nevents, 0);
226 227 228 229 230 231 232

	litest_touch_up(dev, 1);
	litest_touch_up(dev, 0);
	libinput_dispatch(li);
}
END_TEST

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
static bool
is_single_axis_2fg_scroll(struct litest_device *dev,
			   enum libinput_pointer_axis axis)
{
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;
	enum libinput_pointer_axis on_axis = axis;
	enum libinput_pointer_axis off_axis =
		(axis == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) ?
		LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL :
		LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
	bool has_on_axis, has_off_axis;
	bool val = true;

	event = libinput_get_event(li);
	while (event) {
		litest_assert_event_type(event, LIBINPUT_EVENT_POINTER_AXIS);
		ptrev = litest_is_axis_event(event, on_axis,
				LIBINPUT_POINTER_AXIS_SOURCE_FINGER);

		has_on_axis = libinput_event_pointer_has_axis(ptrev, on_axis);
		has_off_axis = libinput_event_pointer_has_axis(ptrev, off_axis);

		if (has_on_axis && has_off_axis) {
			val = (libinput_event_pointer_get_axis_value(ptrev, off_axis) == 0.0);
			break;
		}

		ck_assert(has_on_axis);
		ck_assert(!has_off_axis);

		libinput_event_destroy(event);
		event = libinput_get_event(li);
	}

	libinput_event_destroy(event);
	return val;
}

START_TEST(touchpad_2fg_scroll_axis_lock)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	enum libinput_pointer_axis axis;
	double delta[4][2] = {
		{ 7,  40},
		{ 7, -40},
		{-7,  40},
		{-7, -40}
	};
	/* 10 degrees off from horiz/vert should count as straight */

	if (!litest_has_2fg_scroll(dev))
		return;

	litest_enable_2fg_scroll(dev);
	litest_drain_events(li);

	axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
	for (int i = 0; i < 4; i++) {
		test_2fg_scroll(dev, delta[i][0], delta[i][1], false);
		ck_assert(is_single_axis_2fg_scroll(dev, axis));
		litest_assert_empty_queue(li);
	}

	axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
	for (int i = 0; i < 4; i++) {
		test_2fg_scroll(dev, delta[i][1], delta[i][0], false);
		ck_assert(is_single_axis_2fg_scroll(dev, axis));
		litest_assert_empty_queue(li);
	}
}
END_TEST

START_TEST(touchpad_2fg_scroll_axis_lock_switch)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	enum libinput_pointer_axis axis;

	if (!litest_has_2fg_scroll(dev))
		return;

	litest_enable_2fg_scroll(dev);
	litest_drain_events(li);

	litest_touch_down(dev, 0, 20, 20);
	litest_touch_down(dev, 1, 25, 20);

	/* Move roughly straight horizontally for >100ms to set axis lock */
324
	litest_touch_move_two_touches(dev, 20, 20, 25, 20, 55, 10, 15);
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	libinput_dispatch(li);
	litest_wait_for_event_of_type(li,
				      LIBINPUT_EVENT_POINTER_AXIS,
				      -1);

	axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
	ck_assert(is_single_axis_2fg_scroll(dev, axis));
	litest_drain_events(li);

	msleep(200);
	libinput_dispatch(li);

	/* Move roughly vertically for >100ms to switch axis lock. This will
	 * contain some horizontal movement while the lock changes; don't
	 * check for single-axis yet
	 */
341
	litest_touch_move_two_touches(dev, 75, 30, 80, 30, 2, 20, 15);
342 343 344 345 346 347 348
	libinput_dispatch(li);
	litest_wait_for_event_of_type(li,
				      LIBINPUT_EVENT_POINTER_AXIS,
				      -1);
	litest_drain_events(li);

	/* Move some more, roughly vertically, and check new axis lock */
349
	litest_touch_move_two_touches(dev, 77, 50, 82, 50, 1, 40, 15);
350 351 352 353 354 355 356 357 358 359
	libinput_dispatch(li);
	litest_wait_for_event_of_type(li,
				      LIBINPUT_EVENT_POINTER_AXIS,
				      -1);

	axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
	ck_assert(is_single_axis_2fg_scroll(dev, axis));
	litest_drain_events(li);

	/* Move in a clear diagonal direction to ensure the lock releases */
360
	litest_touch_move_two_touches(dev, 78, 90, 83, 90, -60, -60, 20);
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
	libinput_dispatch(li);
	litest_wait_for_event_of_type(li,
				      LIBINPUT_EVENT_POINTER_AXIS,
				      -1);

	axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
	ck_assert(!is_single_axis_2fg_scroll(dev, axis));

	litest_touch_up(dev, 1);
	litest_touch_up(dev, 0);
	libinput_dispatch(li);
	litest_drain_events(li);
}
END_TEST

376 377 378 379 380 381
START_TEST(touchpad_2fg_scroll_slow_distance)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;
382 383
	double width, height;
	double y_move = 100;
384

385
	if (!litest_has_2fg_scroll(dev))
386 387
		return;

388
	/* We want to move > 5 mm. */
389 390 391 392
	ck_assert_int_eq(libinput_device_get_size(dev->libinput_device,
						  &width,
						  &height), 0);
	y_move = 100.0/height * 7;
393

394
	litest_enable_2fg_scroll(dev);
395 396
	litest_drain_events(li);

397 398
	litest_touch_down(dev, 0, 49, 50);
	litest_touch_down(dev, 1, 51, 50);
399
	litest_touch_move_two_touches(dev, 49, 50, 51, 50, 0, y_move, 100);
400 401 402 403 404 405 406 407 408
	litest_touch_up(dev, 1);
	litest_touch_up(dev, 0);
	libinput_dispatch(li);

	event = libinput_get_event(li);
	ck_assert_notnull(event);

	/* last event is value 0, tested elsewhere */
	while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) {
409
		double axisval;
410 411 412 413
		ck_assert_int_eq(libinput_event_get_type(event),
				 LIBINPUT_EVENT_POINTER_AXIS);
		ptrev = libinput_event_get_pointer_event(event);

414 415 416
		axisval = libinput_event_pointer_get_axis_value(ptrev,
				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
		ck_assert(axisval > 0.0);
417 418 419 420

		/* this is to verify we test the right thing, if the value
		   is greater than scroll.threshold we triggered the wrong
		   condition */
421
		ck_assert(axisval < 5.0);
422 423 424 425 426 427 428 429 430 431

		libinput_event_destroy(event);
		event = libinput_get_event(li);
	}

	litest_assert_empty_queue(li);
	libinput_event_destroy(event);
}
END_TEST

432 433 434 435 436 437 438
START_TEST(touchpad_2fg_scroll_source)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;

439
	if (!litest_has_2fg_scroll(dev))
440 441
		return;

442
	litest_enable_2fg_scroll(dev);
443 444
	litest_drain_events(li);

445
	test_2fg_scroll(dev, 0, 30, false);
446 447 448 449 450 451 452 453 454 455 456 457 458
	litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);

	while ((event = libinput_get_event(li))) {
		ck_assert_int_eq(libinput_event_get_type(event),
				 LIBINPUT_EVENT_POINTER_AXIS);
		ptrev = libinput_event_get_pointer_event(event);
		ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
				 LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
		libinput_event_destroy(event);
	}
}
END_TEST

459 460 461 462 463
START_TEST(touchpad_2fg_scroll_semi_mt)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

464
	if (!litest_has_2fg_scroll(dev))
465 466
		return;

467
	litest_enable_2fg_scroll(dev);
468 469 470 471 472
	litest_drain_events(li);

	litest_touch_down(dev, 0, 20, 20);
	litest_touch_down(dev, 1, 30, 20);
	libinput_dispatch(li);
473 474 475 476
	litest_touch_move_two_touches(dev,
				      20, 20,
				      30, 20,
				      30, 40,
477
				      10);
478 479 480 481 482

	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
}
END_TEST

483 484 485 486 487
START_TEST(touchpad_2fg_scroll_return_to_motion)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

488
	if (!litest_has_2fg_scroll(dev))
489 490
		return;

491
	litest_enable_2fg_scroll(dev);
492 493 494 495
	litest_drain_events(li);

	/* start with motion */
	litest_touch_down(dev, 0, 70, 70);
496
	litest_touch_move_to(dev, 0, 70, 70, 49, 50, 10);
497 498 499
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);

	/* 2fg scroll */
500
	litest_touch_down(dev, 1, 51, 50);
501
	litest_touch_move_two_touches(dev, 49, 50, 51, 50, 0, 20, 5);
502
	litest_touch_up(dev, 1);
503 504 505
	libinput_dispatch(li);
	litest_timeout_finger_switch();
	libinput_dispatch(li);
506 507
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);

508
	litest_touch_move_to(dev, 0, 49, 70, 49, 50, 10);
509 510 511
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);

	/* back to 2fg scroll, lifting the other finger */
512
	litest_touch_down(dev, 1, 51, 50);
513
	litest_touch_move_two_touches(dev, 49, 50, 51, 50, 0, 20, 5);
514
	litest_touch_up(dev, 0);
515 516 517
	libinput_dispatch(li);
	litest_timeout_finger_switch();
	libinput_dispatch(li);
518 519 520
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);

	/* move with second finger */
521
	litest_touch_move_to(dev, 1, 51, 70, 51, 50, 10);
522 523 524 525 526 527 528
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);

	litest_touch_up(dev, 1);
	litest_assert_empty_queue(li);
}
END_TEST

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
START_TEST(touchpad_2fg_scroll_from_btnareas)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	if (!litest_has_2fg_scroll(dev) ||
	    !litest_has_btnareas(dev))
		return;

	litest_enable_2fg_scroll(dev);
	litest_enable_buttonareas(dev);
	litest_drain_events(li);

	litest_touch_down(dev, 0, 30, 95);
	litest_touch_down(dev, 1, 50, 95);
	libinput_dispatch(li);

	/* First finger moves out of the area first but it's a scroll
	 * motion, should not trigger POINTER_MOTION */
	for (int i = 0; i < 5; i++) {
		litest_touch_move(dev, 0, 30, 95 - i);
	}
	libinput_dispatch(li);

	for (int i = 0; i < 20; i++) {
		litest_touch_move(dev, 0, 30, 90 - i);
555
		litest_touch_move(dev, 1, 50, 95 - i);
556 557 558 559 560 561 562 563 564 565
	}
	libinput_dispatch(li);

	litest_touch_up(dev, 0);
	litest_touch_up(dev, 1);

	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
}
END_TEST

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
START_TEST(touchpad_scroll_natural_defaults)
{
	struct litest_device *dev = litest_current_device();

	ck_assert_int_ge(libinput_device_config_scroll_has_natural_scroll(dev->libinput_device), 1);
	ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 0);
	ck_assert_int_eq(libinput_device_config_scroll_get_default_natural_scroll_enabled(dev->libinput_device), 0);
}
END_TEST

START_TEST(touchpad_scroll_natural_enable_config)
{
	struct litest_device *dev = litest_current_device();
	enum libinput_config_status status;

	status = libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);
	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
	ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 1);

	status = libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 0);
	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
	ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 0);
}
END_TEST

591
START_TEST(touchpad_scroll_natural_2fg)
592 593 594 595
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

596
	if (!litest_has_2fg_scroll(dev))
597 598
		return;

599
	litest_enable_2fg_scroll(dev);
600 601 602 603
	litest_drain_events(li);

	libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);

604
	test_2fg_scroll(dev, 0.1, 40, false);
605
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -9);
606
	test_2fg_scroll(dev, 0.1, -40, false);
607
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 9);
608
	test_2fg_scroll(dev, 40, 0.1, false);
609
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
610
	test_2fg_scroll(dev, -40, 0.1, false);
611
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 9);
612 613 614 615

}
END_TEST

616 617 618 619 620 621 622 623 624 625 626
START_TEST(touchpad_scroll_natural_edge)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	litest_enable_edge_scroll(dev);
	litest_drain_events(li);

	libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);

	litest_touch_down(dev, 0, 99, 20);
627
	litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10);
628 629 630 631 632 633 634
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -4);
	litest_assert_empty_queue(li);

	litest_touch_down(dev, 0, 99, 80);
635
	litest_touch_move_to(dev, 0, 99, 80, 99, 20, 10);
636 637 638 639 640 641 642 643 644
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 4);
	litest_assert_empty_queue(li);

}
END_TEST

645
START_TEST(touchpad_edge_scroll_vert)
646 647 648 649
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

650
	litest_touch_down(dev, 0, 99, 20);
651
	litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10);
652 653
	litest_touch_up(dev, 0);

654
	litest_drain_events(li);
655
	litest_enable_edge_scroll(dev);
656 657

	litest_touch_down(dev, 0, 99, 20);
658
	litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10);
659 660 661
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
662
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 4);
663 664 665
	litest_assert_empty_queue(li);

	litest_touch_down(dev, 0, 99, 80);
666
	litest_touch_move_to(dev, 0, 99, 80, 99, 20, 10);
667 668 669
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
670
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -4);
671
	litest_assert_empty_queue(li);
672 673 674
}
END_TEST

675 676 677 678 679 680 681 682
static int
touchpad_has_horiz_edge_scroll_size(struct litest_device *dev)
{
	double width, height;
	int rc;

	rc = libinput_device_get_size(dev->libinput_device, &width, &height);

683
	return rc == 0 && height >= 40;
684 685
}

686 687 688 689 690
START_TEST(touchpad_edge_scroll_horiz)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

691
	litest_touch_down(dev, 0, 99, 20);
692
	litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10);
693 694
	litest_touch_up(dev, 0);

695 696 697
	if (!touchpad_has_horiz_edge_scroll_size(dev))
		return;

698 699
	litest_drain_events(li);
	litest_enable_edge_scroll(dev);
700 701

	litest_touch_down(dev, 0, 20, 99);
702
	litest_touch_move_to(dev, 0, 20, 99, 70, 99, 10);
703 704 705
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
706
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 4);
707 708 709
	litest_assert_empty_queue(li);

	litest_touch_down(dev, 0, 70, 99);
710
	litest_touch_move_to(dev, 0, 70, 99, 20, 99, 10);
711 712 713
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
714
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -4);
715 716 717 718
	litest_assert_empty_queue(li);
}
END_TEST

719 720 721 722 723 724 725 726 727
START_TEST(touchpad_edge_scroll_horiz_clickpad)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	litest_drain_events(li);
	litest_enable_edge_scroll(dev);

	litest_touch_down(dev, 0, 20, 99);
728
	litest_touch_move_to(dev, 0, 20, 99, 70, 99, 10);
729 730 731 732 733 734 735
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 4);
	litest_assert_empty_queue(li);

	litest_touch_down(dev, 0, 70, 99);
736
	litest_touch_move_to(dev, 0, 70, 99, 20, 99, 10);
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
	litest_touch_up(dev, 0);

	libinput_dispatch(li);
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -4);
	litest_assert_empty_queue(li);
}
END_TEST

START_TEST(touchpad_edge_scroll_no_horiz)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	if (touchpad_has_horiz_edge_scroll_size(dev))
		return;

	litest_drain_events(li);
	litest_enable_edge_scroll(dev);

	litest_touch_down(dev, 0, 20, 99);
757
	litest_touch_move_to(dev, 0, 20, 99, 70, 99, 10);
758 759 760 761 762
	litest_touch_up(dev, 0);

	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);

	litest_touch_down(dev, 0, 70, 99);
763
	litest_touch_move_to(dev, 0, 70, 99, 20, 99, 10);
764 765 766 767 768 769
	litest_touch_up(dev, 0);

	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
}
END_TEST

770 771 772 773 774 775 776
START_TEST(touchpad_scroll_defaults)
{
	struct litest_device *dev = litest_current_device();
	struct libinput_device *device = dev->libinput_device;
	struct libevdev *evdev = dev->evdev;
	enum libinput_config_scroll_method method, expected;
	enum libinput_config_status status;
777 778 779 780 781 782
	bool should_have_2fg = false;

	if (libevdev_get_num_slots(evdev) > 1 ||
	    (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_APPLE &&
	     libevdev_get_id_product(dev->evdev) == PRODUCT_ID_APPLE_APPLETOUCH))
		should_have_2fg = true;
783 784 785

	method = libinput_device_config_scroll_get_methods(device);
	ck_assert(method & LIBINPUT_CONFIG_SCROLL_EDGE);
786
	if (should_have_2fg)
787
		ck_assert(method & LIBINPUT_CONFIG_SCROLL_2FG);
788 789
	else
		ck_assert((method & LIBINPUT_CONFIG_SCROLL_2FG) == 0);
790

791
	if (should_have_2fg)
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
		expected = LIBINPUT_CONFIG_SCROLL_2FG;
	else
		expected = LIBINPUT_CONFIG_SCROLL_EDGE;

	method = libinput_device_config_scroll_get_method(device);
	ck_assert_int_eq(method, expected);
	method = libinput_device_config_scroll_get_default_method(device);
	ck_assert_int_eq(method, expected);

	status = libinput_device_config_scroll_set_method(device,
					  LIBINPUT_CONFIG_SCROLL_EDGE);
	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
	status = libinput_device_config_scroll_set_method(device,
					  LIBINPUT_CONFIG_SCROLL_2FG);

807
	if (should_have_2fg)
808 809 810 811 812 813
		ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
	else
		ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST

814
START_TEST(touchpad_edge_scroll_timeout)
815 816 817 818 819
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;
820
	double width = 0, height = 0;
821 822 823 824 825 826 827 828 829 830 831 832 833 834
	int nevents = 0;
	double mm; /* one mm in percent of the device */

	ck_assert_int_eq(libinput_device_get_size(dev->libinput_device,
						  &width,
						  &height), 0);
	mm = 100.0/height;

	/* timeout-based scrolling is disabled when software buttons are
	 * active, so switch to clickfinger. Not all test devices support
	 * that, hence the extra check. */
	if (libinput_device_config_click_get_methods(dev->libinput_device) &
	    LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER)
		litest_enable_clickfinger(dev);
835 836

	litest_drain_events(li);
837
	litest_enable_edge_scroll(dev);
838

839 840
	/* move 0.5mm, enough to load up the motion history, but less than
	 * the scroll threshold of 2mm */
841
	litest_touch_down(dev, 0, 99, 20);
842 843 844 845
	libinput_dispatch(li);
	litest_timeout_hysteresis();
	libinput_dispatch(li);

846
	litest_touch_move_to(dev, 0, 99, 20, 99, 20 + mm/2, 8);
847
	libinput_dispatch(li);
848 849
	litest_assert_empty_queue(li);

850 851 852
	litest_timeout_edgescroll();
	libinput_dispatch(li);

853 854 855
	litest_assert_empty_queue(li);

	/* now move slowly up to the 2mm scroll threshold. we expect events */
856
	litest_touch_move_to(dev, 0, 99, 20 + mm/2, 99, 20 + mm * 2, 20);
857 858 859
	litest_touch_up(dev, 0);
	libinput_dispatch(li);

860 861
	litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);

862 863 864 865 866 867 868 869 870
	while ((event = libinput_get_event(li))) {
		double value;

		ptrev = litest_is_axis_event(event,
					     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
					     0);
		value = libinput_event_pointer_get_axis_value(ptrev,
							      LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
		ck_assert_double_lt(value, 5.0);
871
		libinput_event_destroy(event);
872
		nevents++;
873 874
	}

875 876 877 878
	/* we sent 20 events but allow for some to be swallowed by rounding
	 * errors, the hysteresis, etc. */
	ck_assert_int_ge(nevents, 10);

879 880 881 882 883 884 885 886 887 888 889
	litest_assert_empty_queue(li);
	libinput_event_destroy(event);
}
END_TEST

START_TEST(touchpad_edge_scroll_no_motion)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	litest_drain_events(li);
890
	litest_enable_edge_scroll(dev);
891

892
	litest_touch_down(dev, 0, 99, 10);
893
	litest_touch_move_to(dev, 0, 99, 10, 99, 70, 12);
894
	/* moving outside -> no motion event */
895
	litest_touch_move_to(dev, 0, 99, 70, 20, 70, 12);
896
	/* moving down outside edge once scrolling had started -> scroll */
897
	litest_touch_move_to(dev, 0, 20, 70, 40, 99, 12);
898 899 900
	litest_touch_up(dev, 0);
	libinput_dispatch(li);

901
	litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 4);
902 903 904 905 906 907 908 909 910 911
	litest_assert_empty_queue(li);
}
END_TEST

START_TEST(touchpad_edge_scroll_no_edge_after_motion)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	litest_drain_events(li);
912
	litest_enable_edge_scroll(dev);
913 914 915

	/* moving into the edge zone must not trigger scroll events */
	litest_touch_down(dev, 0, 20, 20);
916 917
	litest_touch_move_to(dev, 0, 20, 20, 99, 20, 22);
	litest_touch_move_to(dev, 0, 99, 20, 99, 80, 22);
918 919 920 921 922 923 924 925
	litest_touch_up(dev, 0);
	libinput_dispatch(li);

	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
	litest_assert_empty_queue(li);
}
END_TEST

926 927 928 929 930 931 932 933
START_TEST(touchpad_edge_scroll_source)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;

	litest_drain_events(li);
934
	litest_enable_edge_scroll(dev);
935 936

	litest_touch_down(dev, 0, 99, 20);
937
	litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10);
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
	litest_touch_up(dev, 0);

	litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);

	while ((event = libinput_get_event(li))) {
		ck_assert_int_eq(libinput_event_get_type(event),
				 LIBINPUT_EVENT_POINTER_AXIS);
		ptrev = libinput_event_get_pointer_event(event);
		ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
				 LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
		libinput_event_destroy(event);
	}
}
END_TEST

953 954 955 956 957 958
START_TEST(touchpad_edge_scroll_no_2fg)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

	litest_drain_events(li);
959
	litest_enable_edge_scroll(dev);
960

961 962
	litest_touch_down(dev, 0, 49, 50);
	litest_touch_down(dev, 1, 51, 50);
963
	litest_touch_move_two_touches(dev, 49, 50, 51, 50, 20, 30, 10);
964 965 966 967 968 969 970 971 972
	libinput_dispatch(li);
	litest_touch_up(dev, 0);
	litest_touch_up(dev, 1);
	libinput_dispatch(li);

	litest_assert_empty_queue(li);
}
END_TEST

973 974 975 976 977
START_TEST(touchpad_edge_scroll_into_buttonareas)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

978 979
	litest_enable_buttonareas(dev);
	litest_enable_edge_scroll(dev);
980 981 982
	litest_drain_events(li);

	litest_touch_down(dev, 0, 99, 40);
983
	litest_touch_move_to(dev, 0, 99, 40, 99, 95, 10);
984
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
985
	/* in the button zone now, make sure we still get events */
986
	litest_touch_move_to(dev, 0, 99, 95, 99, 100, 10);
987
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
988 989

	/* and out of the zone again */
990
	litest_touch_move_to(dev, 0, 99, 100, 99, 70, 10);
991
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
992 993

	/* still out of the zone */
994
	litest_touch_move_to(dev, 0, 99, 70, 99, 50, 10);
995
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
996 997 998 999 1000 1001 1002 1003
}
END_TEST

START_TEST(touchpad_edge_scroll_within_buttonareas)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

1004 1005 1006
	if (!touchpad_has_horiz_edge_scroll_size(dev))
		return;

1007 1008
	litest_enable_buttonareas(dev);
	litest_enable_edge_scroll(dev);
1009 1010 1011 1012 1013
	litest_drain_events(li);

	litest_touch_down(dev, 0, 20, 99);

	/* within left button */
1014
	litest_touch_move_to(dev, 0, 20, 99, 40, 99, 10);
1015
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
1016 1017

	/* over to right button */
1018
	litest_touch_move_to(dev, 0, 40, 99, 60, 99, 10);
1019
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
1020 1021

	/* within right button */
1022
	litest_touch_move_to(dev, 0, 60, 99, 80, 99, 10);
1023
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
}
END_TEST

START_TEST(touchpad_edge_scroll_buttonareas_click_stops_scroll)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;
	double val;

1035 1036 1037
	if (!touchpad_has_horiz_edge_scroll_size(dev))
		return;

1038 1039
	litest_enable_buttonareas(dev);
	litest_enable_edge_scroll(dev);
1040 1041 1042
	litest_drain_events(li);

	litest_touch_down(dev, 0, 20, 95);
1043
	litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10);
1044
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
1045

1046
	litest_button_click(dev, BTN_LEFT, true);
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
	libinput_dispatch(li);

	event = libinput_get_event(li);
	ptrev = litest_is_axis_event(event,
				     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
				     LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
	val = libinput_event_pointer_get_axis_value(ptrev,
				    LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
	ck_assert(val == 0.0);
	libinput_event_destroy(event);

	event = libinput_get_event(li);
1059 1060 1061
	litest_is_button_event(event,
			       BTN_RIGHT,
			       LIBINPUT_BUTTON_STATE_PRESSED);
1062 1063 1064

	libinput_event_destroy(event);

1065 1066 1067 1068 1069 1070 1071
	/* move within button areas but we cancelled the scroll so now we
	 * get pointer motion events when moving.
	 *
	 * This is not ideal behavior, but the use-case of horizontal
	 * edge scrolling, click, then scrolling without lifting the finger
	 * is so small we'll let it pass.
	 */
1072
	litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10);
1073
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
1074

1075
	litest_button_click(dev, BTN_LEFT, false);
1076

1077
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090

	litest_touch_up(dev, 0);
}
END_TEST

START_TEST(touchpad_edge_scroll_clickfinger_click_stops_scroll)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;
	struct libinput_event *event;
	struct libinput_event_pointer *ptrev;
	double val;

1091 1092 1093
	if (!touchpad_has_horiz_edge_scroll_size(dev))
		return;

1094 1095
	litest_enable_clickfinger(dev);
	litest_enable_edge_scroll(dev);
1096 1097 1098
	litest_drain_events(li);

	litest_touch_down(dev, 0, 20, 95);
1099
	litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10);
1100
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
1101

1102
	litest_button_click(dev, BTN_LEFT, true);
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
	libinput_dispatch(li);

	event = libinput_get_event(li);
	ptrev = litest_is_axis_event(event,
				     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
				     LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
	val = libinput_event_pointer_get_axis_value(ptrev,
				    LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
	ck_assert(val == 0.0);
	libinput_event_destroy(event);

	event = libinput_get_event(li);
1115 1116 1117
	litest_is_button_event(event,
			       BTN_LEFT,
			       LIBINPUT_BUTTON_STATE_PRESSED);
1118 1119 1120 1121

	libinput_event_destroy(event);

	/* clickfinger releases pointer -> expect movement */
1122
	litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10);
1123
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
1124 1125
	litest_assert_empty_queue(li);

1126
	litest_button_click(dev, BTN_LEFT, false);
1127

1128
	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
1129 1130 1131 1132 1133

	litest_touch_up(dev, 0);
}
END_TEST

1134 1135 1136 1137 1138
START_TEST(touchpad_edge_scroll_into_area)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

1139
	litest_enable_edge_scroll(dev);
1140 1141 1142 1143 1144
	litest_drain_events(li);

	/* move into area, move vertically, move back to edge */

	litest_touch_down(dev, 0, 99, 20);
1145 1146
	litest_touch_move_to(dev, 0, 99, 20, 99, 50, 15);
	litest_touch_move_to(dev, 0, 99, 50, 20, 50, 15);
1147 1148
	litest_assert_only_typed_events(li,
					LIBINPUT_EVENT_POINTER_AXIS);
1149 1150
	litest_touch_move_to(dev, 0, 20, 50, 20, 20, 15);
	litest_touch_move_to(dev, 0, 20, 20, 99, 20, 15);
1151 1152
	litest_assert_empty_queue(li);

1153
	litest_touch_move_to(dev, 0, 99, 20, 99, 50, 15);
1154 1155 1156 1157 1158
	litest_assert_only_typed_events(li,
					LIBINPUT_EVENT_POINTER_AXIS);
}
END_TEST

1159 1160 1161 1162 1163 1164
static bool
touchpad_has_top_palm_detect_size(struct litest_device *dev)
{
	double width, height;
	int rc;

1165
	if (!litest_has_palm_detect_size(dev))
1166 1167 1168 1169 1170 1171 1172
		return false;

	rc = libinput_device_get_size(dev->libinput_device, &width, &height);

	return rc == 0 && height > 55;
}

1173 1174 1175 1176 1177
START_TEST(touchpad_palm_detect_at_edge)
{
	struct litest_device *dev = litest_current_device();
	struct libinput *li = dev->libinput;

1178
	if (!litest_has_palm_detect_size(dev) ||
1179
	    !litest_has_2fg_scroll(dev))
1180 1181
		return;

1182
	litest_enable_2fg_scroll(dev);
1183