touchpad: use the evdev device's filter struct
[platform/upstream/libinput.git] / src / evdev-mt-touchpad-buttons.c
index 2ac231c..21417ab 100644 (file)
@@ -52,8 +52,6 @@ button_state_to_str(enum button_state state) {
        CASE_RETURN_STRING(BUTTON_STATE_NONE);
        CASE_RETURN_STRING(BUTTON_STATE_AREA);
        CASE_RETURN_STRING(BUTTON_STATE_BOTTOM);
-       CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_NEW);
-       CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_TO_AREA);
        CASE_RETURN_STRING(BUTTON_STATE_TOP);
        CASE_RETURN_STRING(BUTTON_STATE_TOP_NEW);
        CASE_RETURN_STRING(BUTTON_STATE_TOP_TO_IGNORE);
@@ -161,13 +159,7 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t,
                tp_set_pointer(tp, t);
                break;
        case BUTTON_STATE_BOTTOM:
-               break;
-       case BUTTON_STATE_BOTTOM_NEW:
                t->button.curr = event;
-               tp_button_set_enter_timer(tp, t);
-               break;
-       case BUTTON_STATE_BOTTOM_TO_AREA:
-               tp_button_set_leave_timer(tp, t);
                break;
        case BUTTON_STATE_TOP:
                break;
@@ -192,7 +184,7 @@ tp_button_none_handle_event(struct tp_dispatch *tp,
        switch (event) {
        case BUTTON_EVENT_IN_BOTTOM_R:
        case BUTTON_EVENT_IN_BOTTOM_L:
-               tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, event);
+               tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
                break;
        case BUTTON_EVENT_IN_TOP_R:
        case BUTTON_EVENT_IN_TOP_M:
@@ -237,92 +229,28 @@ tp_button_area_handle_event(struct tp_dispatch *tp,
 
 static void
 tp_button_bottom_handle_event(struct tp_dispatch *tp,
-                           struct tp_touch *t,
-                           enum button_event event)
+                             struct tp_touch *t,
+                             enum button_event event)
 {
        switch (event) {
        case BUTTON_EVENT_IN_BOTTOM_R:
        case BUTTON_EVENT_IN_BOTTOM_L:
                if (event != t->button.curr)
-                       tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
-                                           event);
-               break;
-       case BUTTON_EVENT_IN_TOP_R:
-       case BUTTON_EVENT_IN_TOP_M:
-       case BUTTON_EVENT_IN_TOP_L:
-       case BUTTON_EVENT_IN_AREA:
-               tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_TO_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_bottom_new_handle_event(struct tp_dispatch *tp,
-                               struct tp_touch *t,
-                               enum button_event event)
-{
-       switch(event) {
-       case BUTTON_EVENT_IN_BOTTOM_R:
-       case BUTTON_EVENT_IN_BOTTOM_L:
-               if (event != t->button.curr)
-                       tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
-                                           event);
-               break;
-       case BUTTON_EVENT_IN_TOP_R:
-       case BUTTON_EVENT_IN_TOP_M:
-       case BUTTON_EVENT_IN_TOP_L:
-       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_BOTTOM, event);
-               break;
-       case BUTTON_EVENT_RELEASE:
-               break;
-       case BUTTON_EVENT_TIMEOUT:
-               tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
-               break;
-       }
-}
-
-static void
-tp_button_bottom_to_area_handle_event(struct tp_dispatch *tp,
-                                     struct tp_touch *t,
-                                     enum button_event event)
-{
-       switch(event) {
-       case BUTTON_EVENT_IN_BOTTOM_R:
-       case BUTTON_EVENT_IN_BOTTOM_L:
-               if (event == t->button.curr)
                        tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM,
                                            event);
-               else
-                       tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
-                                           event);
                break;
        case BUTTON_EVENT_IN_TOP_R:
        case BUTTON_EVENT_IN_TOP_M:
        case BUTTON_EVENT_IN_TOP_L:
        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:
-               break;
        case BUTTON_EVENT_TIMEOUT:
-               tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
                break;
        }
 }
@@ -465,12 +393,6 @@ tp_button_handle_event(struct tp_dispatch *tp,
        case BUTTON_STATE_BOTTOM:
                tp_button_bottom_handle_event(tp, t, event);
                break;
-       case BUTTON_STATE_BOTTOM_NEW:
-               tp_button_bottom_new_handle_event(tp, t, event);
-               break;
-       case BUTTON_STATE_BOTTOM_TO_AREA:
-               tp_button_bottom_to_area_handle_event(tp, t, event);
-               break;
        case BUTTON_STATE_TOP:
                tp_button_top_handle_event(tp, t, event);
                break;
@@ -562,6 +484,67 @@ tp_process_button(struct tp_dispatch *tp,
        return 0;
 }
 
+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;
+       }
+}
+
+void
+tp_init_softbuttons(struct tp_dispatch *tp,
+                   struct evdev_device *device,
+                   double topbutton_size_mult)
+{
+       int width, height;
+       const struct input_absinfo *absinfo_x, *absinfo_y;
+       int xoffset, yoffset;
+       int yres;
+
+       absinfo_x = device->abs.absinfo_x;
+       absinfo_y = device->abs.absinfo_y;
+
+       xoffset = absinfo_x->minimum,
+       yoffset = absinfo_y->minimum;
+       yres = absinfo_y->resolution;
+       width = abs(absinfo_x->maximum - absinfo_x->minimum);
+       height = abs(absinfo_y->maximum - absinfo_y->minimum);
+
+       /* button height: 10mm or 15% of the touchpad height,
+          whichever is smaller */
+       if (yres > 1 && (height * 0.15/yres) > 10) {
+               tp->buttons.bottom_area.top_edge =
+               absinfo_y->maximum - 10 * yres;
+       } else {
+               tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
+       }
+
+       tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
+
+       if (tp->buttons.has_topbuttons) {
+               /* 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;
+               double topsize_pct = .15 * topbutton_size_mult;
+
+               if (yres > 1) {
+                       tp->buttons.top_area.bottom_edge =
+                       yoffset + topsize_mm * yres;
+               } else {
+                       tp->buttons.top_area.bottom_edge = height * topsize_pct + yoffset;
+               }
+               tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
+               tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
+       } else {
+               tp->buttons.top_area.bottom_edge = INT_MIN;
+       }
+}
+
 int
 tp_init_buttons(struct tp_dispatch *tp,
                struct evdev_device *device)
@@ -581,11 +564,13 @@ tp_init_buttons(struct tp_dispatch *tp,
            libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
                if (tp->buttons.is_clickpad)
                        log_bug_kernel(libinput,
-                                      "clickpad advertising right button\n");
+                                      "%s: clickpad advertising right button\n",
+                                      device->sysname);
        } else {
                if (!tp->buttons.is_clickpad)
                        log_bug_kernel(libinput,
-                                      "non clickpad without right button?\n");
+                                      "%s: non clickpad without right button?\n",
+                                      device->sysname);
        }
 
        absinfo_x = device->abs.absinfo_x;
@@ -597,22 +582,11 @@ tp_init_buttons(struct tp_dispatch *tp,
 
        tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
 
-       if (libevdev_get_id_vendor(device->evdev) == 0x5ac) /* Apple */
+       if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
                tp->buttons.use_clickfinger = true;
 
        if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
-               int xoffset = absinfo_x->minimum,
-                   yoffset = absinfo_y->minimum;
-               tp->buttons.bottom_area.top_edge = height * .8 + yoffset;
-               tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
-
-               if (tp->buttons.has_topbuttons) {
-                       tp->buttons.top_area.bottom_edge = height * .08 + yoffset;
-                       tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
-                       tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
-               } else {
-                       tp->buttons.top_area.bottom_edge = INT_MIN;
-               }
+               tp_init_softbuttons(tp, device, 1.0);
        } else {
                tp->buttons.bottom_area.top_edge = INT_MAX;
                tp->buttons.top_area.bottom_edge = INT_MIN;
@@ -665,11 +639,12 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
                state = LIBINPUT_BUTTON_STATE_RELEASED;
        }
 
-       if (button)
-               pointer_notify_button(&tp->device->base,
-                                     time,
-                                     button,
-                                     state);
+       if (button) {
+               evdev_pointer_notify_button(tp->device,
+                                           time,
+                                           button,
+                                           state);
+       }
        return 1;
 }
 
@@ -691,10 +666,10 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
                        else
                                state = LIBINPUT_BUTTON_STATE_RELEASED;
 
-                       pointer_notify_button(&tp->device->base,
-                                             time,
-                                             button,
-                                             state);
+                       evdev_pointer_notify_button(tp->device,
+                                                   time,
+                                                   button,
+                                                   state);
                }
 
                button++;
@@ -705,16 +680,46 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
        return 0;
 }
 
+static void
+tp_notify_softbutton(struct tp_dispatch *tp,
+                    uint64_t time,
+                    uint32_t button,
+                    uint32_t is_topbutton,
+                    enum libinput_button_state state)
+{
+       /* 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;
+
+               event.time.tv_sec = time/1000;
+               event.time.tv_usec = (time % 1000) * 1000;
+               event.type = EV_KEY;
+               event.code = button;
+               event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0;
+               dispatch->interface->process(dispatch, tp->buttons.trackpoint,
+                                            &event, time);
+               return;
+       }
+
+       /* Ignore button events not for the trackpoint while suspended */
+       if (tp->device->suspended)
+               return;
+
+       evdev_pointer_notify_button(tp->device, time, button, state);
+}
+
 static int
 tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
 {
-       uint32_t current, old, button;
+       uint32_t current, old, button, is_top;
        enum libinput_button_state state;
        enum { AREA = 0x01, LEFT = 0x02, MIDDLE = 0x04, RIGHT = 0x08 };
 
        current = tp->buttons.state;
        old = tp->buttons.old_state;
        button = 0;
+       is_top = 0;
 
        if (!tp->buttons.click_pending && current == old)
                return 0;
@@ -727,15 +732,18 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
                        case BUTTON_EVENT_IN_AREA:
                                button |= AREA;
                                break;
-                       case BUTTON_EVENT_IN_BOTTOM_L:
                        case BUTTON_EVENT_IN_TOP_L:
+                               is_top = 1;
+                       case BUTTON_EVENT_IN_BOTTOM_L:
                                button |= LEFT;
                                break;
                        case BUTTON_EVENT_IN_TOP_M:
+                               is_top = 1;
                                button |= MIDDLE;
                                break;
-                       case BUTTON_EVENT_IN_BOTTOM_R:
                        case BUTTON_EVENT_IN_TOP_R:
+                               is_top = 1;
+                       case BUTTON_EVENT_IN_BOTTOM_R:
                                button |= RIGHT;
                                break;
                        default:
@@ -757,20 +765,21 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
                        button = BTN_LEFT;
 
                tp->buttons.active = button;
+               tp->buttons.active_is_topbutton = is_top;
                state = LIBINPUT_BUTTON_STATE_PRESSED;
        } else {
                button = tp->buttons.active;
+               is_top = tp->buttons.active_is_topbutton;
                tp->buttons.active = 0;
+               tp->buttons.active_is_topbutton = 0;
                state = LIBINPUT_BUTTON_STATE_RELEASED;
        }
 
        tp->buttons.click_pending = false;
 
        if (button)
-               pointer_notify_button(&tp->device->base,
-                                     time,
-                                     button,
-                                     state);
+               tp_notify_softbutton(tp, time, button, is_top, state);
+
        return 1;
 }
 
@@ -792,3 +801,9 @@ tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
 {
        return t->button.state == BUTTON_STATE_AREA;
 }
+
+bool
+tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t)
+{
+       return is_inside_top_button_area(tp, t) || is_inside_bottom_button_area(tp, t);
+}