evdev-mt-touchpad.c 87.9 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
 */

#include "config.h"

26
#include <assert.h>
27
#include <math.h>
28
#include <stdbool.h>
29
#include <limits.h>
30

31
#include "quirks.h"
32
#include "evdev-mt-touchpad.h"
33

34
#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT ms2us(300)
35
#define DEFAULT_TRACKPOINT_EVENT_TIMEOUT ms2us(40)
36
37
#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 ms2us(200)
#define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 ms2us(500)
38
#define THUMB_MOVE_TIMEOUT ms2us(300)
39
#define FAKE_FINGER_OVERFLOW (1 << 7)
40
#define THUMB_IGNORE_SPEED_THRESHOLD 20 /* mm/s */
41

42
static inline struct tp_history_point*
43
44
45
46
47
48
49
50
51
tp_motion_history_offset(struct tp_touch *t, int offset)
{
	int offset_index =
		(t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
		TOUCHPAD_HISTORY_LENGTH;

	return &t->history.samples[offset_index];
}

52
struct normalized_coords
53
tp_filter_motion(struct tp_dispatch *tp,
54
		 const struct device_float_coords *unaccelerated,
55
		 uint64_t time)
56
{
57
	struct device_float_coords raw;
58
	const struct normalized_coords zero = { 0.0, 0.0 };
59

60
61
	if (device_float_is_zero(*unaccelerated))
		return zero;
62

63
64
	/* Convert to device units with x/y in the same resolution */
	raw = tp_scale_to_xaxis(tp, *unaccelerated);
65

66
	return filter_dispatch(tp->device->pointer.filter,
67
			       &raw, tp, time);
68
69
}

70
71
struct normalized_coords
tp_filter_motion_unaccelerated(struct tp_dispatch *tp,
72
			       const struct device_float_coords *unaccelerated,
73
74
			       uint64_t time)
{
75
	struct device_float_coords raw;
76
	const struct normalized_coords zero = { 0.0, 0.0 };
77

78
79
	if (device_float_is_zero(*unaccelerated))
		return zero;
80

81
82
	/* Convert to device units with x/y in the same resolution */
	raw = tp_scale_to_xaxis(tp, *unaccelerated);
83

84
	return filter_dispatch_constant(tp->device->pointer.filter,
85
					&raw, tp, time);
86
87
}

88
89
90
91
92
93
94
95
96
static inline void
tp_calculate_motion_speed(struct tp_dispatch *tp, struct tp_touch *t)
{
	const struct tp_history_point *last;
	struct device_coords delta;
	struct phys_coords mm;
	double distance;
	double speed;

97
98
99
100
	/* Don't do this on single-touch or semi-mt devices */
	if (!tp->has_mt || tp->semi_mt)
		return;

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
	/* This doesn't kick in until we have at least 4 events in the
	 * motion history. As a side-effect, this automatically handles the
	 * 2fg scroll where a finger is down and moving fast before the
	 * other finger comes down for the scroll.
	 *
	 * We do *not* reset the speed to 0 here though. The motion history
	 * is reset whenever a new finger is down, so we'd be resetting the
	 * speed and failing.
	 */
	if (t->history.count < 4)
		return;

	/* TODO: we probably need a speed history here so we can average
	 * across a few events */
	last = tp_motion_history_offset(t, 1);
	delta.x = abs(t->point.x - last->point.x);
	delta.y = abs(t->point.y - last->point.y);
	mm = evdev_device_unit_delta_to_mm(tp->device, &delta);

	distance = length_in_mm(mm);
	speed = distance/(t->time - last->time); /* mm/us */
	speed *= 1000000; /* mm/s */

	t->speed.last_speed = speed;
}

127
128
129
130
131
132
133
134
static inline void
tp_motion_history_push(struct tp_touch *t)
{
	int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;

	if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
		t->history.count++;

135
136
	t->history.samples[motion_index].point = t->point;
	t->history.samples[motion_index].time = t->time;
137
138
139
	t->history.index = motion_index;
}

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* Idea: if we got a tuple of *very* quick moves like {Left, Right,
 * Left}, or {Right, Left, Right}, it means touchpad jitters since no
 * human can move like that within thresholds.
 *
 * We encode left moves as zeroes, and right as ones. We also drop
 * the array to all zeroes when contraints are not satisfied. Then we
 * search for the pattern {1,0,1}. It can't match {Left, Right, Left},
 * but it does match {Left, Right, Left, Right}, so it's okay.
 *
 * This only looks at x changes, y changes are ignored.
 */
static inline void
tp_detect_wobbling(struct tp_dispatch *tp,
		   struct tp_touch *t,
		   uint64_t time)
{
	int dx, dy;
	uint64_t dtime;
158
	const struct device_coords* prev_point;
159

160
161
162
163
	if (tp->nfingers_down != 1 ||
	    tp->nfingers_down != tp->old_nfingers_down)
		return;

164
	if (tp->hysteresis.enabled || t->history.count == 0)
165
166
		return;

167
168
169
170
171
	if (!(tp->queued & TOUCHPAD_EVENT_MOTION)) {
		t->hysteresis.x_motion_history = 0;
		return;
	}

172
173
174
	prev_point = &tp_motion_history_offset(t, 0)->point;
	dx = prev_point->x - t->point.x;
	dy = prev_point->y - t->point.y;
175
176
177
178
	dtime = time - tp->hysteresis.last_motion_time;

	tp->hysteresis.last_motion_time = time;

179
	if ((dx == 0 && dy != 0) || dtime > ms2us(40)) {
180
181
182
183
		t->hysteresis.x_motion_history = 0;
		return;
	}

184
	t->hysteresis.x_motion_history >>= 1;
185
186
187
	if (dx > 0) { /* right move */
		static const char r_l_r = 0x5; /* {Right, Left, Right} */

188
		t->hysteresis.x_motion_history |= (1 << 2);
189
190
		if (t->hysteresis.x_motion_history == r_l_r) {
			tp->hysteresis.enabled = true;
191
192
			evdev_log_debug(tp->device,
					"hysteresis enabled. "
193
					"See %stouchpad-jitter.html for details\n",
194
					HTTP_DOC_LINK);
195
196
197
198
		}
	}
}

199
200
201
202
static inline void
tp_motion_hysteresis(struct tp_dispatch *tp,
		     struct tp_touch *t)
{
203
204
205
	if (!tp->hysteresis.enabled)
		return;

206
207
208
209
210
211
	if (t->history.count > 0)
		t->point = evdev_hysteresis(&t->point,
					    &t->hysteresis.center,
					    &tp->hysteresis.margin);

	t->hysteresis.center = t->point;
212
213
}

214
215
216
217
218
219
220
221
222
static inline void
tp_motion_history_reset(struct tp_touch *t)
{
	t->history.count = 0;
}

static inline struct tp_touch *
tp_current_touch(struct tp_dispatch *tp)
{
223
	return &tp->touches[min(tp->slot, tp->ntouches - 1)];
224
225
}

226
227
228
229
230
231
232
static inline struct tp_touch *
tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
{
	assert(slot < tp->ntouches);
	return &tp->touches[slot];
}

233
234
235
static inline unsigned int
tp_fake_finger_count(struct tp_dispatch *tp)
{
236
237
238
239
	/* Only one of BTN_TOOL_DOUBLETAP/TRIPLETAP/... may be set at any
	 * time */
	if (__builtin_popcount(
		       tp->fake_touches & ~(FAKE_FINGER_OVERFLOW|0x1)) > 1)
240
241
242
		evdev_log_bug_kernel(tp->device,
				     "Invalid fake finger state %#x\n",
				     tp->fake_touches);
243

244
245
246
247
	if (tp->fake_touches & FAKE_FINGER_OVERFLOW)
		return FAKE_FINGER_OVERFLOW;
	else /* don't count BTN_TOUCH */
		return ffs(tp->fake_touches >> 1);
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
}

static inline bool
tp_fake_finger_is_touching(struct tp_dispatch *tp)
{
	return tp->fake_touches & 0x1;
}

static inline void
tp_fake_finger_set(struct tp_dispatch *tp,
		   unsigned int code,
		   bool is_press)
{
	unsigned int shift;

	switch (code) {
	case BTN_TOUCH:
265
266
		if (!is_press)
			tp->fake_touches &= ~FAKE_FINGER_OVERFLOW;
267
268
269
270
271
272
273
274
275
276
		shift = 0;
		break;
	case BTN_TOOL_FINGER:
		shift = 1;
		break;
	case BTN_TOOL_DOUBLETAP:
	case BTN_TOOL_TRIPLETAP:
	case BTN_TOOL_QUADTAP:
		shift = code - BTN_TOOL_DOUBLETAP + 2;
		break;
277
278
279
280
281
282
283
	/* when QUINTTAP is released we're either switching to 6 fingers
	   (flag stays in place until BTN_TOUCH is released) or
	   one of DOUBLE/TRIPLE/QUADTAP (will clear the flag on press) */
	case BTN_TOOL_QUINTTAP:
		if (is_press)
			tp->fake_touches |= FAKE_FINGER_OVERFLOW;
		return;
284
285
286
287
	default:
		return;
	}

288
289
	if (is_press) {
		tp->fake_touches &= ~FAKE_FINGER_OVERFLOW;
290
		tp->fake_touches |= 1 << shift;
291
292

	} else {
293
		tp->fake_touches &= ~(0x1 << shift);
294
	}
295
296
}

297
static inline void
298
tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
299
{
300
301
302
	if (t->state == TOUCH_BEGIN ||
	    t->state == TOUCH_UPDATE ||
	    t->state == TOUCH_HOVERING)
303
304
		return;

305
306
307
	/* we begin the touch as hovering because until BTN_TOUCH happens we
	 * don't know if it's a touch down or not. And BTN_TOUCH may happen
	 * after ABS_MT_TRACKING_ID */
308
309
	tp_motion_history_reset(t);
	t->dirty = true;
310
	t->has_ended = false;
311
	t->was_down = false;
312
	t->palm.state = PALM_NONE;
313
	t->state = TOUCH_HOVERING;
314
	t->pinned.is_pinned = false;
315
	t->time = time;
316
317
	t->speed.last_speed = 0;
	t->speed.exceeded_count = 0;
318
	t->hysteresis.x_motion_history = 0;
319
320
321
322
323
324
325
326
	tp->queued |= TOUCHPAD_EVENT_MOTION;
}

static inline void
tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
	t->dirty = true;
	t->state = TOUCH_BEGIN;
327
	t->time = time;
328
	t->was_down = true;
329
	tp->nfingers_down++;
330
	t->palm.time = time;
331
332
	t->thumb.state = THUMB_STATE_MAYBE;
	t->thumb.first_touch_time = time;
333
	t->tap.is_thumb = false;
334
	t->tap.is_palm = false;
335
	assert(tp->nfingers_down >= 1);
336
	tp->hysteresis.last_motion_time = time;
337
338
}

339
/**
340
341
342
343
344
345
 * Schedule a touch to be ended, based on either the events or some
 * attributes of the touch (size, pressure). In some cases we need to
 * resurrect a touch that has ended, so this doesn't actually end the touch
 * yet. All the TOUCH_MAYBE_END touches get properly ended once the device
 * state has been processed once and we know how many zombie touches we
 * need.
346
 */
347
static inline void
348
349
350
tp_maybe_end_touch(struct tp_dispatch *tp,
		   struct tp_touch *t,
		   uint64_t time)
351
{
352
353
	switch (t->state) {
	case TOUCH_NONE:
354
355
	case TOUCH_MAYBE_END:
		return;
356
	case TOUCH_END:
357
358
359
		evdev_log_bug_libinput(tp->device,
				       "touch %d: already in TOUCH_END\n",
				       t->index);
360
		return;
361
	case TOUCH_HOVERING:
362
363
364
	case TOUCH_BEGIN:
	case TOUCH_UPDATE:
		break;
365
366
	}

367
368
369
370
371
372
373
	if (t->state != TOUCH_HOVERING) {
		assert(tp->nfingers_down >= 1);
		tp->nfingers_down--;
		t->state = TOUCH_MAYBE_END;
	} else {
		t->state = TOUCH_NONE;
	}
374

375
	t->dirty = true;
376
}
377

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
/**
 * Inverse to tp_maybe_end_touch(), restores a touch back to its previous
 * state.
 */
static inline void
tp_recover_ended_touch(struct tp_dispatch *tp,
		       struct tp_touch *t)
{
	t->dirty = true;
	t->state = TOUCH_UPDATE;
	tp->nfingers_down++;
}

/**
 * End a touch, even if the touch sequence is still active.
 * Use tp_maybe_end_touch() instead.
 */
static inline void
tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
	if (t->state != TOUCH_MAYBE_END) {
		evdev_log_bug_libinput(tp->device,
				       "touch %d should be MAYBE_END, is %d\n",
				       t->index,
				       t->state);
		return;
404
	}
405
406

	t->dirty = true;
407
	t->palm.state = PALM_NONE;
408
	t->state = TOUCH_END;
409
	t->pinned.is_pinned = false;
410
	t->time = time;
411
	t->palm.time = 0;
412
	tp->queued |= TOUCHPAD_EVENT_MOTION;
413
414
}

415
416
417
418
419
420
421
/**
 * End the touch sequence on ABS_MT_TRACKING_ID -1 or when the BTN_TOOL_* 0 is received.
 */
static inline void
tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
	t->has_ended = true;
422
	tp_maybe_end_touch(tp, t, time);
423
424
}

425
426
427
428
429
430
431
432
static void
tp_stop_actions(struct tp_dispatch *tp, uint64_t time)
{
	tp_edge_scroll_stop_events(tp, time);
	tp_gesture_cancel(tp, time);
	tp_tap_suspend(tp, time);
}

433
struct device_coords
434
tp_get_delta(struct tp_touch *t)
435
{
436
437
	struct device_coords delta;
	const struct device_coords zero = { 0.0, 0.0 };
438

439
	if (t->history.count <= 1)
440
441
		return zero;

442
443
444
445
	delta.x = tp_motion_history_offset(t, 0)->point.x -
		  tp_motion_history_offset(t, 1)->point.x;
	delta.y = tp_motion_history_offset(t, 0)->point.y -
		  tp_motion_history_offset(t, 1)->point.y;
446

447
	return delta;
448
449
450
}

static void
451
452
tp_process_absolute(struct tp_dispatch *tp,
		    const struct input_event *e,
453
		    uint64_t time)
454
{
455
456
457
458
	struct tp_touch *t = tp_current_touch(tp);

	switch(e->code) {
	case ABS_MT_POSITION_X:
459
460
461
		evdev_device_check_abs_axis_range(tp->device,
						  e->code,
						  e->value);
462
		t->point.x = e->value;
463
		t->time = time;
464
		t->dirty = true;
465
		tp->queued |= TOUCHPAD_EVENT_MOTION;
466
467
		break;
	case ABS_MT_POSITION_Y:
468
469
470
		evdev_device_check_abs_axis_range(tp->device,
						  e->code,
						  e->value);
471
		t->point.y = e->value;
472
		t->time = time;
473
		t->dirty = true;
474
		tp->queued |= TOUCHPAD_EVENT_MOTION;
475
476
477
478
479
480
		break;
	case ABS_MT_SLOT:
		tp->slot = e->value;
		break;
	case ABS_MT_TRACKING_ID:
		if (e->value != -1)
481
			tp_new_touch(tp, t, time);
482
		else
483
			tp_end_sequence(tp, t, time);
484
		break;
485
486
	case ABS_MT_PRESSURE:
		t->pressure = e->value;
487
		t->time = time;
488
		t->dirty = true;
489
		tp->queued |= TOUCHPAD_EVENT_OTHERAXIS;
490
		break;
491
492
	case ABS_MT_TOOL_TYPE:
		t->is_tool_palm = e->value == MT_TOOL_PALM;
493
		t->time = time;
494
495
496
		t->dirty = true;
		tp->queued |= TOUCHPAD_EVENT_OTHERAXIS;
		break;
497
498
499
500
501
502
503
504
505
506
	case ABS_MT_TOUCH_MAJOR:
		t->major = e->value;
		t->dirty = true;
		tp->queued |= TOUCHPAD_EVENT_OTHERAXIS;
		break;
	case ABS_MT_TOUCH_MINOR:
		t->minor = e->value;
		t->dirty = true;
		tp->queued |= TOUCHPAD_EVENT_OTHERAXIS;
		break;
507
	}
508
509
}

510
511
512
static void
tp_process_absolute_st(struct tp_dispatch *tp,
		       const struct input_event *e,
513
		       uint64_t time)
514
515
516
517
518
{
	struct tp_touch *t = tp_current_touch(tp);

	switch(e->code) {
	case ABS_X:
519
520
521
		evdev_device_check_abs_axis_range(tp->device,
						  e->code,
						  e->value);
522
		t->point.x = e->value;
523
		t->time = time;
524
		t->dirty = true;
525
		tp->queued |= TOUCHPAD_EVENT_MOTION;
526
527
		break;
	case ABS_Y:
528
529
530
		evdev_device_check_abs_axis_range(tp->device,
						  e->code,
						  e->value);
531
		t->point.y = e->value;
532
		t->time = time;
533
534
535
		t->dirty = true;
		tp->queued |= TOUCHPAD_EVENT_MOTION;
		break;
536
537
	case ABS_PRESSURE:
		t->pressure = e->value;
538
		t->time = time;
539
540
541
		t->dirty = true;
		tp->queued |= TOUCHPAD_EVENT_OTHERAXIS;
		break;
542
543
544
	}
}

545
546
547
548
549
550
551
552
553
554
555
556
static inline void
tp_restore_synaptics_touches(struct tp_dispatch *tp,
			     uint64_t time)
{
	unsigned int i;
	unsigned int nfake_touches;

	nfake_touches = tp_fake_finger_count(tp);
	if (nfake_touches < 3)
		return;

	if (tp->nfingers_down >= nfake_touches ||
557
	    (tp->nfingers_down == tp->num_slots && nfake_touches == tp->num_slots))
558
559
560
561
562
563
564
565
566
567
568
		return;

	/* Synaptics devices may end touch 2 on BTN_TOOL_TRIPLETAP
	 * and start it again on the next frame with different coordinates
	 * (#91352). We search the touches we have, if there is one that has
	 * just ended despite us being on tripletap, we move it back to
	 * update.
	 */
	for (i = 0; i < tp->num_slots; i++) {
		struct tp_touch *t = tp_get_touch(tp, i);

569
		if (t->state != TOUCH_MAYBE_END)
570
571
572
			continue;

		/* new touch, move it through begin to update immediately */
573
		tp_recover_ended_touch(tp, t);
574
575
576
	}
}

577
static void
578
579
tp_process_fake_touches(struct tp_dispatch *tp,
			uint64_t time)
580
581
582
{
	struct tp_touch *t;
	unsigned int nfake_touches;
583
	unsigned int i, start;
584

585
	nfake_touches = tp_fake_finger_count(tp);
586
587
	if (nfake_touches == FAKE_FINGER_OVERFLOW)
		return;
588

589
590
591
592
	if (tp->device->model_flags &
	    EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD)
		tp_restore_synaptics_touches(tp, time);

593
	start = tp->has_mt ? tp->num_slots : 0;
594
	for (i = start; i < tp->ntouches; i++) {
595
		t = tp_get_touch(tp, i);
596
		if (i < nfake_touches)
597
			tp_new_touch(tp, t, time);
598
		else
599
			tp_end_sequence(tp, t, time);
600
601
602
	}
}

603
604
605
606
607
608
609
static void
tp_process_trackpoint_button(struct tp_dispatch *tp,
			     const struct input_event *e,
			     uint64_t time)
{
	struct evdev_dispatch *dispatch;
	struct input_event event;
Deepa Dinamani's avatar
Deepa Dinamani committed
610
611
612
613
614
615
616
	struct input_event syn_report = {
		 .input_event_sec = 0,
		 .input_event_usec = 0,
		 .type = EV_SYN,
		 .code = SYN_REPORT,
		 .value = 0
	};
617

618
	if (!tp->buttons.trackpoint)
619
620
621
622
623
		return;

	dispatch = tp->buttons.trackpoint->dispatch;

	event = *e;
Deepa Dinamani's avatar
Deepa Dinamani committed
624
625
	syn_report.input_event_sec = e->input_event_sec;
	syn_report.input_event_usec = e->input_event_usec;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643

	switch (event.code) {
	case BTN_0:
		event.code = BTN_LEFT;
		break;
	case BTN_1:
		event.code = BTN_RIGHT;
		break;
	case BTN_2:
		event.code = BTN_MIDDLE;
		break;
	default:
		return;
	}

	dispatch->interface->process(dispatch,
				     tp->buttons.trackpoint,
				     &event, time);
644
645
646
	dispatch->interface->process(dispatch,
				     tp->buttons.trackpoint,
				     &syn_report, time);
647
648
}

649
650
651
static void
tp_process_key(struct tp_dispatch *tp,
	       const struct input_event *e,
652
	       uint64_t time)
653
654
655
656
657
{
	switch (e->code) {
		case BTN_LEFT:
		case BTN_MIDDLE:
		case BTN_RIGHT:
658
			tp_process_button(tp, e, time);
659
			break;
660
		case BTN_TOUCH:
661
		case BTN_TOOL_FINGER:
662
663
664
		case BTN_TOOL_DOUBLETAP:
		case BTN_TOOL_TRIPLETAP:
		case BTN_TOOL_QUADTAP:
665
		case BTN_TOOL_QUINTTAP:
666
			tp_fake_finger_set(tp, e->code, !!e->value);
667
			break;
668
669
670
671
672
		case BTN_0:
		case BTN_1:
		case BTN_2:
			tp_process_trackpoint_button(tp, e, time);
			break;
673
674
675
	}
}

676
static void
677
tp_unpin_finger(const struct tp_dispatch *tp, struct tp_touch *t)
678
{
679
680
	struct phys_coords mm;
	struct device_coords delta;
681

682
683
684
	if (!t->pinned.is_pinned)
		return;

685
686
687
688
	delta.x = abs(t->point.x - t->pinned.center.x);
	delta.y = abs(t->point.y - t->pinned.center.y);

	mm = evdev_device_unit_delta_to_mm(tp->device, &delta);
689

690
	/* 1.5mm movement -> unpin */
691
	if (hypot(mm.x, mm.y) >= 1.5) {
692
		t->pinned.is_pinned = false;
693
		return;
694
695
696
697
	}
}

static void
698
tp_pin_fingers(struct tp_dispatch *tp)
699
{
700
	struct tp_touch *t;
701
702

	tp_for_each_touch(tp, t) {
703
		t->pinned.is_pinned = true;
704
		t->pinned.center = t->point;
705
706
707
	}
}

708
bool
709
tp_touch_active(const struct tp_dispatch *tp, const struct tp_touch *t)
710
711
{
	return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
712
		t->palm.state == PALM_NONE &&
713
		!t->pinned.is_pinned &&
714
		t->thumb.state != THUMB_STATE_YES &&
715
716
		tp_button_touch_active(tp, t) &&
		tp_edge_scroll_touch_active(tp, t);
717
}
718

719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
static inline bool
tp_palm_was_in_side_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
{
	return t->palm.first.x < tp->palm.left_edge ||
	       t->palm.first.x > tp->palm.right_edge;
}

static inline bool
tp_palm_was_in_top_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
{
	return t->palm.first.y < tp->palm.upper_edge;
}

static inline bool
tp_palm_in_side_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
{
	return t->point.x < tp->palm.left_edge ||
	       t->point.x > tp->palm.right_edge;
}

static inline bool
tp_palm_in_top_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
{
	return t->point.y < tp->palm.upper_edge;
}

static inline bool
tp_palm_in_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
{
	return tp_palm_in_side_edge(tp, t) || tp_palm_in_top_edge(tp, t);
}

751
bool
752
tp_palm_tap_is_palm(const struct tp_dispatch *tp, const struct tp_touch *t)
753
754
755
756
{
	if (t->state != TOUCH_BEGIN)
		return false;

757
	if (!tp_palm_in_edge(tp, t))
758
759
		return false;

760
761
762
	evdev_log_debug(tp->device,
			"palm: touch %d: palm-tap detected\n",
			t->index);
763
	return true;
764
765
}

766
767
768
769
static bool
tp_palm_detect_dwt_triggered(struct tp_dispatch *tp,
			     struct tp_touch *t,
			     uint64_t time)
770
{
771
772
	if (tp->dwt.dwt_enabled &&
	    tp->dwt.keyboard_active &&
773
	    t->state == TOUCH_BEGIN) {
774
775
		t->palm.state = PALM_TYPING;
		t->palm.first = t->point;
776
		return true;
777
778
	} else if (!tp->dwt.keyboard_active &&
		   t->state == TOUCH_UPDATE &&
Peter Hutterer's avatar
Peter Hutterer committed
779
		   t->palm.state == PALM_TYPING) {
780
781
782
783
784
785
786
787
788
		/* If a touch has started before the first or after the last
		   key press, release it on timeout. Benefit: a palm rested
		   while typing on the touchpad will be ignored, but a touch
		   started once we stop typing will be able to control the
		   pointer (alas not tap, etc.).
		   */
		if (t->palm.time == 0 ||
		    t->palm.time > tp->dwt.keyboard_last_press_time) {
			t->palm.state = PALM_NONE;
789
			evdev_log_debug(tp->device,
790
791
					"palm: touch %d released, timeout after typing\n",
					t->index);
792
		}
793
794
	}

795
	return false;
796
797
}

798
799
800
801
static bool
tp_palm_detect_trackpoint_triggered(struct tp_dispatch *tp,
				    struct tp_touch *t,
				    uint64_t time)
802
{
803
	if (!tp->palm.monitor_trackpoint)
804
		return false;
805

806
807
808
809
	if (t->palm.state == PALM_NONE &&
	    t->state == TOUCH_BEGIN &&
	    tp->palm.trackpoint_active) {
		t->palm.state = PALM_TRACKPOINT;
810
		return true;
811
812
813
814
815
816
817
	} else if (t->palm.state == PALM_TRACKPOINT &&
		   t->state == TOUCH_UPDATE &&
		   !tp->palm.trackpoint_active) {

		if (t->palm.time == 0 ||
		    t->palm.time > tp->palm.trackpoint_last_event_time) {
			t->palm.state = PALM_NONE;
818
			evdev_log_debug(tp->device,
819
				       "palm: touch %d released, timeout after trackpoint\n", t->index);
820
821
822
		}
	}

823
	return false;
824
825
}

826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
static bool
tp_palm_detect_tool_triggered(struct tp_dispatch *tp,
			      struct tp_touch *t,
			      uint64_t time)
{
	if (!tp->palm.use_mt_tool)
		return false;

	if (t->palm.state != PALM_NONE &&
	    t->palm.state != PALM_TOOL_PALM)
		return false;

	if (t->palm.state == PALM_NONE &&
	    t->is_tool_palm)
		t->palm.state = PALM_TOOL_PALM;
	else if (t->palm.state == PALM_TOOL_PALM &&
		 !t->is_tool_palm)
		t->palm.state = PALM_NONE;

	return t->palm.state == PALM_TOOL_PALM;
}

848
849
850
851
static inline bool
tp_palm_detect_move_out_of_edge(struct tp_dispatch *tp,
				struct tp_touch *t,
				uint64_t time)
852
{
853
	const int PALM_TIMEOUT = ms2us(200);
854
	int directions = 0;
855
856
	struct device_float_coords delta;
	int dirs;
857

858
859
860
861
862
863
864
865
866
867
868
869
	if (time < t->palm.time + PALM_TIMEOUT && !tp_palm_in_edge(tp, t)) {
		if (tp_palm_was_in_side_edge(tp, t))
			directions = NE|E|SE|SW|W|NW;
		else if (tp_palm_was_in_top_edge(tp, t))
			directions = S|SE|SW;

		if (directions) {
			delta = device_delta(t->point, t->palm.first);
			dirs = phys_get_direction(tp_phys_delta(tp, delta));
			if ((dirs & directions) && !(dirs & ~directions))
				return true;
		}
870
871
872
873
874
	}

	return false;
}

875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
static inline bool
tp_palm_detect_multifinger(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
	struct tp_touch *other;

	if (tp->nfingers_down < 2)
		return false;

	/* If we have at least one other active non-palm touch make this
	 * touch non-palm too. This avoids palm detection during two-finger
	 * scrolling.
	 *
	 * Note: if both touches start in the palm zone within the same
	 * frame the second touch will still be PALM_NONE and thus detected
	 * here as non-palm touch. This is too niche to worry about for now.
	 */
	tp_for_each_touch(tp, other) {
		if (other == t)
			continue;

		if (tp_touch_active(tp, other) &&
		    other->palm.state == PALM_NONE) {
			return true;
		}
	}

	return false;
}

904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
static inline bool
tp_palm_detect_touch_size_triggered(struct tp_dispatch *tp,
				    struct tp_touch *t,
				    uint64_t time)
{
	if (!tp->palm.use_size)
		return false;

	/* If a finger size is large enough for palm, we stick with that and
	 * force the user to release and reset the finger */
	if (t->palm.state != PALM_NONE && t->palm.state != PALM_TOUCH_SIZE)
		return false;

	if (t->major > tp->palm.size_threshold ||
	    t->minor > tp->palm.size_threshold) {
919
920
		if (t->palm.state != PALM_TOUCH_SIZE)
			evdev_log_debug(tp->device,
921
922
					"palm: touch %d size exceeded\n",
					t->index);
923
924
925
926
927
928
929
		t->palm.state = PALM_TOUCH_SIZE;
		return true;
	}

	return false;
}

930
931
932
933
static inline bool
tp_palm_detect_edge(struct tp_dispatch *tp,
		    struct tp_touch *t,
		    uint64_t time)
934
{
935
	if (t->palm.state == PALM_EDGE) {
936
937
		if (tp_palm_detect_multifinger(tp, t, time)) {
			t->palm.state = PALM_NONE;
938
			evdev_log_debug(tp->device,
939
940
				  "palm: touch %d released, multiple fingers\n",
				  t->index);
941
942
943
944
945
946

		/* If labelled a touch as palm, we unlabel as palm when
		   we move out of the palm edge zone within the timeout, provided
		   the direction is within 45 degrees of the horizontal.
		 */
		} else if (tp_palm_detect_move_out_of_edge(tp, t, time)) {
947
			t->palm.state = PALM_NONE;
948
			evdev_log_debug(tp->device,
949
950
				  "palm: touch %d released, out of edge zone\n",
				  t->index);
951
		}
952
		return false;
953
	} else if (tp_palm_detect_multifinger(tp, t, time)) {
954
		return false;
955
	}
956
957
958

	/* palm must start in exclusion zone, it's ok to move into
	   the zone without being a palm */
959
	if (t->state != TOUCH_BEGIN || !tp_palm_in_edge(tp, t))
960
		return false;
961
962
963
964
965
966

	/* don't detect palm in software button areas, it's
	   likely that legitimate touches start in the area
	   covered by the exclusion zone */
	if (tp->buttons.is_clickpad &&
	    tp_button_is_inside_softbutton_area(tp, t))
967
		return false;
968

969
	if (tp_touch_get_edge(tp, t) & EDGE_RIGHT)
970
		return false;
971

972
	t->palm.state = PALM_EDGE;
973
	t->palm.time = time;
974
	t->palm.first = t->point;
975

976
977
978
	return true;
}

979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
static bool
tp_palm_detect_pressure_triggered(struct tp_dispatch *tp,
				  struct tp_touch *t,
				  uint64_t time)
{
	if (!tp->palm.use_pressure)
		return false;

	if (t->palm.state != PALM_NONE &&
	    t->palm.state != PALM_PRESSURE)
		return false;

	if (t->pressure > tp->palm.pressure_threshold)
		t->palm.state = PALM_PRESSURE;

	return t->palm.state == PALM_PRESSURE;
}

997
998
999
1000
1001
static bool
tp_palm_detect_arbitration_triggered(struct tp_dispatch *tp,
				     struct tp_touch *t,
				     uint64_t time)
{
1002
	if (!tp->arbitration.in_arbitration)
1003
1004
1005
1006
1007
1008
1009
		return false;

	t->palm.state = PALM_ARBITRATION;

	return true;
}

1010
1011
1012
static void
tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
1013
1014
	const char *palm_state;
	enum touch_palm_state oldstate = t->palm.state;
1015

1016
1017
1018
	if (tp_palm_detect_pressure_triggered(tp, t, time))
		goto out;

1019
1020
1021
	if (tp_palm_detect_arbitration_triggered(tp, t, time))
		goto out;

1022
1023
1024
1025
1026
1027
	if (tp_palm_detect_dwt_triggered(tp, t, time))
		goto out;

	if (tp_palm_detect_trackpoint_triggered(tp, t, time))
		goto out;

1028
1029
1030
	if (tp_palm_detect_tool_triggered(tp, t, time))
		goto out;

1031
1032
1033
	if (tp_palm_detect_touch_size_triggered(tp, t, time))
		goto out;

1034
1035
1036
	if (tp_palm_detect_edge(tp, t, time))
		goto out;

1037
1038
1039
1040
1041
1042
1043
1044
1045
	/* Pressure is highest priority because it cannot be released and
	 * overrides all other checks. So we check once before anything else
	 * in case pressure triggers on a non-palm touch. And again after
	 * everything in case one of the others released but we have a
	 * pressure trigger now.
	 */
	if (tp_palm_detect_pressure_triggered(tp, t, time))
		goto out;

1046
	return;
1047
out:
1048

1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
	if (oldstate == t->palm.state)
		return;

	switch (t->palm.state) {
	case PALM_EDGE:
		palm_state = "edge";
		break;
	case PALM_TYPING:
		palm_state = "typing";
		break;
	case PALM_TRACKPOINT:
		palm_state = "trackpoint";
		break;
1062
1063
1064
	case PALM_TOOL_PALM:
		palm_state = "tool-palm";
		break;
1065
1066
1067
	case PALM_PRESSURE:
		palm_state = "pressure";
		break;
1068
1069
1070
	case PALM_TOUCH_SIZE:
		palm_state = "touch size";
		break;
1071
1072
1073
	case PALM_ARBITRATION:
		palm_state = "arbitration";
		break;
1074
1075
1076
1077
1078
	case PALM_NONE:
	default:
		abort();
		break;
	}
1079
	evdev_log_debug(tp->device,
1080
1081
		  "palm: touch %d, palm detected (%s)\n",
		  t->index,
1082
		  palm_state);
1083
1084
}

1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
static inline const char*
thumb_state_to_str(enum tp_thumb_state state)
{
	switch(state){
	CASE_RETURN_STRING(THUMB_STATE_NO);
	CASE_RETURN_STRING(THUMB_STATE_YES);
	CASE_RETURN_STRING(THUMB_STATE_MAYBE);
	}

	return NULL;
}

1097
static void
1098
tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
1099
{
1100
1101
1102
1103
1104
	enum tp_thumb_state state = t->thumb.state;

	/* once a thumb, always a thumb, once ruled out always ruled out */
	if (!tp->thumb.detect_thumbs ||
	    t->thumb.state != THUMB_STATE_MAYBE)
1105
1106
		return;

1107
1108
1109
1110
1111
1112
1113
	if (t->point.y < tp->thumb.upper_thumb_line) {
		/* if a potential thumb is above the line, it won't ever
		 * label as thumb */
		t->thumb.state = THUMB_STATE_NO;
		goto out;
	}

1114
1115
1116
1117
1118
	/* If the thumb moves by more than 7mm, it's not a resting thumb */
	if (t->state == TOUCH_BEGIN)
		t->thumb.initial = t->point;
	else if (t->state == TOUCH_UPDATE) {
		struct device_float_coords delta;
1119
		struct phys_coords mm;
1120
1121

		delta = device_delta(t->point, t->thumb.initial);
1122
1123
		mm = tp_phys_delta(tp, delta);
		if (length_in_mm(mm) > 7) {
1124
1125
1126
1127
1128
			t->thumb.state = THUMB_STATE_NO;
			goto out;
		}
	}

1129
	/* Note: a thumb at the edge of the touchpad won't trigger the
1130
1131
1132
1133
	 * threshold, the surface area is usually too small. So we have a
	 * two-stage detection: pressure and time within the area.
	 * A finger that remains at the very bottom of the touchpad becomes
	 * a thumb.
1134
	 */
1135
1136
	if (tp->thumb.use_pressure &&
	    t->pressure > tp->thumb.pressure_threshold)
1137
1138
1139
		t->thumb.state = THUMB_STATE_YES;
	else if (t->point.y > tp->thumb.lower_thumb_line &&
		 tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE &&
1140
		 t->thumb.first_touch_time + THUMB_MOVE_TIMEOUT < time)