2 * Copyright © 2014 Red Hat, Inc.
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 #include "linux/input.h"
30 #include "evdev-mt-touchpad.h"
32 #define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */
33 #define DEFAULT_BUTTON_ENTER_TIMEOUT 100 /* ms */
34 #define DEFAULT_BUTTON_LEAVE_TIMEOUT 300 /* ms */
36 /*****************************************
37 * BEFORE YOU EDIT THIS FILE, look at the state diagram in
38 * doc/touchpad-softbutton-state-machine.svg, or online at
39 * https://drive.google.com/file/d/0B1NwWmji69nocUs1cVJTbkdwMFk/edit?usp=sharing
40 * (it's a http://draw.io diagram)
42 * Any changes in this file must be represented in the diagram.
44 * The state machine only affects the soft button area code.
47 #define CASE_RETURN_STRING(a) case a: return #a;
49 static inline const char*
50 button_state_to_str(enum button_state state) {
52 CASE_RETURN_STRING(BUTTON_STATE_NONE);
53 CASE_RETURN_STRING(BUTTON_STATE_AREA);
54 CASE_RETURN_STRING(BUTTON_STATE_BOTTOM);
55 CASE_RETURN_STRING(BUTTON_STATE_TOP);
56 CASE_RETURN_STRING(BUTTON_STATE_TOP_NEW);
57 CASE_RETURN_STRING(BUTTON_STATE_TOP_TO_IGNORE);
58 CASE_RETURN_STRING(BUTTON_STATE_IGNORE);
63 static inline const char*
64 button_event_to_str(enum button_event event) {
66 CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_R);
67 CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_L);
68 CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_R);
69 CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_M);
70 CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_L);
71 CASE_RETURN_STRING(BUTTON_EVENT_IN_AREA);
72 CASE_RETURN_STRING(BUTTON_EVENT_UP);
73 CASE_RETURN_STRING(BUTTON_EVENT_PRESS);
74 CASE_RETURN_STRING(BUTTON_EVENT_RELEASE);
75 CASE_RETURN_STRING(BUTTON_EVENT_TIMEOUT);
81 is_inside_bottom_button_area(struct tp_dispatch *tp, struct tp_touch *t)
83 return t->y >= tp->buttons.bottom_area.top_edge;
87 is_inside_bottom_right_area(struct tp_dispatch *tp, struct tp_touch *t)
89 return is_inside_bottom_button_area(tp, t) &&
90 t->x > tp->buttons.bottom_area.rightbutton_left_edge;
94 is_inside_bottom_left_area(struct tp_dispatch *tp, struct tp_touch *t)
96 return is_inside_bottom_button_area(tp, t) &&
97 !is_inside_bottom_right_area(tp, t);
101 is_inside_top_button_area(struct tp_dispatch *tp, struct tp_touch *t)
103 return t->y <= tp->buttons.top_area.bottom_edge;
107 is_inside_top_right_area(struct tp_dispatch *tp, struct tp_touch *t)
109 return is_inside_top_button_area(tp, t) &&
110 t->x > tp->buttons.top_area.rightbutton_left_edge;
114 is_inside_top_left_area(struct tp_dispatch *tp, struct tp_touch *t)
116 return is_inside_top_button_area(tp, t) &&
117 t->x < tp->buttons.top_area.leftbutton_right_edge;
121 is_inside_top_middle_area(struct tp_dispatch *tp, struct tp_touch *t)
123 return is_inside_top_button_area(tp, t) &&
124 t->x >= tp->buttons.top_area.leftbutton_right_edge &&
125 t->x <= tp->buttons.top_area.rightbutton_left_edge;
129 tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t)
131 libinput_timer_set(&t->button.timer,
132 t->millis + DEFAULT_BUTTON_ENTER_TIMEOUT);
136 tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t)
138 libinput_timer_set(&t->button.timer,
139 t->millis + DEFAULT_BUTTON_LEAVE_TIMEOUT);
143 * tp_button_set_state, change state and implement on-entry behavior
144 * as described in the state machine diagram.
147 tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t,
148 enum button_state new_state, enum button_event event)
150 libinput_timer_cancel(&t->button.timer);
152 t->button.state = new_state;
153 switch (t->button.state) {
154 case BUTTON_STATE_NONE:
157 case BUTTON_STATE_AREA:
158 t->button.curr = BUTTON_EVENT_IN_AREA;
159 tp_set_pointer(tp, t);
161 case BUTTON_STATE_BOTTOM:
162 t->button.curr = event;
164 case BUTTON_STATE_TOP:
166 case BUTTON_STATE_TOP_NEW:
167 t->button.curr = event;
168 tp_button_set_enter_timer(tp, t);
170 case BUTTON_STATE_TOP_TO_IGNORE:
171 tp_button_set_leave_timer(tp, t);
173 case BUTTON_STATE_IGNORE:
180 tp_button_none_handle_event(struct tp_dispatch *tp,
182 enum button_event event)
185 case BUTTON_EVENT_IN_BOTTOM_R:
186 case BUTTON_EVENT_IN_BOTTOM_L:
187 tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
189 case BUTTON_EVENT_IN_TOP_R:
190 case BUTTON_EVENT_IN_TOP_M:
191 case BUTTON_EVENT_IN_TOP_L:
192 tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event);
194 case BUTTON_EVENT_IN_AREA:
195 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
197 case BUTTON_EVENT_UP:
198 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
200 case BUTTON_EVENT_PRESS:
201 case BUTTON_EVENT_RELEASE:
202 case BUTTON_EVENT_TIMEOUT:
208 tp_button_area_handle_event(struct tp_dispatch *tp,
210 enum button_event event)
213 case BUTTON_EVENT_IN_BOTTOM_R:
214 case BUTTON_EVENT_IN_BOTTOM_L:
215 case BUTTON_EVENT_IN_TOP_R:
216 case BUTTON_EVENT_IN_TOP_M:
217 case BUTTON_EVENT_IN_TOP_L:
218 case BUTTON_EVENT_IN_AREA:
220 case BUTTON_EVENT_UP:
221 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
223 case BUTTON_EVENT_PRESS:
224 case BUTTON_EVENT_RELEASE:
225 case BUTTON_EVENT_TIMEOUT:
231 tp_button_bottom_handle_event(struct tp_dispatch *tp,
233 enum button_event event)
236 case BUTTON_EVENT_IN_BOTTOM_R:
237 case BUTTON_EVENT_IN_BOTTOM_L:
238 if (event != t->button.curr)
239 tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM,
242 case BUTTON_EVENT_IN_TOP_R:
243 case BUTTON_EVENT_IN_TOP_M:
244 case BUTTON_EVENT_IN_TOP_L:
245 case BUTTON_EVENT_IN_AREA:
246 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
248 case BUTTON_EVENT_UP:
249 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
251 case BUTTON_EVENT_PRESS:
252 case BUTTON_EVENT_RELEASE:
253 case BUTTON_EVENT_TIMEOUT:
259 tp_button_top_handle_event(struct tp_dispatch *tp,
261 enum button_event event)
264 case BUTTON_EVENT_IN_BOTTOM_R:
265 case BUTTON_EVENT_IN_BOTTOM_L:
266 tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
268 case BUTTON_EVENT_IN_TOP_R:
269 case BUTTON_EVENT_IN_TOP_M:
270 case BUTTON_EVENT_IN_TOP_L:
271 if (event != t->button.curr)
272 tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
275 case BUTTON_EVENT_IN_AREA:
276 tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
278 case BUTTON_EVENT_UP:
279 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
281 case BUTTON_EVENT_PRESS:
282 case BUTTON_EVENT_RELEASE:
283 case BUTTON_EVENT_TIMEOUT:
289 tp_button_top_new_handle_event(struct tp_dispatch *tp,
291 enum button_event event)
294 case BUTTON_EVENT_IN_BOTTOM_R:
295 case BUTTON_EVENT_IN_BOTTOM_L:
296 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
298 case BUTTON_EVENT_IN_TOP_R:
299 case BUTTON_EVENT_IN_TOP_M:
300 case BUTTON_EVENT_IN_TOP_L:
301 if (event != t->button.curr)
302 tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
305 case BUTTON_EVENT_IN_AREA:
306 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
308 case BUTTON_EVENT_UP:
309 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
311 case BUTTON_EVENT_PRESS:
312 tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
314 case BUTTON_EVENT_RELEASE:
316 case BUTTON_EVENT_TIMEOUT:
317 tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
323 tp_button_top_to_ignore_handle_event(struct tp_dispatch *tp,
325 enum button_event event)
328 case BUTTON_EVENT_IN_TOP_R:
329 case BUTTON_EVENT_IN_TOP_M:
330 case BUTTON_EVENT_IN_TOP_L:
331 if (event == t->button.curr)
332 tp_button_set_state(tp, t, BUTTON_STATE_TOP,
335 tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
338 case BUTTON_EVENT_IN_BOTTOM_R:
339 case BUTTON_EVENT_IN_BOTTOM_L:
340 case BUTTON_EVENT_IN_AREA:
342 case BUTTON_EVENT_UP:
343 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
345 case BUTTON_EVENT_PRESS:
346 case BUTTON_EVENT_RELEASE:
348 case BUTTON_EVENT_TIMEOUT:
349 tp_button_set_state(tp, t, BUTTON_STATE_IGNORE, event);
355 tp_button_ignore_handle_event(struct tp_dispatch *tp,
357 enum button_event event)
360 case BUTTON_EVENT_IN_BOTTOM_R:
361 case BUTTON_EVENT_IN_BOTTOM_L:
362 case BUTTON_EVENT_IN_TOP_R:
363 case BUTTON_EVENT_IN_TOP_M:
364 case BUTTON_EVENT_IN_TOP_L:
365 case BUTTON_EVENT_IN_AREA:
367 case BUTTON_EVENT_UP:
368 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
370 case BUTTON_EVENT_PRESS:
371 case BUTTON_EVENT_RELEASE:
372 case BUTTON_EVENT_TIMEOUT:
378 tp_button_handle_event(struct tp_dispatch *tp,
380 enum button_event event,
383 struct libinput *libinput = tp->device->base.seat->libinput;
384 enum button_state current = t->button.state;
386 switch(t->button.state) {
387 case BUTTON_STATE_NONE:
388 tp_button_none_handle_event(tp, t, event);
390 case BUTTON_STATE_AREA:
391 tp_button_area_handle_event(tp, t, event);
393 case BUTTON_STATE_BOTTOM:
394 tp_button_bottom_handle_event(tp, t, event);
396 case BUTTON_STATE_TOP:
397 tp_button_top_handle_event(tp, t, event);
399 case BUTTON_STATE_TOP_NEW:
400 tp_button_top_new_handle_event(tp, t, event);
402 case BUTTON_STATE_TOP_TO_IGNORE:
403 tp_button_top_to_ignore_handle_event(tp, t, event);
405 case BUTTON_STATE_IGNORE:
406 tp_button_ignore_handle_event(tp, t, event);
410 if (current != t->button.state)
412 "button state: from %s, event %s to %s\n",
413 button_state_to_str(current),
414 button_event_to_str(event),
415 button_state_to_str(t->button.state));
419 tp_button_handle_state(struct tp_dispatch *tp, uint64_t time)
423 tp_for_each_touch(tp, t) {
424 if (t->state == TOUCH_NONE)
427 if (t->state == TOUCH_END) {
428 tp_button_handle_event(tp, t, BUTTON_EVENT_UP, time);
429 } else if (t->dirty) {
430 if (is_inside_bottom_right_area(tp, t))
431 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_R, time);
432 else if (is_inside_bottom_left_area(tp, t))
433 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_L, time);
434 else if (is_inside_top_right_area(tp, t))
435 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_R, time);
436 else if (is_inside_top_middle_area(tp, t))
437 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_M, time);
438 else if (is_inside_top_left_area(tp, t))
439 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_L, time);
441 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_AREA, time);
443 if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
444 tp_button_handle_event(tp, t, BUTTON_EVENT_RELEASE, time);
445 if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
446 tp_button_handle_event(tp, t, BUTTON_EVENT_PRESS, time);
453 tp_button_handle_timeout(uint64_t now, void *data)
455 struct tp_touch *t = data;
457 tp_button_handle_event(t->tp, t, BUTTON_EVENT_TIMEOUT, now);
461 tp_process_button(struct tp_dispatch *tp,
462 const struct input_event *e,
465 struct libinput *libinput = tp->device->base.seat->libinput;
466 uint32_t mask = 1 << (e->code - BTN_LEFT);
468 /* Ignore other buttons on clickpads */
469 if (tp->buttons.is_clickpad && e->code != BTN_LEFT) {
470 log_bug_kernel(libinput,
471 "received %s button event on a clickpad\n",
472 libevdev_event_code_get_name(EV_KEY, e->code));
477 tp->buttons.state |= mask;
478 tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS;
480 tp->buttons.state &= ~mask;
481 tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
488 tp_release_all_buttons(struct tp_dispatch *tp,
491 if (tp->buttons.state) {
492 tp->buttons.state = 0;
493 tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
498 tp_init_softbuttons(struct tp_dispatch *tp,
499 struct evdev_device *device,
500 double topbutton_size_mult)
503 const struct input_absinfo *absinfo_x, *absinfo_y;
504 int xoffset, yoffset;
507 absinfo_x = device->abs.absinfo_x;
508 absinfo_y = device->abs.absinfo_y;
510 xoffset = absinfo_x->minimum,
511 yoffset = absinfo_y->minimum;
512 yres = absinfo_y->resolution;
513 width = abs(absinfo_x->maximum - absinfo_x->minimum);
514 height = abs(absinfo_y->maximum - absinfo_y->minimum);
516 /* button height: 10mm or 15% of the touchpad height,
517 whichever is smaller */
518 if (yres > 1 && (height * 0.15/yres) > 10) {
519 tp->buttons.bottom_area.top_edge =
520 absinfo_y->maximum - 10 * yres;
522 tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
525 tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
527 if (tp->buttons.has_topbuttons) {
528 /* T440s has the top button line 5mm from the top, event
529 analysis has shown events to start down to ~10mm from the
530 top - which maps to 15%. We allow the caller to enlarge the
531 area using a multiplier for the touchpad disabled case. */
532 double topsize_mm = 10 * topbutton_size_mult;
533 double topsize_pct = .15 * topbutton_size_mult;
536 tp->buttons.top_area.bottom_edge =
537 yoffset + topsize_mm * yres;
539 tp->buttons.top_area.bottom_edge = height * topsize_pct + yoffset;
541 tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
542 tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
544 tp->buttons.top_area.bottom_edge = INT_MIN;
549 tp_init_buttons(struct tp_dispatch *tp,
550 struct evdev_device *device)
552 struct libinput *libinput = tp->device->base.seat->libinput;
556 const struct input_absinfo *absinfo_x, *absinfo_y;
558 tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
559 INPUT_PROP_BUTTONPAD);
560 tp->buttons.has_topbuttons = libevdev_has_property(device->evdev,
561 INPUT_PROP_TOPBUTTONPAD);
563 if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
564 libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
565 if (tp->buttons.is_clickpad)
566 log_bug_kernel(libinput,
567 "%s: clickpad advertising right button\n",
570 if (!tp->buttons.is_clickpad)
571 log_bug_kernel(libinput,
572 "%s: non clickpad without right button?\n",
576 absinfo_x = device->abs.absinfo_x;
577 absinfo_y = device->abs.absinfo_y;
579 width = abs(absinfo_x->maximum - absinfo_x->minimum);
580 height = abs(absinfo_y->maximum - absinfo_y->minimum);
581 diagonal = sqrt(width*width + height*height);
583 tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
585 if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
586 tp->buttons.use_clickfinger = true;
588 if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
589 tp_init_softbuttons(tp, device, 1.0);
591 tp->buttons.bottom_area.top_edge = INT_MAX;
592 tp->buttons.top_area.bottom_edge = INT_MIN;
595 tp_for_each_touch(tp, t) {
596 t->button.state = BUTTON_STATE_NONE;
597 libinput_timer_init(&t->button.timer,
598 tp->device->base.seat->libinput,
599 tp_button_handle_timeout, t);
606 tp_destroy_buttons(struct tp_dispatch *tp)
610 tp_for_each_touch(tp, t)
611 libinput_timer_cancel(&t->button.timer);
615 tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
617 uint32_t current, old, button;
618 enum libinput_button_state state;
620 current = tp->buttons.state;
621 old = tp->buttons.old_state;
627 switch (tp->nfingers_down) {
628 case 1: button = BTN_LEFT; break;
629 case 2: button = BTN_RIGHT; break;
630 case 3: button = BTN_MIDDLE; break;
634 tp->buttons.active = button;
635 state = LIBINPUT_BUTTON_STATE_PRESSED;
637 button = tp->buttons.active;
638 tp->buttons.active = 0;
639 state = LIBINPUT_BUTTON_STATE_RELEASED;
643 evdev_pointer_notify_button(tp->device,
652 tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
654 uint32_t current, old, button;
656 current = tp->buttons.state;
657 old = tp->buttons.old_state;
660 while (current || old) {
661 enum libinput_button_state state;
663 if ((current & 0x1) ^ (old & 0x1)) {
666 if (!!(current & 0x1))
667 state = LIBINPUT_BUTTON_STATE_PRESSED;
669 state = LIBINPUT_BUTTON_STATE_RELEASED;
671 b = evdev_to_left_handed(tp->device, button);
672 evdev_pointer_notify_button(tp->device,
687 tp_notify_softbutton(struct tp_dispatch *tp,
690 uint32_t is_topbutton,
691 enum libinput_button_state state)
693 /* If we've a trackpoint, send top buttons through the trackpoint */
694 if (is_topbutton && tp->buttons.trackpoint) {
695 struct evdev_dispatch *dispatch = tp->buttons.trackpoint->dispatch;
696 struct input_event event;
698 event.time.tv_sec = time/1000;
699 event.time.tv_usec = (time % 1000) * 1000;
702 event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0;
703 dispatch->interface->process(dispatch, tp->buttons.trackpoint,
708 /* Ignore button events not for the trackpoint while suspended */
709 if (tp->device->suspended)
712 evdev_pointer_notify_button(tp->device, time, button, state);
716 tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
718 uint32_t current, old, button, is_top;
719 enum libinput_button_state state;
720 enum { AREA = 0x01, LEFT = 0x02, MIDDLE = 0x04, RIGHT = 0x08 };
722 current = tp->buttons.state;
723 old = tp->buttons.old_state;
727 if (!tp->buttons.click_pending && current == old)
733 tp_for_each_touch(tp, t) {
734 switch (t->button.curr) {
735 case BUTTON_EVENT_IN_AREA:
738 case BUTTON_EVENT_IN_TOP_L:
740 case BUTTON_EVENT_IN_BOTTOM_L:
743 case BUTTON_EVENT_IN_TOP_M:
747 case BUTTON_EVENT_IN_TOP_R:
749 case BUTTON_EVENT_IN_BOTTOM_R:
758 /* No touches, wait for a touch before processing */
759 tp->buttons.click_pending = true;
763 if ((button & MIDDLE) || ((button & LEFT) && (button & RIGHT)))
764 button = evdev_to_left_handed(tp->device, BTN_MIDDLE);
765 else if (button & RIGHT)
766 button = evdev_to_left_handed(tp->device, BTN_RIGHT);
767 else if (button & LEFT)
768 button = evdev_to_left_handed(tp->device, BTN_LEFT);
769 else /* main area is always BTN_LEFT */
772 tp->buttons.active = button;
773 tp->buttons.active_is_topbutton = is_top;
774 state = LIBINPUT_BUTTON_STATE_PRESSED;
776 button = tp->buttons.active;
777 is_top = tp->buttons.active_is_topbutton;
778 tp->buttons.active = 0;
779 tp->buttons.active_is_topbutton = 0;
780 state = LIBINPUT_BUTTON_STATE_RELEASED;
783 tp->buttons.click_pending = false;
786 tp_notify_softbutton(tp, time, button, is_top, state);
792 tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
794 if (tp->buttons.is_clickpad) {
795 if (tp->buttons.use_clickfinger)
796 return tp_post_clickfinger_buttons(tp, time);
798 return tp_post_softbutton_buttons(tp, time);
801 return tp_post_physical_buttons(tp, time);
805 tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
807 return t->button.state == BUTTON_STATE_AREA;
811 tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t)
813 return is_inside_top_button_area(tp, t) || is_inside_bottom_button_area(tp, t);