evdev-mt-touchpad.h 17 KB
Newer Older
1
/*
Peter Hutterer's avatar
Peter Hutterer committed
2
 * Copyright © 2014-2015 Red Hat, Inc.
3
 *
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
 */

#ifndef EVDEV_MT_TOUCHPAD_H
#define EVDEV_MT_TOUCHPAD_H

#include <stdbool.h>

#include "evdev.h"
30
#include "timer.h"
31 32

#define TOUCHPAD_HISTORY_LENGTH 4
33
#define TOUCHPAD_MIN_SAMPLES 4
34

35
/* Convert mm to a distance normalized to DEFAULT_MOUSE_DPI */
36
#define TP_MM_TO_DPI_NORMALIZED(mm) (DEFAULT_MOUSE_DPI/25.4 * mm)
37

38 39
enum touchpad_event {
	TOUCHPAD_EVENT_NONE		= 0,
Peter Hutterer's avatar
Peter Hutterer committed
40 41 42 43 44
	TOUCHPAD_EVENT_MOTION		= bit(0),
	TOUCHPAD_EVENT_BUTTON_PRESS	= bit(1),
	TOUCHPAD_EVENT_BUTTON_RELEASE	= bit(2),
	TOUCHPAD_EVENT_OTHERAXIS	= bit(3),
	TOUCHPAD_EVENT_TIMESTAMP	= bit(4),
45 46
};

47 48
enum touch_state {
	TOUCH_NONE = 0,
49 50 51 52 53
	TOUCH_HOVERING = 1,
	TOUCH_BEGIN = 2,
	TOUCH_UPDATE = 3,
	TOUCH_MAYBE_END = 4,
	TOUCH_END = 5,
54 55
};

56 57 58
enum touch_palm_state {
	PALM_NONE = 0,
	PALM_EDGE,
59
	PALM_TYPING,
60
	PALM_TRACKPOINT,
61
	PALM_TOOL_PALM,
62
	PALM_PRESSURE,
63
	PALM_TOUCH_SIZE,
64
	PALM_ARBITRATION,
65 66
};

67
enum button_event {
68
	BUTTON_EVENT_IN_BOTTOM_R = 30,
69
	BUTTON_EVENT_IN_BOTTOM_M,
70 71 72 73 74 75 76 77 78
	BUTTON_EVENT_IN_BOTTOM_L,
	BUTTON_EVENT_IN_TOP_R,
	BUTTON_EVENT_IN_TOP_M,
	BUTTON_EVENT_IN_TOP_L,
	BUTTON_EVENT_IN_AREA,
	BUTTON_EVENT_UP,
	BUTTON_EVENT_PRESS,
	BUTTON_EVENT_RELEASE,
	BUTTON_EVENT_TIMEOUT,
79 80 81
};

enum button_state {
82 83 84 85 86 87 88
	BUTTON_STATE_NONE,
	BUTTON_STATE_AREA,
	BUTTON_STATE_BOTTOM,
	BUTTON_STATE_TOP,
	BUTTON_STATE_TOP_NEW,
	BUTTON_STATE_TOP_TO_IGNORE,
	BUTTON_STATE_IGNORE,
89 90
};

91 92 93 94 95 96 97
enum tp_tap_state {
	TAP_STATE_IDLE = 4,
	TAP_STATE_TOUCH,
	TAP_STATE_HOLD,
	TAP_STATE_TAPPED,
	TAP_STATE_TOUCH_2,
	TAP_STATE_TOUCH_2_HOLD,
98
	TAP_STATE_TOUCH_2_RELEASE,
99 100 101
	TAP_STATE_TOUCH_3,
	TAP_STATE_TOUCH_3_HOLD,
	TAP_STATE_DRAGGING_OR_DOUBLETAP,
102
	TAP_STATE_DRAGGING_OR_TAP,
103 104 105 106 107 108
	TAP_STATE_DRAGGING,
	TAP_STATE_DRAGGING_WAIT,
	TAP_STATE_DRAGGING_2,
	TAP_STATE_DEAD, /**< finger count exceeded */
};

109 110 111 112 113 114
enum tp_tap_touch_state {
	TAP_TOUCH_STATE_IDLE = 16,	/**< not in touch */
	TAP_TOUCH_STATE_TOUCH,		/**< touching, may tap */
	TAP_TOUCH_STATE_DEAD,		/**< exceeded motion/timeout */
};

115 116
/* For edge scrolling, so we only care about right and bottom */
enum tp_edge {
Peter Hutterer's avatar
Peter Hutterer committed
117 118 119
	EDGE_NONE	= 0,
	EDGE_RIGHT	= bit(0),
	EDGE_BOTTOM	= bit(1),
120 121 122 123 124 125 126 127 128
};

enum tp_edge_scroll_touch_state {
	EDGE_SCROLL_TOUCH_STATE_NONE,
	EDGE_SCROLL_TOUCH_STATE_EDGE_NEW,
	EDGE_SCROLL_TOUCH_STATE_EDGE,
	EDGE_SCROLL_TOUCH_STATE_AREA,
};

129 130 131 132 133
enum tp_gesture_state {
	GESTURE_STATE_NONE,
	GESTURE_STATE_UNKNOWN,
	GESTURE_STATE_SCROLL,
	GESTURE_STATE_PINCH,
134
	GESTURE_STATE_SWIPE,
135 136
};

137
enum tp_thumb_state {
138 139 140 141 142 143 144
	THUMB_STATE_FINGER,
	THUMB_STATE_JAILED,
	THUMB_STATE_PINCH,
	THUMB_STATE_SUPPRESSED,
	THUMB_STATE_REVIVED,
	THUMB_STATE_REVIVED_JAILED,
	THUMB_STATE_DEAD,
145 146
};

147 148 149 150 151 152
enum tp_jump_state {
	JUMP_STATE_IGNORE = 0,
	JUMP_STATE_EXPECT_FIRST,
	JUMP_STATE_EXPECT_DELAY,
};

153
struct tp_touch {
154
	struct tp_dispatch *tp;
155
	unsigned int index;
156
	enum touch_state state;
157
	bool has_ended;				/* TRACKING_ID == -1 */
158
	bool dirty;
159
	struct device_coords point;
160
	uint64_t time;
161
	uint64_t initial_time;
162
	int pressure;
163
	bool is_tool_palm; /* MT_TOOL_PALM */
164
	int major, minor;
165

166 167 168
	bool was_down; /* if distance == 0, false for pure hovering
			  touches */

169 170 171 172 173 174 175 176 177
	struct {
		/* A quirk mostly used on Synaptics touchpads. In a
		   transition to/from fake touches > num_slots, the current
		   event data is likely garbage and the subsequent event
		   is likely too. This marker tells us to reset the motion
		   history again -> this effectively swallows any motion */
		bool reset_motion_history;
	} quirks;

178
	struct {
179 180 181 182
		struct tp_history_point {
			uint64_t time;
			struct device_coords point;
		} samples[TOUCHPAD_HISTORY_LENGTH];
183 184 185 186
		unsigned int index;
		unsigned int count;
	} history;

187 188 189 190
	struct {
		double last_delta_mm;
	} jumps;

191 192
	struct {
		struct device_coords center;
193
		uint8_t x_motion_history;
194
	} hysteresis;
195 196 197 198 199 200 201

	/* A pinned touchpoint is the one that pressed the physical button
	 * on a clickpad. After the release, it won't move until the center
	 * moves more than a threshold away from the original coordinates
	 */
	struct {
		bool is_pinned;
202
		struct device_coords center;
203
	} pinned;
204 205 206 207 208

	/* Software-button state and timeout if applicable */
	struct {
		enum button_state state;
		/* We use button_event here so we can use == on events */
209
		enum button_event current;
210
		struct libinput_timer timer;
211 212
		struct device_coords initial;
		bool has_moved; /* has moved more than threshold */
213
		uint64_t initial_time;
214
	} button;
215 216 217

	struct {
		enum tp_tap_touch_state state;
218
		struct device_coords initial;
219
		bool is_thumb;
220
		bool is_palm;
221
	} tap;
222

223
	struct {
224
		enum tp_edge_scroll_touch_state edge_state;
225 226 227
		uint32_t edge;
		int direction;
		struct libinput_timer timer;
228
		struct device_coords initial;
229 230
	} scroll;

231
	struct {
232
		enum touch_palm_state state;
233
		struct device_coords first; /* first coordinates if is_palm == true */
234
		uint64_t time; /* first timestamp if is_palm == true */
235
	} palm;
236 237 238 239

	struct {
		struct device_coords initial;
	} gesture;
240

241 242 243 244
	struct {
		double last_speed; /* speed in mm/s at last sample */
		unsigned int exceeded_count;
	} speed;
245 246
};

247 248 249 250 251 252 253 254
enum suspend_trigger {
	SUSPEND_NO_FLAG         = 0x0,
	SUSPEND_EXTERNAL_MOUSE  = 0x1,
	SUSPEND_SENDEVENTS      = 0x2,
	SUSPEND_LID             = 0x4,
	SUSPEND_TABLET_MODE     = 0x8,
};

255 256 257 258
struct tp_dispatch {
	struct evdev_dispatch base;
	struct evdev_device *device;
	unsigned int nfingers_down;		/* number of fingers down */
259
	unsigned int old_nfingers_down;		/* previous no fingers down */
260
	unsigned int slot;			/* current slot */
261
	bool has_mt;
262
	bool semi_mt;
263

264 265
	uint32_t suspend_reason;

266 267
	/* pen/touch arbitration */
	struct {
268
		enum evdev_arbitration_state state;
269 270
		struct libinput_timer arbitration_timer;
	} arbitration;
Peter Hutterer's avatar
Peter Hutterer committed
271

272
	unsigned int nactive_slots;		/* number of active slots */
273
	unsigned int num_slots;			/* number of slots */
274
	unsigned int ntouches;			/* no slots inc. fakes */
275
	struct tp_touch *touches;		/* len == ntouches */
276 277 278 279 280 281
	/* bit 0: BTN_TOUCH
	 * bit 1: BTN_TOOL_FINGER
	 * bit 2: BTN_TOOL_DOUBLETAP
	 * ...
	 */
	unsigned int fake_touches;
282

283 284 285 286
	struct {
		struct ratelimit warning;
	} jump;

287 288 289 290 291 292 293 294
	/* if pressure goes above high -> touch down,
	   if pressure then goes below low -> touch up */
	struct {
		bool use_pressure;
		int high;
		int low;
	} pressure;

295 296 297 298 299 300 301 302 303 304 305
	/* If touch size (either axis) goes above high -> touch down,
	   if touch size (either axis) goes below low -> touch up */
	struct  {
		bool use_touch_size;
		int high;
		int low;

		/* convert device units to angle */
		double orientation_to_angle;
	} touch_size;

306
	struct {
307
		bool enabled;
308
		struct device_coords margin;
309 310
		unsigned int other_event_count;
		uint64_t last_motion_time;
311
	} hysteresis;
312 313

	struct {
314 315
		double x_scale_coeff;
		double y_scale_coeff;
316
		double xy_scale_coeff;
317
	} accel;
318

319
	struct {
320
		bool enabled;
321 322 323 324
		bool started;
		unsigned int finger_count;
		unsigned int finger_count_pending;
		struct libinput_timer finger_count_switch_timer;
325
		enum tp_gesture_state state;
326 327 328 329 330 331
		struct tp_touch *touches[2];
		uint64_t initial_time;
		double initial_distance;
		double prev_scale;
		double angle;
		struct device_float_coords center;
332 333
	} gesture;

334
	struct {
335
		bool is_clickpad;		/* true for clickpads */
336
		bool has_topbuttons;
337
		bool use_clickfinger;		/* number of fingers decides button number */
338
		bool click_pending;
339 340
		uint32_t state;
		uint32_t old_state;
341 342 343 344
		struct {
			double x_scale_coeff;
			double y_scale_coeff;
		} motion_dist;			/* for pinned touches */
345
		unsigned int active;		/* currently active button, for release event */
346
		bool active_is_topbutton;	/* is active a top button? */
347

348 349 350
		/* Only used for clickpads. The software button areas are
		 * always 2 horizontal stripes across the touchpad.
		 * The buttons are split according to the edge settings.
351
		 */
352
		struct {
353 354
			int32_t top_edge;	/* in device coordinates */
			int32_t rightbutton_left_edge; /* in device coordinates */
355
			int32_t middlebutton_left_edge; /* in device coordinates */
356
		} bottom_area;
357

358
		struct {
359 360 361
			int32_t bottom_edge;	/* in device coordinates */
			int32_t rightbutton_left_edge; /* in device coordinates */
			int32_t leftbutton_right_edge; /* in device coordinates */
362
		} top_area;
363 364

		struct evdev_device *trackpoint;
365 366 367 368

		enum libinput_config_click_method click_method;
		struct libinput_device_config_click_method config_method;
	} buttons;
369

370
	struct {
371 372
		struct libinput_device_config_scroll_method config_method;
		enum libinput_config_scroll_method method;
373 374
		int32_t right_edge;		/* in device coordinates */
		int32_t bottom_edge;		/* in device coordinates */
375 376 377 378 379 380 381 382
		struct {
			bool h, v;
		} active;
		struct phys_coords vector;
		uint64_t time_prev;
		struct {
			uint64_t h, v;
		} duration;
383 384
	} scroll;

385
	enum touchpad_event queued;
386 387

	struct {
388
		struct libinput_device_config_tap config;
389
		bool enabled;
390
		bool suspended;
391
		struct libinput_timer timer;
392
		enum tp_tap_state state;
393
		uint32_t buttons_pressed;
394 395
		uint64_t saved_press_time,
			 saved_release_time;
396

397 398 399
		enum libinput_config_tap_button_map map;
		enum libinput_config_tap_button_map want_map;

400
		bool drag_enabled;
401
		bool drag_lock_enabled;
402 403

		unsigned int nfingers_down;	/* number of fingers down for tapping (excl. thumb/palm) */
404
	} tap;
405 406

	struct {
407 408
		int32_t right_edge;		/* in device coordinates */
		int32_t left_edge;		/* in device coordinates */
409
		int32_t upper_edge;		/* in device coordinates */
410 411 412 413

		bool trackpoint_active;
		struct libinput_event_listener trackpoint_listener;
		struct libinput_timer trackpoint_timer;
414
		uint64_t trackpoint_last_event_time;
415
		uint32_t trackpoint_event_count;
416
		bool monitor_trackpoint;
417 418

		bool use_mt_tool;
419 420 421

		bool use_pressure;
		int pressure_threshold;
422 423 424

		bool use_size;
		int size_threshold;
425
	} palm;
426 427 428 429

	struct {
		struct libinput_device_config_send_events config;
		enum libinput_config_send_events_mode current_mode;
430
	} sendevents;
431

432
	struct {
433 434 435
		struct libinput_device_config_dwt config;
		bool dwt_enabled;

436 437 438 439 440
		/* We have to allow for more than one device node to be the
		 * internal dwt keyboard (Razer Blade). But they're the same
		 * physical device, so we don't care about per-keyboard
		 * key/modifier masks.
		 */
441
		struct list paired_keyboard_list;
442

443
		unsigned long key_mask[NLONGS(KEY_CNT)];
444
		unsigned long mod_mask[NLONGS(KEY_CNT)];
445 446
		bool keyboard_active;
		struct libinput_timer keyboard_timer;
447
		uint64_t keyboard_last_press_time;
448
	} dwt;
449 450 451

	struct {
		bool detect_thumbs;
452 453
		int upper_thumb_line;
		int lower_thumb_line;
454 455 456

		bool use_pressure;
		int pressure_threshold;
457 458 459

		bool use_size;
		int size_threshold;
460 461 462 463

		enum tp_thumb_state state;
		unsigned int index;
		bool pinch_eligible;
464
	} thumb;
465 466 467 468 469 470 471 472 473 474

	struct {
		/* A quirk used on the T450 series Synaptics hardware.
		 * Slowly moving the finger causes multiple events with only
		 * ABS_MT_PRESSURE but no x/y information. When the x/y
		 * event comes, it will be a jump of ~20 units. We use the
		 * below to count non-motion events to discard that first
		 * event with the jump.
		 */
		unsigned int nonmotion_event_count;
475 476 477 478 479 480

		struct msc_timestamp {
			enum tp_jump_state state;
			uint32_t interval;
			uint32_t now;
		} msc_timestamp;
481
	} quirks;
482 483

	struct {
484
		struct libinput_event_listener listener;
485 486
		struct evdev_device *lid_switch;
	} lid_switch;
487 488 489 490 491

	struct {
		struct libinput_event_listener listener;
		struct evdev_device *tablet_mode_switch;
	} tablet_mode_switch;
492 493 494

	struct {
		bool rotate;
495 496 497 498 499
		bool want_rotate;

		bool must_rotate; /* true if we should rotate when applicable */
		struct evdev_device *tablet_device;
		bool tablet_left_handed_state;
500
	} left_handed;
501 502
};

503 504 505 506 507
static inline struct tp_dispatch*
tp_dispatch(struct evdev_dispatch *dispatch)
{
	evdev_verify_dispatch_type(dispatch, DISPATCH_TOUCHPAD);

508
	return container_of(dispatch, struct tp_dispatch, base);
509 510
}

511 512 513
#define tp_for_each_touch(_tp, _t) \
	for (unsigned int _i = 0; _i < (_tp)->ntouches && (_t = &(_tp)->touches[_i]); _i++)

514
static inline struct libinput*
515
tp_libinput_context(const struct tp_dispatch *tp)
516
{
517
	return evdev_libinput_context(tp->device);
518 519
}

520
static inline struct normalized_coords
521 522
tp_normalize_delta(const struct tp_dispatch *tp,
		   struct device_float_coords delta)
523
{
524 525
	struct normalized_coords normalized;

526 527
	normalized.x = delta.x * tp->accel.x_scale_coeff;
	normalized.y = delta.y * tp->accel.y_scale_coeff;
528 529

	return normalized;
530 531
}

532 533 534 535 536 537 538 539 540 541 542 543
static inline struct phys_coords
tp_phys_delta(const struct tp_dispatch *tp,
	      struct device_float_coords delta)
{
	struct phys_coords mm;

	mm.x = delta.x / tp->device->abs.absinfo_x->resolution;
	mm.y = delta.y / tp->device->abs.absinfo_y->resolution;

	return mm;
}

544
/**
545 546
 * Takes a set of device coordinates, returns that set of coordinates in the
 * x-axis' resolution.
547 548
 */
static inline struct device_float_coords
549 550
tp_scale_to_xaxis(const struct tp_dispatch *tp,
		  struct device_float_coords delta)
551 552 553
{
	struct device_float_coords raw;

554 555
	raw.x = delta.x;
	raw.y = delta.y * tp->accel.xy_scale_coeff;
556 557 558 559

	return raw;
}

560
struct device_coords
561
tp_get_delta(struct tp_touch *t);
562

563
struct normalized_coords
564
tp_filter_motion(struct tp_dispatch *tp,
565
		 const struct device_float_coords *unaccelerated,
566
		 uint64_t time);
Peter Hutterer's avatar
Peter Hutterer committed
567

568 569
struct normalized_coords
tp_filter_motion_unaccelerated(struct tp_dispatch *tp,
570
			       const struct device_float_coords *unaccelerated,
571
			       uint64_t time);
572

573
bool
574
tp_touch_active(const struct tp_dispatch *tp, const struct tp_touch *t);
575

576 577 578 579
bool
tp_touch_active_for_gesture(const struct tp_dispatch *tp,
			    const struct tp_touch *t);

580
int
581
tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
582

583 584 585
void
tp_tap_post_process_state(struct tp_dispatch *tp);

586
void
587 588
tp_init_tap(struct tp_dispatch *tp);

589
void
590
tp_remove_tap(struct tp_dispatch *tp);
591

592
void
593 594
tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device);

595
void
596 597 598
tp_init_top_softbuttons(struct tp_dispatch *tp,
			struct evdev_device *device,
			double topbutton_size_mult);
599

600
void
601
tp_remove_buttons(struct tp_dispatch *tp);
602

603
void
604 605
tp_process_button(struct tp_dispatch *tp,
		  const struct input_event *e,
606
		  uint64_t time);
607

608 609 610 611
void
tp_release_all_buttons(struct tp_dispatch *tp,
		       uint64_t time);

612
int
613
tp_post_button_events(struct tp_dispatch *tp, uint64_t time);
614

615
void
616
tp_button_handle_state(struct tp_dispatch *tp, uint64_t time);
617

618
bool
619 620
tp_button_touch_active(const struct tp_dispatch *tp,
		       const struct tp_touch *t);
621

622
bool
623 624
tp_button_is_inside_softbutton_area(const struct tp_dispatch *tp,
				    const struct tp_touch *t);
625

626 627 628 629
void
tp_release_all_taps(struct tp_dispatch *tp,
		    uint64_t time);

630 631 632 633 634 635
void
tp_tap_suspend(struct tp_dispatch *tp, uint64_t time);

void
tp_tap_resume(struct tp_dispatch *tp, uint64_t time);

636
bool
637
tp_tap_dragging(const struct tp_dispatch *tp);
638

639
void
640 641 642
tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device);

void
643
tp_remove_edge_scroll(struct tp_dispatch *tp);
644 645 646 647 648 649 650 651 652 653 654

void
tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time);

int
tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time);

void
tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time);

int
655 656
tp_edge_scroll_touch_active(const struct tp_dispatch *tp,
			    const struct tp_touch *t);
657

658
uint32_t
659
tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t);
660

661
void
662 663 664 665 666 667
tp_init_gesture(struct tp_dispatch *tp);

void
tp_remove_gesture(struct tp_dispatch *tp);

void
668 669 670 671
tp_gesture_stop(struct tp_dispatch *tp, uint64_t time);

void
tp_gesture_cancel(struct tp_dispatch *tp, uint64_t time);
672 673 674 675 676 677 678 679 680 681

void
tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time);

void
tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time);

void
tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time);

682
bool
683
tp_palm_tap_is_palm(const struct tp_dispatch *tp, const struct tp_touch *t);
684

685 686 687
void
tp_clickpad_middlebutton_apply_config(struct evdev_device *device);

688 689 690
bool
tp_thumb_ignored(const struct tp_dispatch *tp, const struct tp_touch *t);

691
void
692 693 694 695 696 697 698 699
tp_thumb_reset(struct tp_dispatch *tp);

bool
tp_thumb_ignored_for_gesture(const struct tp_dispatch *tp, const struct tp_touch *t);

bool
tp_thumb_ignored_for_tap(const struct tp_dispatch *tp,
			 const struct tp_touch *t);
700

701 702 703
void
tp_thumb_suppress(struct tp_dispatch *tp, struct tp_touch *t);

704
void
705 706 707
tp_thumb_update_touch(struct tp_dispatch *tp,
		      struct tp_touch *t,
		      uint64_t time);
708

709 710 711
void
tp_detect_thumb_while_moving(struct tp_dispatch *tp);

712 713 714
void
tp_thumb_update_multifinger(struct tp_dispatch *tp);

715 716 717
void
tp_init_thumb(struct tp_dispatch *tp);

718
#endif