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

Jon A. Cruz's avatar
Jon A. Cruz committed
24 25
#include "config.h"

26 27
#include <errno.h>
#include <limits.h>
28
#include <math.h>
29 30
#include <string.h>
#include <unistd.h>
31
#include "linux/input.h"
32 33 34

#include "evdev-mt-touchpad.h"

35 36
#define DEFAULT_BUTTON_ENTER_TIMEOUT ms2us(100)
#define DEFAULT_BUTTON_LEAVE_TIMEOUT ms2us(300)
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

/*****************************************
 * BEFORE YOU EDIT THIS FILE, look at the state diagram in
 * doc/touchpad-softbutton-state-machine.svg, or online at
 * https://drive.google.com/file/d/0B1NwWmji69nocUs1cVJTbkdwMFk/edit?usp=sharing
 * (it's a http://draw.io diagram)
 *
 * Any changes in this file must be represented in the diagram.
 *
 * The state machine only affects the soft button area code.
 */

static inline const char*
button_state_to_str(enum button_state state) {
	switch(state) {
	CASE_RETURN_STRING(BUTTON_STATE_NONE);
	CASE_RETURN_STRING(BUTTON_STATE_AREA);
	CASE_RETURN_STRING(BUTTON_STATE_BOTTOM);
55 56 57 58
	CASE_RETURN_STRING(BUTTON_STATE_TOP);
	CASE_RETURN_STRING(BUTTON_STATE_TOP_NEW);
	CASE_RETURN_STRING(BUTTON_STATE_TOP_TO_IGNORE);
	CASE_RETURN_STRING(BUTTON_STATE_IGNORE);
59 60 61 62 63 64 65 66
	}
	return NULL;
}

static inline const char*
button_event_to_str(enum button_event event) {
	switch(event) {
	CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_R);
67
	CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_M);
68
	CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_L);
69 70 71
	CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_R);
	CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_M);
	CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_L);
72 73 74 75 76 77 78 79 80 81
	CASE_RETURN_STRING(BUTTON_EVENT_IN_AREA);
	CASE_RETURN_STRING(BUTTON_EVENT_UP);
	CASE_RETURN_STRING(BUTTON_EVENT_PRESS);
	CASE_RETURN_STRING(BUTTON_EVENT_RELEASE);
	CASE_RETURN_STRING(BUTTON_EVENT_TIMEOUT);
	}
	return NULL;
}

static inline bool
82 83
is_inside_bottom_button_area(const struct tp_dispatch *tp,
			     const struct tp_touch *t)
84
{
85
	return t->point.y >= tp->buttons.bottom_area.top_edge;
86 87 88
}

static inline bool
89 90
is_inside_bottom_right_area(const struct tp_dispatch *tp,
			    const struct tp_touch *t)
91
{
92
	return is_inside_bottom_button_area(tp, t) &&
93
	       t->point.x > tp->buttons.bottom_area.rightbutton_left_edge;
94 95
}

96 97 98 99 100 101 102 103 104
static inline bool
is_inside_bottom_middle_area(const struct tp_dispatch *tp,
			   const struct tp_touch *t)
{
	return is_inside_bottom_button_area(tp, t) &&
	       !is_inside_bottom_right_area(tp, t) &&
	       t->point.x > tp->buttons.bottom_area.middlebutton_left_edge;
}

105
static inline bool
106 107
is_inside_bottom_left_area(const struct tp_dispatch *tp,
			   const struct tp_touch *t)
108
{
109
	return is_inside_bottom_button_area(tp, t) &&
110
	       !is_inside_bottom_middle_area(tp, t) &&
111
	       !is_inside_bottom_right_area(tp, t);
112 113
}

114
static inline bool
115 116
is_inside_top_button_area(const struct tp_dispatch *tp,
			  const struct tp_touch *t)
117
{
118
	return t->point.y <= tp->buttons.top_area.bottom_edge;
119 120 121
}

static inline bool
122 123
is_inside_top_right_area(const struct tp_dispatch *tp,
			 const struct tp_touch *t)
124 125
{
	return is_inside_top_button_area(tp, t) &&
126
	       t->point.x > tp->buttons.top_area.rightbutton_left_edge;
127 128 129
}

static inline bool
130 131
is_inside_top_left_area(const struct tp_dispatch *tp,
			const struct tp_touch *t)
132 133
{
	return is_inside_top_button_area(tp, t) &&
134
	       t->point.x < tp->buttons.top_area.leftbutton_right_edge;
135 136 137
}

static inline bool
138 139
is_inside_top_middle_area(const struct tp_dispatch *tp,
			  const struct tp_touch *t)
140 141
{
	return is_inside_top_button_area(tp, t) &&
142 143
	       t->point.x >= tp->buttons.top_area.leftbutton_right_edge &&
	       t->point.x <= tp->buttons.top_area.rightbutton_left_edge;
144 145
}

146 147 148
static void
tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t)
{
149
	libinput_timer_set(&t->button.timer,
150
			   t->time + DEFAULT_BUTTON_ENTER_TIMEOUT);
151 152 153 154 155
}

static void
tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t)
{
156
	libinput_timer_set(&t->button.timer,
157
			   t->time + DEFAULT_BUTTON_LEAVE_TIMEOUT);
158 159 160 161 162 163 164
}

/*
 * tp_button_set_state, change state and implement on-entry behavior
 * as described in the state machine diagram.
 */
static void
165 166 167 168
tp_button_set_state(struct tp_dispatch *tp,
		    struct tp_touch *t,
		    enum button_state new_state,
		    enum button_event event)
169
{
170
	libinput_timer_cancel(&t->button.timer);
171 172

	t->button.state = new_state;
173

174 175 176 177 178 179 180 181 182 183
	switch (t->button.state) {
	case BUTTON_STATE_NONE:
		t->button.curr = 0;
		break;
	case BUTTON_STATE_AREA:
		t->button.curr = BUTTON_EVENT_IN_AREA;
		break;
	case BUTTON_STATE_BOTTOM:
		t->button.curr = event;
		break;
184 185 186 187 188 189 190 191 192 193 194 195
	case BUTTON_STATE_TOP:
		break;
	case BUTTON_STATE_TOP_NEW:
		t->button.curr = event;
		tp_button_set_enter_timer(tp, t);
		break;
	case BUTTON_STATE_TOP_TO_IGNORE:
		tp_button_set_leave_timer(tp, t);
		break;
	case BUTTON_STATE_IGNORE:
		t->button.curr = 0;
		break;
196 197 198 199 200 201 202 203 204 205
	}
}

static void
tp_button_none_handle_event(struct tp_dispatch *tp,
			    struct tp_touch *t,
			    enum button_event event)
{
	switch (event) {
	case BUTTON_EVENT_IN_BOTTOM_R:
206
	case BUTTON_EVENT_IN_BOTTOM_M:
207
	case BUTTON_EVENT_IN_BOTTOM_L:
208
		tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
209
		break;
210 211 212 213 214
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
		tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event);
		break;
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	case BUTTON_EVENT_IN_AREA:
		tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
	case BUTTON_EVENT_RELEASE:
	case BUTTON_EVENT_TIMEOUT:
		break;
	}
}

static void
tp_button_area_handle_event(struct tp_dispatch *tp,
			    struct tp_touch *t,
			    enum button_event event)
{
	switch (event) {
	case BUTTON_EVENT_IN_BOTTOM_R:
235
	case BUTTON_EVENT_IN_BOTTOM_M:
236
	case BUTTON_EVENT_IN_BOTTOM_L:
237 238 239
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
240 241 242 243 244 245 246 247 248 249 250 251 252 253
	case BUTTON_EVENT_IN_AREA:
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
	case BUTTON_EVENT_RELEASE:
	case BUTTON_EVENT_TIMEOUT:
		break;
	}
}

static void
tp_button_bottom_handle_event(struct tp_dispatch *tp,
254 255
			      struct tp_touch *t,
			      enum button_event event)
256 257 258
{
	switch (event) {
	case BUTTON_EVENT_IN_BOTTOM_R:
259
	case BUTTON_EVENT_IN_BOTTOM_M:
260 261
	case BUTTON_EVENT_IN_BOTTOM_L:
		if (event != t->button.curr)
262 263 264
			tp_button_set_state(tp,
					    t,
					    BUTTON_STATE_BOTTOM,
265 266
					    event);
		break;
267 268 269
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
270
	case BUTTON_EVENT_IN_AREA:
271
		tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
272 273 274 275 276 277 278 279 280 281 282
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
	case BUTTON_EVENT_RELEASE:
	case BUTTON_EVENT_TIMEOUT:
		break;
	}
}

283 284
static void
tp_button_top_handle_event(struct tp_dispatch *tp,
285 286
			   struct tp_touch *t,
			   enum button_event event)
287 288 289
{
	switch (event) {
	case BUTTON_EVENT_IN_BOTTOM_R:
290
	case BUTTON_EVENT_IN_BOTTOM_M:
291 292 293 294 295 296 297
	case BUTTON_EVENT_IN_BOTTOM_L:
		tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
		break;
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
		if (event != t->button.curr)
298 299 300
			tp_button_set_state(tp,
					    t,
					    BUTTON_STATE_TOP_NEW,
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
					    event);
		break;
	case BUTTON_EVENT_IN_AREA:
		tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
	case BUTTON_EVENT_RELEASE:
	case BUTTON_EVENT_TIMEOUT:
		break;
	}
}

static void
tp_button_top_new_handle_event(struct tp_dispatch *tp,
318 319
			       struct tp_touch *t,
			       enum button_event event)
320 321 322
{
	switch(event) {
	case BUTTON_EVENT_IN_BOTTOM_R:
323
	case BUTTON_EVENT_IN_BOTTOM_M:
324 325 326 327 328 329 330
	case BUTTON_EVENT_IN_BOTTOM_L:
		tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
		break;
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
		if (event != t->button.curr)
331 332 333
			tp_button_set_state(tp,
					    t,
					    BUTTON_STATE_TOP_NEW,
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
					    event);
		break;
	case BUTTON_EVENT_IN_AREA:
		tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
		tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
		break;
	case BUTTON_EVENT_RELEASE:
		break;
	case BUTTON_EVENT_TIMEOUT:
		tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
		break;
	}
}

static void
tp_button_top_to_ignore_handle_event(struct tp_dispatch *tp,
355 356
				     struct tp_touch *t,
				     enum button_event event)
357 358 359 360 361 362
{
	switch(event) {
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
		if (event == t->button.curr)
363 364 365
			tp_button_set_state(tp,
					    t,
					    BUTTON_STATE_TOP,
366 367
					    event);
		else
368 369 370
			tp_button_set_state(tp,
					    t,
					    BUTTON_STATE_TOP_NEW,
371 372 373
					    event);
		break;
	case BUTTON_EVENT_IN_BOTTOM_R:
374
	case BUTTON_EVENT_IN_BOTTOM_M:
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
	case BUTTON_EVENT_IN_BOTTOM_L:
	case BUTTON_EVENT_IN_AREA:
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
	case BUTTON_EVENT_RELEASE:
		break;
	case BUTTON_EVENT_TIMEOUT:
		tp_button_set_state(tp, t, BUTTON_STATE_IGNORE, event);
		break;
	}
}

static void
tp_button_ignore_handle_event(struct tp_dispatch *tp,
392 393
			      struct tp_touch *t,
			      enum button_event event)
394 395 396
{
	switch (event) {
	case BUTTON_EVENT_IN_BOTTOM_R:
397
	case BUTTON_EVENT_IN_BOTTOM_M:
398 399 400 401 402 403 404 405 406 407
	case BUTTON_EVENT_IN_BOTTOM_L:
	case BUTTON_EVENT_IN_TOP_R:
	case BUTTON_EVENT_IN_TOP_M:
	case BUTTON_EVENT_IN_TOP_L:
	case BUTTON_EVENT_IN_AREA:
		break;
	case BUTTON_EVENT_UP:
		tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
		break;
	case BUTTON_EVENT_PRESS:
408 409
		t->button.curr = BUTTON_EVENT_IN_AREA;
		break;
410
	case BUTTON_EVENT_RELEASE:
411
		break;
412 413 414 415 416
	case BUTTON_EVENT_TIMEOUT:
		break;
	}
}

417 418 419 420
static void
tp_button_handle_event(struct tp_dispatch *tp,
		       struct tp_touch *t,
		       enum button_event event,
421
		       uint64_t time)
422 423 424 425 426 427 428 429 430 431 432 433 434
{
	enum button_state current = t->button.state;

	switch(t->button.state) {
	case BUTTON_STATE_NONE:
		tp_button_none_handle_event(tp, t, event);
		break;
	case BUTTON_STATE_AREA:
		tp_button_area_handle_event(tp, t, event);
		break;
	case BUTTON_STATE_BOTTOM:
		tp_button_bottom_handle_event(tp, t, event);
		break;
435 436 437 438 439 440 441 442 443 444 445 446
	case BUTTON_STATE_TOP:
		tp_button_top_handle_event(tp, t, event);
		break;
	case BUTTON_STATE_TOP_NEW:
		tp_button_top_new_handle_event(tp, t, event);
		break;
	case BUTTON_STATE_TOP_TO_IGNORE:
		tp_button_top_to_ignore_handle_event(tp, t, event);
		break;
	case BUTTON_STATE_IGNORE:
		tp_button_ignore_handle_event(tp, t, event);
		break;
447 448 449
	}

	if (current != t->button.state)
450 451 452 453 454
		evdev_log_debug(tp->device,
				"button state: from %s, event %s to %s\n",
				button_state_to_str(current),
				button_event_to_str(event),
				button_state_to_str(t->button.state));
455 456
}

457
void
458
tp_button_handle_state(struct tp_dispatch *tp, uint64_t time)
459 460 461 462
{
	struct tp_touch *t;

	tp_for_each_touch(tp, t) {
463
		if (t->state == TOUCH_NONE || t->state == TOUCH_HOVERING)
464 465 466 467 468
			continue;

		if (t->state == TOUCH_END) {
			tp_button_handle_event(tp, t, BUTTON_EVENT_UP, time);
		} else if (t->dirty) {
469 470
			enum button_event event;

471
			if (is_inside_bottom_right_area(tp, t))
472
				event = BUTTON_EVENT_IN_BOTTOM_R;
473 474
			else if (is_inside_bottom_middle_area(tp, t))
				event = BUTTON_EVENT_IN_BOTTOM_M;
475
			else if (is_inside_bottom_left_area(tp, t))
476
				event = BUTTON_EVENT_IN_BOTTOM_L;
477
			else if (is_inside_top_right_area(tp, t))
478
				event = BUTTON_EVENT_IN_TOP_R;
479
			else if (is_inside_top_middle_area(tp, t))
480
				event = BUTTON_EVENT_IN_TOP_M;
481
			else if (is_inside_top_left_area(tp, t))
482
				event = BUTTON_EVENT_IN_TOP_L;
483
			else
484 485 486
				event = BUTTON_EVENT_IN_AREA;

			tp_button_handle_event(tp, t, event, time);
487 488 489 490 491 492 493 494
		}
		if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
			tp_button_handle_event(tp, t, BUTTON_EVENT_RELEASE, time);
		if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
			tp_button_handle_event(tp, t, BUTTON_EVENT_PRESS, time);
	}
}

495
static void
496
tp_button_handle_timeout(uint64_t now, void *data)
497
{
498
	struct tp_touch *t = data;
499

500
	tp_button_handle_event(t->tp, t, BUTTON_EVENT_TIMEOUT, now);
501
}
502

503
void
504 505
tp_process_button(struct tp_dispatch *tp,
		  const struct input_event *e,
506
		  uint64_t time)
507 508
{
	uint32_t mask = 1 << (e->code - BTN_LEFT);
509 510 511

	/* Ignore other buttons on clickpads */
	if (tp->buttons.is_clickpad && e->code != BTN_LEFT) {
512 513 514
		evdev_log_bug_kernel(tp->device,
				     "received %s button event on a clickpad\n",
				     libevdev_event_code_get_name(EV_KEY, e->code));
515
		return;
516 517
	}

518 519 520 521 522 523 524 525 526
	if (e->value) {
		tp->buttons.state |= mask;
		tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS;
	} else {
		tp->buttons.state &= ~mask;
		tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
	}
}

527 528 529 530 531 532 533 534 535 536
void
tp_release_all_buttons(struct tp_dispatch *tp,
		       uint64_t time)
{
	if (tp->buttons.state) {
		tp->buttons.state = 0;
		tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
	}
}

537
static void
538
tp_init_softbuttons(struct tp_dispatch *tp,
539
		    struct evdev_device *device)
540
{
541 542
	double width, height;
	struct device_coords edges;
543
	int mb_le, mb_re; /* middle button left/right edge */
544
	struct phys_coords mm = { 0.0, 0.0 };
545

546
	evdev_device_get_size(device, &width, &height);
547

548
	/* button height: 10mm or 15% or the touchpad height,
549
	   whichever is smaller */
550 551 552 553 554 555 556 557 558
	if (height * 0.15 > 10)
		mm.y = height - 10;
	else
		mm.y = height * 0.85;

	mm.x = width * 0.5;
	edges = evdev_device_mm_to_units(device, &mm);
	tp->buttons.bottom_area.top_edge = edges.y;
	tp->buttons.bottom_area.rightbutton_left_edge = edges.x;
559

560 561 562 563 564 565
	tp->buttons.bottom_area.middlebutton_left_edge = INT_MAX;

	/* if middlebutton emulation is enabled, don't init a software area */
	if (device->middlebutton.want_enabled)
		return;

566 567 568 569
	/* The middle button is 25% of the touchpad and centered. Many
	 * touchpads don't have markings for the middle button at all so we
	 * need to make it big enough to reliably hit it but not too big so
	 * it takes away all the space.
570 571 572
	 *
	 * On touchpads with visible markings we reduce the size of the
	 * middle button since users have a visual guide.
573
	 */
574
	if (tp->device->model_flags & EVDEV_MODEL_TOUCHPAD_VISIBLE_MARKER) {
575 576 577
		mm.x = width/2 - 5; /* 10mm wide */
		edges = evdev_device_mm_to_units(device, &mm);
		mb_le = edges.x;
578

579 580 581
		mm.x = width/2 + 5; /* 10mm wide */
		edges = evdev_device_mm_to_units(device, &mm);
		mb_re = edges.x;
582
	} else {
583 584 585 586 587 588 589
		mm.x = width * 0.375;
		edges = evdev_device_mm_to_units(device, &mm);
		mb_le = edges.x;

		mm.x = width * 0.625;
		edges = evdev_device_mm_to_units(device, &mm);
		mb_re = edges.x;
590 591 592 593
	}

	tp->buttons.bottom_area.middlebutton_left_edge = mb_le;
	tp->buttons.bottom_area.rightbutton_left_edge = mb_re;
594 595 596 597 598 599 600
}

void
tp_init_top_softbuttons(struct tp_dispatch *tp,
			struct evdev_device *device,
			double topbutton_size_mult)
{
601
	struct device_coords edges;
602 603

	if (tp->buttons.has_topbuttons) {
604 605 606 607 608
		/* T440s has the top button line 5mm from the top, event
		   analysis has shown events to start down to ~10mm from the
		   top - which maps to 15%.  We allow the caller to enlarge the
		   area using a multiplier for the touchpad disabled case. */
		double topsize_mm = 10 * topbutton_size_mult;
609 610 611 612 613
		struct phys_coords mm;
		double width, height;

		evdev_device_get_size(device, &width, &height);

614
		mm.x = width * 0.60;
615 616 617 618
		mm.y = topsize_mm;
		edges = evdev_device_mm_to_units(device, &mm);
		tp->buttons.top_area.bottom_edge = edges.y;
		tp->buttons.top_area.rightbutton_left_edge = edges.x;
619

620
		mm.x = width * 0.40;
621 622
		edges = evdev_device_mm_to_units(device, &mm);
		tp->buttons.top_area.leftbutton_right_edge = edges.x;
623 624 625 626 627
	} else {
		tp->buttons.top_area.bottom_edge = INT_MIN;
	}
}

628 629 630
static inline uint32_t
tp_button_config_click_get_methods(struct libinput_device *device)
{
631
	struct evdev_device *evdev = evdev_device(device);
632 633 634 635 636 637 638 639 640
	struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
	uint32_t methods = LIBINPUT_CONFIG_CLICK_METHOD_NONE;

	if (tp->buttons.is_clickpad) {
		methods |= LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
		if (tp->has_mt)
			methods |= LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
	}

641 642 643
	if (evdev->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON)
		methods |= LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;

644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
	return methods;
}

static void
tp_switch_click_method(struct tp_dispatch *tp)
{
	/*
	 * All we need to do when switching click methods is to change the
	 * bottom_area.top_edge so that when in clickfinger mode the bottom
	 * touchpad area is not dead wrt finger movement starting there.
	 *
	 * We do not need to take any state into account, fingers which are
	 * already down will simply keep the state / area they have assigned
	 * until they are released, and the post_button_events path is state
	 * agnostic.
	 */

	switch (tp->buttons.click_method) {
	case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS:
		tp_init_softbuttons(tp, tp->device);
		break;
	case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER:
	case LIBINPUT_CONFIG_CLICK_METHOD_NONE:
		tp->buttons.bottom_area.top_edge = INT_MAX;
		break;
	}
}

static enum libinput_config_status
tp_button_config_click_set_method(struct libinput_device *device,
				  enum libinput_config_click_method method)
{
676
	struct evdev_device *evdev = evdev_device(device);
677 678 679 680 681 682 683 684 685 686 687
	struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;

	tp->buttons.click_method = method;
	tp_switch_click_method(tp);

	return LIBINPUT_CONFIG_STATUS_SUCCESS;
}

static enum libinput_config_click_method
tp_button_config_click_get_method(struct libinput_device *device)
{
688
	struct evdev_device *evdev = evdev_device(device);
689 690 691 692 693 694 695 696
	struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;

	return tp->buttons.click_method;
}

static enum libinput_config_click_method
tp_click_get_default_method(struct tp_dispatch *tp)
{
697
	struct evdev_device *device = tp->device;
698 699 700 701
	uint32_t clickfinger_models = EVDEV_MODEL_CHROMEBOOK |
				      EVDEV_MODEL_SYSTEM76_BONOBO |
				      EVDEV_MODEL_SYSTEM76_GALAGO |
				      EVDEV_MODEL_SYSTEM76_KUDU |
702 703 704 705 706
				      EVDEV_MODEL_CLEVO_W740SU |
				      EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON;

	if (device->model_flags & clickfinger_models)
		return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
707

708 709
	if (!tp->buttons.is_clickpad)
		return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
710
	else if (libevdev_get_id_vendor(tp->device->evdev) == VENDOR_ID_APPLE)
711
		return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
712 713

	return LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
714 715 716 717 718
}

static enum libinput_config_click_method
tp_button_config_click_get_default_method(struct libinput_device *device)
{
719
	struct evdev_device *evdev = evdev_device(device);
720 721 722 723 724
	struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;

	return tp_click_get_default_method(tp);
}

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 751 752 753
void
tp_clickpad_middlebutton_apply_config(struct evdev_device *device)
{
	struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;

	if (!tp->buttons.is_clickpad ||
	    tp->buttons.state != 0)
		return;

	if (device->middlebutton.want_enabled ==
	    device->middlebutton.enabled)
		return;

	device->middlebutton.enabled = device->middlebutton.want_enabled;
	if (tp->buttons.click_method ==
	    LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS)
		tp_init_softbuttons(tp, device);
}

static int
tp_clickpad_middlebutton_is_available(struct libinput_device *device)
{
	return evdev_middlebutton_is_available(device);
}

static enum libinput_config_status
tp_clickpad_middlebutton_set(struct libinput_device *device,
		     enum libinput_config_middle_emulation_state enable)
{
754
	struct evdev_device *evdev = evdev_device(device);
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798

	switch (enable) {
	case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED:
		evdev->middlebutton.want_enabled = true;
		break;
	case LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED:
		evdev->middlebutton.want_enabled = false;
		break;
	default:
		return LIBINPUT_CONFIG_STATUS_INVALID;
	}

	tp_clickpad_middlebutton_apply_config(evdev);

	return LIBINPUT_CONFIG_STATUS_SUCCESS;
}

static enum libinput_config_middle_emulation_state
tp_clickpad_middlebutton_get(struct libinput_device *device)
{
	return evdev_middlebutton_get(device);
}

static enum libinput_config_middle_emulation_state
tp_clickpad_middlebutton_get_default(struct libinput_device *device)
{
	return evdev_middlebutton_get_default(device);
}

static inline void
tp_init_clickpad_middlebutton_emulation(struct tp_dispatch *tp,
					struct evdev_device *device)
{
	device->middlebutton.enabled_default = false;
	device->middlebutton.want_enabled = false;
	device->middlebutton.enabled = false;

	device->middlebutton.config.available = tp_clickpad_middlebutton_is_available;
	device->middlebutton.config.set = tp_clickpad_middlebutton_set;
	device->middlebutton.config.get = tp_clickpad_middlebutton_get;
	device->middlebutton.config.get_default = tp_clickpad_middlebutton_get_default;
	device->base.config.middle_emulation = &device->middlebutton.config;
}

799 800 801 802 803 804 805
static inline void
tp_init_middlebutton_emulation(struct tp_dispatch *tp,
			       struct evdev_device *device)
{
	bool enable_by_default,
	     want_config_option;

806 807 808 809
	/* On clickpads we provide the config option but disable by default.
	   When enabled, the middle software button disappears */
	if (tp->buttons.is_clickpad) {
		tp_init_clickpad_middlebutton_emulation(tp, device);
810
		return;
811
	}
812 813 814 815 816 817 818 819 820

	/* init middle button emulation on non-clickpads, but only if we
	 * don't have a middle button. Exception: ALPS touchpads don't know
	 * if they have a middle button, so we always want the option there
	 * and enabled by default.
	 */
	if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE)) {
		enable_by_default = true;
		want_config_option = false;
821
	} else if (device->model_flags & EVDEV_MODEL_ALPS_TOUCHPAD) {
822 823 824 825 826 827 828 829 830 831
		enable_by_default = true;
		want_config_option = true;
	} else
		return;

	evdev_init_middlebutton(tp->device,
				enable_by_default,
				want_config_option);
}

832
void
833 834 835
tp_init_buttons(struct tp_dispatch *tp,
		struct evdev_device *device)
{
836
	struct tp_touch *t;
837
	const struct input_absinfo *absinfo_x, *absinfo_y;
838
	int i;
839

840 841
	tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
							INPUT_PROP_BUTTONPAD);
842 843
	tp->buttons.has_topbuttons = libevdev_has_property(device->evdev,
						        INPUT_PROP_TOPBUTTONPAD);
844

845
	if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
846 847
	    libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
		if (tp->buttons.is_clickpad)
848 849
			evdev_log_bug_kernel(device,
					     "clickpad advertising right button\n");
850
	} else if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) &&
851 852
		   !tp->buttons.is_clickpad &&
		   libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) {
853 854
			evdev_log_bug_kernel(device,
					     "non clickpad without right button?\n");
855
	}
856

857 858 859
	absinfo_x = device->abs.absinfo_x;
	absinfo_y = device->abs.absinfo_y;

860 861 862
	/* pinned-finger motion threshold, see tp_unpin_finger. */
	tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution;
	tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution;
863

864 865 866 867 868
	tp->buttons.config_method.get_methods = tp_button_config_click_get_methods;
	tp->buttons.config_method.set_method = tp_button_config_click_set_method;
	tp->buttons.config_method.get_method = tp_button_config_click_get_method;
	tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method;
	tp->device->base.config.click_method = &tp->buttons.config_method;
869

870 871 872 873
	tp->buttons.click_method = tp_click_get_default_method(tp);
	tp_switch_click_method(tp);

	tp_init_top_softbuttons(tp, device, 1.0);
874

875
	tp_init_middlebutton_emulation(tp, device);
876

877
	i = 0;
878
	tp_for_each_touch(tp, t) {
879 880 881 882 883 884 885 886
		char timer_name[64];
		i++;

		snprintf(timer_name,
			 sizeof(timer_name),
			 "%s (%d) button",
			 evdev_device_get_sysname(device),
			 i);
887 888
		t->button.state = BUTTON_STATE_NONE;
		libinput_timer_init(&t->button.timer,
889
				    tp_libinput_context(tp),
890
				    timer_name,
891 892
				    tp_button_handle_timeout, t);
	}
893 894
}

895
void
896
tp_remove_buttons(struct tp_dispatch *tp)
897
{
898 899
	struct tp_touch *t;

900
	tp_for_each_touch(tp, t) {
901
		libinput_timer_cancel(&t->button.timer);
902 903
		libinput_timer_destroy(&t->button.timer);
	}
904 905
}

906
static int
907
tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
908 909 910 911 912 913 914 915
{
	uint32_t current, old, button;

	current = tp->buttons.state;
	old = tp->buttons.old_state;
	button = BTN_LEFT;

	while (current || old) {
916
		enum libinput_button_state state;
917 918

		if ((current & 0x1) ^ (old & 0x1)) {
919 920
			uint32_t b;

921
			if (!!(current & 0x1))
922
				state = LIBINPUT_BUTTON_STATE_PRESSED;
923
			else
924
				state = LIBINPUT_BUTTON_STATE_RELEASED;
925

926
			b = evdev_to_left_handed(tp->device, button);
927 928 929 930
			evdev_pointer_notify_physical_button(tp->device,
							     time,
							     b,
							     state);
931 932 933 934 935 936 937 938 939 940
		}

		button++;
		current >>= 1;
		old >>= 1;
	}

	return 0;
}

941 942 943 944
static inline bool
tp_clickfinger_within_distance(struct tp_dispatch *tp,
			       struct tp_touch *t1,
			       struct tp_touch *t2)
945 946
{
	double x, y;
947
	bool within_distance = false;
948 949
	int xres, yres;
	int bottom_threshold;
950 951 952 953

	if (!t1 || !t2)
		return 0;

954 955
	if (t1->thumb.state == THUMB_STATE_YES ||
	    t2->thumb.state == THUMB_STATE_YES)
956 957
		return 0;

958 959 960
	x = abs(t1->point.x - t2->point.x);
	y = abs(t1->point.y - t2->point.y);

961 962 963 964
	xres = tp->device->abs.absinfo_x->resolution;
	yres = tp->device->abs.absinfo_y->resolution;
	x /= xres;
	y /= yres;
965

966 967 968 969 970
	/* maximum horiz spread is 40mm horiz, 30mm vert, anything wider
	 * than that is probably a gesture. */
	if (x > 40 || y > 30)
		goto out;

971
	within_distance = true;
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991

	/* if y spread is <= 20mm, they're definitely together. */
	if (y <= 20)
		goto out;

	/* if they're vertically spread between 20-40mm, they're not
	 * together if:
	 * - the touchpad's vertical size is >50mm, anything smaller is
	 *   unlikely to have a thumb resting on it
	 * - and one of the touches is in the bottom 20mm of the touchpad
	 *   and the other one isn't
	 */

	if (tp->device->abs.dimensions.y/yres < 50)
		goto out;

	bottom_threshold = tp->device->abs.absinfo_y->maximum - 20 * yres;
	if ((t1->point.y > bottom_threshold) !=
		    (t2->point.y > bottom_threshold))
		within_distance = 0;
992

993 994
out:
	return within_distance;
995 996
}

997 998 999 1000
static uint32_t
tp_clickfinger_set_button(struct tp_dispatch *tp)
{
	uint32_t button;
1001 1002 1003
	unsigned int nfingers = tp->nfingers_down;
	struct tp_touch *t;
	struct tp_touch *first = NULL,
1004
			*second = NULL;
1005

1006
	if (nfingers != 2)
1007 1008
		goto out;

1009
	/* two fingers down on the touchpad. Check for distance
1010 1011 1012 1013 1014
	 * between the fingers. */
	tp_for_each_touch(tp, t) {
		if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE)
			continue;

1015
		if (t->thumb.state == THUMB_STATE_YES)
1016 1017
			continue;

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
		if (!first)
			first = t;
		else if (!second)
			second = t;
	}

	if (!first || !second) {
		nfingers = 1;
		goto out;
	}

1029
	if (tp_clickfinger_within_distance(tp, first, second))
1030 1031 1032
		nfingers = 2;
	else
		nfingers = 1;
1033

1034 1035
out:
	switch (nfingers) {
1036 1037 1038 1039
	case 0:
	case 1: button = BTN_LEFT; break;
	case 2: button = BTN_RIGHT; break;
	default:
1040
		button = BTN_MIDDLE; break;
1041 1042 1043 1044 1045 1046
		break;
	}

	return button;
}

1047 1048 1049 1050 1051 1052
static int
tp_notify_clickpadbutton(struct tp_dispatch *tp,
			 uint64_t time,
			 uint32_t button,
			 uint32_t is_topbutton,
			 enum libinput_button_state state)
1053 1054 1055 1056 1057 1058
{
	/* If we've a trackpoint, send top buttons through the trackpoint */
	if (is_topbutton && tp->buttons.trackpoint) {
		struct evdev_dispatch *dispatch = tp->buttons.trackpoint->dispatch;
		struct input_event event;

1059
		event.time = us2tv(time);
1060 1061 1062
		event.type = EV_KEY;
		event.code = button;
		event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0;
1063 1064 1065 1066
		dispatch->interface->process(dispatch,
					     tp->buttons.trackpoint,
					     &event,
					     time);
1067
		return 1;
1068 1069
	}

1070
	/* Ignore button events not for the trackpoint while suspended */
1071
	if (tp->device->is_suspended)
1072 1073
		return 0;

1074 1075 1076 1077
	/* A button click always terminates edge scrolling, even if we
	 * don't end up sending a button event. */
	tp_edge_scroll_stop_events(tp, time);

1078 1079 1080 1081 1082
	/*
	 * If the user has requested clickfinger replace the button chosen
	 * by the softbutton code with one based on the number of fingers.
	 */
	if (tp->buttons.click_method == LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER &&
1083
	    state == LIBINPUT_BUTTON_STATE_PRESSED) {
1084
		button = tp_clickfinger_set_button(tp);
1085 1086 1087 1088 1089
		tp->buttons.active = button;

		if (!button)
			return 0;
	}
1090

1091
	evdev_pointer_notify_button(tp->device, time, button, state);
1092
	return 1;
1093 1094
}

1095
static int
1096
tp_post_clickpadbutton_buttons(struct tp_dispatch *tp, uint64_t time)
1097
{
1098
	uint32_t current, old, button, is_top;
1099
	enum libinput_button_state state;
1100
	enum { AREA = 0x01, LEFT = 0x02, MIDDLE = 0x04, RIGHT = 0x08 };
1101
	bool want_left_handed = true;
1102 1103 1104

	current = tp->buttons.state;
	old = tp->buttons.old_state;
1105
	is_top = 0;
1106

1107
	if (!tp->buttons.click_pending && current == old)
1108 1109 1110 1111
		return 0;

	if (current) {
		struct tp_touch *t;
1112
		uint32_t area = 0;
1113 1114

		tp_for_each_touch(tp, t) {
1115 1116
			switch (t->button.curr) {
			case BUTTON_EVENT_IN_AREA:
1117
				area |= AREA;
1118
				break;
1119
			case BUTTON_EVENT_IN_TOP_L:
1120
				is_top = 1;
1121
				/* fallthrough */
1122
			case BUTTON_EVENT_IN_BOTTOM_L:
1123
				area |= LEFT;
1124
				break;
1125
			case BUTTON_EVENT_IN_TOP_M:
1126
				is_top = 1;
1127 1128
				/* fallthrough */
			case BUTTON_EVENT_IN_BOTTOM_M:
1129
				area |= MIDDLE;
1130 1131
				break;
			case BUTTON_EVENT_IN_TOP_R:
1132
				is_top = 1;
1133
				/* fallthrough */
1134
			case BUTTON_EVENT_IN_BOTTOM_R:
1135
				area |= RIGHT;
1136 1137 1138 1139
				break;
			default:
				break;
			}
1140 1141
		}

1142 1143
		if (area == 0 &&
		    tp->buttons.click_method != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) {
1144 1145 1146
			/* No touches, wait for a touch before processing */
			tp->buttons.click_pending = true;
			return 0;
1147 1148
		}

1149 1150 1151 1152
		if ((tp->device->middlebutton.enabled || is_top) &&
		    (area & LEFT) && (area & RIGHT)) {
			button = BTN_MIDDLE;
		} else if (area & MIDDLE) {
1153 1154 1155 1156
			button = BTN_MIDDLE;
		} else if (area & RIGHT) {
			button = BTN_RIGHT;
		} else if (area & LEFT) {
1157
			button = BTN_LEFT;
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
		} else { /* main or no area (for clickfinger) is always BTN_LEFT */
			button = BTN_LEFT;
			want_left_handed = false;
		}

		if (is_top)
			want_left_handed = false;

		if (want_left_handed)
			button = evdev_to_left_handed(tp->device, button);
1168 1169

		tp->buttons.active = button;
1170
		tp->buttons.active_is_topbutton = is_top;
1171
		state = LIBINPUT_BUTTON_STATE_PRESSED;
1172 1173
	} else {
		button = tp->buttons.active;
1174
		is_top = tp->buttons.active_is_topbutton;
1175
		tp->buttons.active = 0;
1176
		tp->buttons.active_is_topbutton = 0;
1177
		state = LIBINPUT_BUTTON_STATE_RELEASED;
1178 1179
	}

1180 1181
	tp->buttons.click_pending = false;

1182
	if (button)
1183 1184 1185 1186 1187
		return tp_notify_clickpadbutton(tp,
						time,
						button,
						is_top,
						state);
1188
	return 0;
1189 1190
}

1191
int
1192
tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
1193
{
1194 1195
	if (tp->buttons.is_clickpad ||
	    tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON)
1196 1197 1198
		return tp_post_clickpadbutton_buttons(tp, time);
	else
		return tp_post_physical_buttons(tp, time);
1199
}
1200

1201
bool
1202 1203
tp_button_touch_active(const struct tp_dispatch *tp,
		       const struct tp_touch *t)
1204 1205 1206
{
	return t->button.state == BUTTON_STATE_AREA;
}
1207 1208

bool
1209 1210
tp_button_is_inside_softbutton_area(const struct tp_dispatch *tp,
				    const struct tp_touch *t)
1211
{
1212 1213
	return is_inside_top_button_area(tp, t) ||
	       is_inside_bottom_button_area(tp, t);
1214
}