touchpad: drop the BOTTOM_TO_AREA/BOTTOM_NEW states
[platform/upstream/libinput.git] / src / evdev-mt-touchpad-buttons.c
1 /*
2  * Copyright © 2014 Red Hat, Inc.
3  *
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.
13  *
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.
21  */
22
23 #include <errno.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include "linux/input.h"
29
30 #include "evdev-mt-touchpad.h"
31
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 */
35
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)
41  *
42  * Any changes in this file must be represented in the diagram.
43  *
44  * The state machine only affects the soft button area code.
45  */
46
47 #define CASE_RETURN_STRING(a) case a: return #a;
48
49 static inline const char*
50 button_state_to_str(enum button_state state) {
51         switch(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);
59         }
60         return NULL;
61 }
62
63 static inline const char*
64 button_event_to_str(enum button_event event) {
65         switch(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);
76         }
77         return NULL;
78 }
79
80 static inline bool
81 is_inside_bottom_button_area(struct tp_dispatch *tp, struct tp_touch *t)
82 {
83         return t->y >= tp->buttons.bottom_area.top_edge;
84 }
85
86 static inline bool
87 is_inside_bottom_right_area(struct tp_dispatch *tp, struct tp_touch *t)
88 {
89         return is_inside_bottom_button_area(tp, t) &&
90                t->x > tp->buttons.bottom_area.rightbutton_left_edge;
91 }
92
93 static inline bool
94 is_inside_bottom_left_area(struct tp_dispatch *tp, struct tp_touch *t)
95 {
96         return is_inside_bottom_button_area(tp, t) &&
97                !is_inside_bottom_right_area(tp, t);
98 }
99
100 static inline bool
101 is_inside_top_button_area(struct tp_dispatch *tp, struct tp_touch *t)
102 {
103         return t->y <= tp->buttons.top_area.bottom_edge;
104 }
105
106 static inline bool
107 is_inside_top_right_area(struct tp_dispatch *tp, struct tp_touch *t)
108 {
109         return is_inside_top_button_area(tp, t) &&
110                t->x > tp->buttons.top_area.rightbutton_left_edge;
111 }
112
113 static inline bool
114 is_inside_top_left_area(struct tp_dispatch *tp, struct tp_touch *t)
115 {
116         return is_inside_top_button_area(tp, t) &&
117                t->x < tp->buttons.top_area.leftbutton_right_edge;
118 }
119
120 static inline bool
121 is_inside_top_middle_area(struct tp_dispatch *tp, struct tp_touch *t)
122 {
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;
126 }
127
128 static void
129 tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t)
130 {
131         libinput_timer_set(&t->button.timer,
132                            t->millis + DEFAULT_BUTTON_ENTER_TIMEOUT);
133 }
134
135 static void
136 tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t)
137 {
138         libinput_timer_set(&t->button.timer,
139                            t->millis + DEFAULT_BUTTON_LEAVE_TIMEOUT);
140 }
141
142 /*
143  * tp_button_set_state, change state and implement on-entry behavior
144  * as described in the state machine diagram.
145  */
146 static void
147 tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t,
148                     enum button_state new_state, enum button_event event)
149 {
150         libinput_timer_cancel(&t->button.timer);
151
152         t->button.state = new_state;
153         switch (t->button.state) {
154         case BUTTON_STATE_NONE:
155                 t->button.curr = 0;
156                 break;
157         case BUTTON_STATE_AREA:
158                 t->button.curr = BUTTON_EVENT_IN_AREA;
159                 tp_set_pointer(tp, t);
160                 break;
161         case BUTTON_STATE_BOTTOM:
162                 t->button.curr = event;
163                 break;
164         case BUTTON_STATE_TOP:
165                 break;
166         case BUTTON_STATE_TOP_NEW:
167                 t->button.curr = event;
168                 tp_button_set_enter_timer(tp, t);
169                 break;
170         case BUTTON_STATE_TOP_TO_IGNORE:
171                 tp_button_set_leave_timer(tp, t);
172                 break;
173         case BUTTON_STATE_IGNORE:
174                 t->button.curr = 0;
175                 break;
176         }
177 }
178
179 static void
180 tp_button_none_handle_event(struct tp_dispatch *tp,
181                             struct tp_touch *t,
182                             enum button_event event)
183 {
184         switch (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);
188                 break;
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);
193                 break;
194         case BUTTON_EVENT_IN_AREA:
195                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
196                 break;
197         case BUTTON_EVENT_UP:
198                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
199                 break;
200         case BUTTON_EVENT_PRESS:
201         case BUTTON_EVENT_RELEASE:
202         case BUTTON_EVENT_TIMEOUT:
203                 break;
204         }
205 }
206
207 static void
208 tp_button_area_handle_event(struct tp_dispatch *tp,
209                             struct tp_touch *t,
210                             enum button_event event)
211 {
212         switch (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:
219                 break;
220         case BUTTON_EVENT_UP:
221                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
222                 break;
223         case BUTTON_EVENT_PRESS:
224         case BUTTON_EVENT_RELEASE:
225         case BUTTON_EVENT_TIMEOUT:
226                 break;
227         }
228 }
229
230 static void
231 tp_button_bottom_handle_event(struct tp_dispatch *tp,
232                               struct tp_touch *t,
233                               enum button_event event)
234 {
235         switch (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,
240                                             event);
241                 break;
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);
247                 break;
248         case BUTTON_EVENT_UP:
249                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
250                 break;
251         case BUTTON_EVENT_PRESS:
252         case BUTTON_EVENT_RELEASE:
253         case BUTTON_EVENT_TIMEOUT:
254                 break;
255         }
256 }
257
258 static void
259 tp_button_top_handle_event(struct tp_dispatch *tp,
260                             struct tp_touch *t,
261                             enum button_event event)
262 {
263         switch (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);
267                 break;
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,
273                                             event);
274                 break;
275         case BUTTON_EVENT_IN_AREA:
276                 tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
277                 break;
278         case BUTTON_EVENT_UP:
279                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
280                 break;
281         case BUTTON_EVENT_PRESS:
282         case BUTTON_EVENT_RELEASE:
283         case BUTTON_EVENT_TIMEOUT:
284                 break;
285         }
286 }
287
288 static void
289 tp_button_top_new_handle_event(struct tp_dispatch *tp,
290                                 struct tp_touch *t,
291                                 enum button_event event)
292 {
293         switch(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);
297                 break;
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,
303                                             event);
304                 break;
305         case BUTTON_EVENT_IN_AREA:
306                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
307                 break;
308         case BUTTON_EVENT_UP:
309                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
310                 break;
311         case BUTTON_EVENT_PRESS:
312                 tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
313                 break;
314         case BUTTON_EVENT_RELEASE:
315                 break;
316         case BUTTON_EVENT_TIMEOUT:
317                 tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
318                 break;
319         }
320 }
321
322 static void
323 tp_button_top_to_ignore_handle_event(struct tp_dispatch *tp,
324                                       struct tp_touch *t,
325                                       enum button_event event)
326 {
327         switch(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,
333                                             event);
334                 else
335                         tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
336                                             event);
337                 break;
338         case BUTTON_EVENT_IN_BOTTOM_R:
339         case BUTTON_EVENT_IN_BOTTOM_L:
340         case BUTTON_EVENT_IN_AREA:
341                 break;
342         case BUTTON_EVENT_UP:
343                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
344                 break;
345         case BUTTON_EVENT_PRESS:
346         case BUTTON_EVENT_RELEASE:
347                 break;
348         case BUTTON_EVENT_TIMEOUT:
349                 tp_button_set_state(tp, t, BUTTON_STATE_IGNORE, event);
350                 break;
351         }
352 }
353
354 static void
355 tp_button_ignore_handle_event(struct tp_dispatch *tp,
356                             struct tp_touch *t,
357                             enum button_event event)
358 {
359         switch (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:
366                 break;
367         case BUTTON_EVENT_UP:
368                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
369                 break;
370         case BUTTON_EVENT_PRESS:
371         case BUTTON_EVENT_RELEASE:
372         case BUTTON_EVENT_TIMEOUT:
373                 break;
374         }
375 }
376
377 static void
378 tp_button_handle_event(struct tp_dispatch *tp,
379                        struct tp_touch *t,
380                        enum button_event event,
381                        uint64_t time)
382 {
383         struct libinput *libinput = tp->device->base.seat->libinput;
384         enum button_state current = t->button.state;
385
386         switch(t->button.state) {
387         case BUTTON_STATE_NONE:
388                 tp_button_none_handle_event(tp, t, event);
389                 break;
390         case BUTTON_STATE_AREA:
391                 tp_button_area_handle_event(tp, t, event);
392                 break;
393         case BUTTON_STATE_BOTTOM:
394                 tp_button_bottom_handle_event(tp, t, event);
395                 break;
396         case BUTTON_STATE_TOP:
397                 tp_button_top_handle_event(tp, t, event);
398                 break;
399         case BUTTON_STATE_TOP_NEW:
400                 tp_button_top_new_handle_event(tp, t, event);
401                 break;
402         case BUTTON_STATE_TOP_TO_IGNORE:
403                 tp_button_top_to_ignore_handle_event(tp, t, event);
404                 break;
405         case BUTTON_STATE_IGNORE:
406                 tp_button_ignore_handle_event(tp, t, event);
407                 break;
408         }
409
410         if (current != t->button.state)
411                 log_debug(libinput,
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));
416 }
417
418 int
419 tp_button_handle_state(struct tp_dispatch *tp, uint64_t time)
420 {
421         struct tp_touch *t;
422
423         tp_for_each_touch(tp, t) {
424                 if (t->state == TOUCH_NONE)
425                         continue;
426
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);
440                         else
441                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_AREA, time);
442                 }
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);
447         }
448
449         return 0;
450 }
451
452 static void
453 tp_button_handle_timeout(uint64_t now, void *data)
454 {
455         struct tp_touch *t = data;
456
457         tp_button_handle_event(t->tp, t, BUTTON_EVENT_TIMEOUT, now);
458 }
459
460 int
461 tp_process_button(struct tp_dispatch *tp,
462                   const struct input_event *e,
463                   uint64_t time)
464 {
465         struct libinput *libinput = tp->device->base.seat->libinput;
466         uint32_t mask = 1 << (e->code - BTN_LEFT);
467
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));
473                 return 0;
474         }
475
476         if (e->value) {
477                 tp->buttons.state |= mask;
478                 tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS;
479         } else {
480                 tp->buttons.state &= ~mask;
481                 tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
482         }
483
484         return 0;
485 }
486
487 int
488 tp_init_buttons(struct tp_dispatch *tp,
489                 struct evdev_device *device)
490 {
491         struct libinput *libinput = tp->device->base.seat->libinput;
492         struct tp_touch *t;
493         int width, height;
494         double diagonal;
495         const struct input_absinfo *absinfo_x, *absinfo_y;
496
497         tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
498                                                         INPUT_PROP_BUTTONPAD);
499         tp->buttons.has_topbuttons = libevdev_has_property(device->evdev,
500                                                         INPUT_PROP_TOPBUTTONPAD);
501
502         if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
503             libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
504                 if (tp->buttons.is_clickpad)
505                         log_bug_kernel(libinput,
506                                        "%s: clickpad advertising right button\n",
507                                        device->sysname);
508         } else {
509                 if (!tp->buttons.is_clickpad)
510                         log_bug_kernel(libinput,
511                                        "%s: non clickpad without right button?\n",
512                                        device->sysname);
513         }
514
515         absinfo_x = device->abs.absinfo_x;
516         absinfo_y = device->abs.absinfo_y;
517
518         width = abs(absinfo_x->maximum - absinfo_x->minimum);
519         height = abs(absinfo_y->maximum - absinfo_y->minimum);
520         diagonal = sqrt(width*width + height*height);
521
522         tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
523
524         if (libevdev_get_id_vendor(device->evdev) == 0x5ac) /* Apple */
525                 tp->buttons.use_clickfinger = true;
526
527         if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
528                 int xoffset = absinfo_x->minimum,
529                     yoffset = absinfo_y->minimum;
530                 int yres = absinfo_y->resolution;
531
532                 /* button height: 10mm or 15% of the touchpad height,
533                    whichever is smaller */
534                 if (yres > 1 && (height * 0.15/yres) > 10) {
535                         tp->buttons.bottom_area.top_edge =
536                                 absinfo_y->maximum - 10 * yres;
537                 } else {
538                         tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
539                 }
540
541                 tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
542
543                 if (tp->buttons.has_topbuttons) {
544                         /* T440s has the top button line 5mm from the top,
545                            make the buttons 6mm high */
546                         if (yres > 1) {
547                                 tp->buttons.top_area.bottom_edge =
548                                         yoffset + 6 * yres;
549                         } else {
550                                 tp->buttons.top_area.bottom_edge = height * .08 + yoffset;
551                         }
552                         tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
553                         tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
554                 } else {
555                         tp->buttons.top_area.bottom_edge = INT_MIN;
556                 }
557         } else {
558                 tp->buttons.bottom_area.top_edge = INT_MAX;
559                 tp->buttons.top_area.bottom_edge = INT_MIN;
560         }
561
562         tp_for_each_touch(tp, t) {
563                 t->button.state = BUTTON_STATE_NONE;
564                 libinput_timer_init(&t->button.timer,
565                                     tp->device->base.seat->libinput,
566                                     tp_button_handle_timeout, t);
567         }
568
569         return 0;
570 }
571
572 void
573 tp_destroy_buttons(struct tp_dispatch *tp)
574 {
575         struct tp_touch *t;
576
577         tp_for_each_touch(tp, t)
578                 libinput_timer_cancel(&t->button.timer);
579 }
580
581 static int
582 tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
583 {
584         uint32_t current, old, button;
585         enum libinput_button_state state;
586
587         current = tp->buttons.state;
588         old = tp->buttons.old_state;
589
590         if (current == old)
591                 return 0;
592
593         if (current) {
594                 switch (tp->nfingers_down) {
595                 case 1: button = BTN_LEFT; break;
596                 case 2: button = BTN_RIGHT; break;
597                 case 3: button = BTN_MIDDLE; break;
598                 default:
599                         return 0;
600                 }
601                 tp->buttons.active = button;
602                 state = LIBINPUT_BUTTON_STATE_PRESSED;
603         } else {
604                 button = tp->buttons.active;
605                 tp->buttons.active = 0;
606                 state = LIBINPUT_BUTTON_STATE_RELEASED;
607         }
608
609         if (button)
610                 pointer_notify_button(&tp->device->base,
611                                       time,
612                                       button,
613                                       state);
614         return 1;
615 }
616
617 static int
618 tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
619 {
620         uint32_t current, old, button;
621
622         current = tp->buttons.state;
623         old = tp->buttons.old_state;
624         button = BTN_LEFT;
625
626         while (current || old) {
627                 enum libinput_button_state state;
628
629                 if ((current & 0x1) ^ (old & 0x1)) {
630                         if (!!(current & 0x1))
631                                 state = LIBINPUT_BUTTON_STATE_PRESSED;
632                         else
633                                 state = LIBINPUT_BUTTON_STATE_RELEASED;
634
635                         pointer_notify_button(&tp->device->base,
636                                               time,
637                                               button,
638                                               state);
639                 }
640
641                 button++;
642                 current >>= 1;
643                 old >>= 1;
644         }
645
646         return 0;
647 }
648
649 static int
650 tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
651 {
652         uint32_t current, old, button;
653         enum libinput_button_state state;
654         enum { AREA = 0x01, LEFT = 0x02, MIDDLE = 0x04, RIGHT = 0x08 };
655
656         current = tp->buttons.state;
657         old = tp->buttons.old_state;
658         button = 0;
659
660         if (!tp->buttons.click_pending && current == old)
661                 return 0;
662
663         if (current) {
664                 struct tp_touch *t;
665
666                 tp_for_each_touch(tp, t) {
667                         switch (t->button.curr) {
668                         case BUTTON_EVENT_IN_AREA:
669                                 button |= AREA;
670                                 break;
671                         case BUTTON_EVENT_IN_BOTTOM_L:
672                         case BUTTON_EVENT_IN_TOP_L:
673                                 button |= LEFT;
674                                 break;
675                         case BUTTON_EVENT_IN_TOP_M:
676                                 button |= MIDDLE;
677                                 break;
678                         case BUTTON_EVENT_IN_BOTTOM_R:
679                         case BUTTON_EVENT_IN_TOP_R:
680                                 button |= RIGHT;
681                                 break;
682                         default:
683                                 break;
684                         }
685                 }
686
687                 if (button == 0) {
688                         /* No touches, wait for a touch before processing */
689                         tp->buttons.click_pending = true;
690                         return 0;
691                 }
692
693                 if ((button & MIDDLE) || ((button & LEFT) && (button & RIGHT)))
694                         button = BTN_MIDDLE;
695                 else if (button & RIGHT)
696                         button = BTN_RIGHT;
697                 else
698                         button = BTN_LEFT;
699
700                 tp->buttons.active = button;
701                 state = LIBINPUT_BUTTON_STATE_PRESSED;
702         } else {
703                 button = tp->buttons.active;
704                 tp->buttons.active = 0;
705                 state = LIBINPUT_BUTTON_STATE_RELEASED;
706         }
707
708         tp->buttons.click_pending = false;
709
710         if (button)
711                 pointer_notify_button(&tp->device->base,
712                                       time,
713                                       button,
714                                       state);
715         return 1;
716 }
717
718 int
719 tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
720 {
721         if (tp->buttons.is_clickpad) {
722                 if (tp->buttons.use_clickfinger)
723                         return tp_post_clickfinger_buttons(tp, time);
724                 else
725                         return tp_post_softbutton_buttons(tp, time);
726         }
727
728         return tp_post_physical_buttons(tp, time);
729 }
730
731 int
732 tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
733 {
734         return t->button.state == BUTTON_STATE_AREA;
735 }