X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fevdev-mt-touchpad-buttons.c;h=21417ab9fd2e27fb2df68d3cbde53a4618f5c638;hb=a721292c254bfc4074ea3ee1f328260feda7c936;hp=65fa21beb84446abb5dcfeb91abb154079be228e;hpb=89165da6d6b90d466edf3283b710c0931bdcc8dd;p=platform%2Fupstream%2Flibinput.git diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 65fa21b..21417ab 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -22,12 +22,10 @@ #include #include -#include #include #include #include -#include -#include +#include "linux/input.h" #include "evdev-mt-touchpad.h" @@ -54,8 +52,10 @@ 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); + CASE_RETURN_STRING(BUTTON_STATE_IGNORE); } return NULL; } @@ -65,6 +65,9 @@ button_event_to_str(enum button_event event) { switch(event) { CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_R); CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_L); + CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_R); + CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_M); + CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_L); CASE_RETURN_STRING(BUTTON_EVENT_IN_AREA); CASE_RETURN_STRING(BUTTON_EVENT_UP); CASE_RETURN_STRING(BUTTON_EVENT_PRESS); @@ -75,54 +78,65 @@ button_event_to_str(enum button_event event) { } static inline bool -is_inside_button_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_bottom_button_area(struct tp_dispatch *tp, struct tp_touch *t) { - return t->y >= tp->buttons.area.top_edge; + return t->y >= tp->buttons.bottom_area.top_edge; } static inline bool -is_inside_right_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_bottom_right_area(struct tp_dispatch *tp, struct tp_touch *t) { - return is_inside_button_area(tp, t) && - t->x > tp->buttons.area.rightbutton_left_edge; + return is_inside_bottom_button_area(tp, t) && + t->x > tp->buttons.bottom_area.rightbutton_left_edge; } static inline bool -is_inside_left_area(struct tp_dispatch *tp, struct tp_touch *t) +is_inside_bottom_left_area(struct tp_dispatch *tp, struct tp_touch *t) { - return is_inside_button_area(tp, t) && - !is_inside_right_area(tp, t); + return is_inside_bottom_button_area(tp, t) && + !is_inside_bottom_right_area(tp, t); } -static void -tp_button_set_timer(struct tp_dispatch *tp, uint64_t timeout) +static inline bool +is_inside_top_button_area(struct tp_dispatch *tp, struct tp_touch *t) { - struct itimerspec its; - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - its.it_value.tv_sec = timeout / 1000; - its.it_value.tv_nsec = (timeout % 1000) * 1000 * 1000; - timerfd_settime(tp->buttons.timer_fd, TFD_TIMER_ABSTIME, &its, NULL); + return t->y <= tp->buttons.top_area.bottom_edge; } -static void -tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t) +static inline bool +is_inside_top_right_area(struct tp_dispatch *tp, struct tp_touch *t) +{ + return is_inside_top_button_area(tp, t) && + t->x > tp->buttons.top_area.rightbutton_left_edge; +} + +static inline bool +is_inside_top_left_area(struct tp_dispatch *tp, struct tp_touch *t) +{ + return is_inside_top_button_area(tp, t) && + t->x < tp->buttons.top_area.leftbutton_right_edge; +} + +static inline bool +is_inside_top_middle_area(struct tp_dispatch *tp, struct tp_touch *t) { - t->button.timeout = t->millis + DEFAULT_BUTTON_ENTER_TIMEOUT; - tp_button_set_timer(tp, t->button.timeout); + return is_inside_top_button_area(tp, t) && + t->x >= tp->buttons.top_area.leftbutton_right_edge && + t->x <= tp->buttons.top_area.rightbutton_left_edge; } static void -tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t) +tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t) { - t->button.timeout = t->millis + DEFAULT_BUTTON_LEAVE_TIMEOUT; - tp_button_set_timer(tp, t->button.timeout); + libinput_timer_set(&t->button.timer, + t->millis + DEFAULT_BUTTON_ENTER_TIMEOUT); } static void -tp_button_clear_timer(struct tp_dispatch *tp, struct tp_touch *t) +tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t) { - t->button.timeout = 0; + libinput_timer_set(&t->button.timer, + t->millis + DEFAULT_BUTTON_LEAVE_TIMEOUT); } /* @@ -133,7 +147,7 @@ static void tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t, enum button_state new_state, enum button_event event) { - tp_button_clear_timer(tp, t); + libinput_timer_cancel(&t->button.timer); t->button.state = new_state; switch (t->button.state) { @@ -145,14 +159,20 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t, tp_set_pointer(tp, t); break; case BUTTON_STATE_BOTTOM: + t->button.curr = event; + break; + case BUTTON_STATE_TOP: break; - case BUTTON_STATE_BOTTOM_NEW: + case BUTTON_STATE_TOP_NEW: t->button.curr = event; tp_button_set_enter_timer(tp, t); break; - case BUTTON_STATE_BOTTOM_TO_AREA: + case BUTTON_STATE_TOP_TO_IGNORE: tp_button_set_leave_timer(tp, t); break; + case BUTTON_STATE_IGNORE: + t->button.curr = 0; + break; } } @@ -164,7 +184,12 @@ 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: + case BUTTON_EVENT_IN_TOP_L: + tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event); break; case BUTTON_EVENT_IN_AREA: tp_button_set_state(tp, t, BUTTON_STATE_AREA, event); @@ -187,6 +212,9 @@ tp_button_area_handle_event(struct tp_dispatch *tp, switch (event) { case BUTTON_EVENT_IN_BOTTOM_R: 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: @@ -201,18 +229,51 @@ 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) +{ + 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); + 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: + case BUTTON_EVENT_TIMEOUT: + break; + } +} + +static void +tp_button_top_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: + 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) - tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, + tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event); break; case BUTTON_EVENT_IN_AREA: - tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_TO_AREA, event); + 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); @@ -225,15 +286,20 @@ tp_button_bottom_handle_event(struct tp_dispatch *tp, } static void -tp_button_bottom_new_handle_event(struct tp_dispatch *tp, +tp_button_top_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: + 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) - tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, + tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event); break; case BUTTON_EVENT_IN_AREA: @@ -243,31 +309,34 @@ tp_button_bottom_new_handle_event(struct tp_dispatch *tp, 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); + 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_BOTTOM, event); + tp_button_set_state(tp, t, BUTTON_STATE_TOP, event); break; } } static void -tp_button_bottom_to_area_handle_event(struct tp_dispatch *tp, +tp_button_top_to_ignore_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: + case BUTTON_EVENT_IN_TOP_R: + case BUTTON_EVENT_IN_TOP_M: + case BUTTON_EVENT_IN_TOP_L: if (event == t->button.curr) - tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, + tp_button_set_state(tp, t, BUTTON_STATE_TOP, event); else - tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, + tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event); break; + case BUTTON_EVENT_IN_BOTTOM_R: + case BUTTON_EVENT_IN_BOTTOM_L: case BUTTON_EVENT_IN_AREA: break; case BUTTON_EVENT_UP: @@ -277,7 +346,30 @@ tp_button_bottom_to_area_handle_event(struct tp_dispatch *tp, case BUTTON_EVENT_RELEASE: break; case BUTTON_EVENT_TIMEOUT: - tp_button_set_state(tp, t, BUTTON_STATE_AREA, event); + tp_button_set_state(tp, t, BUTTON_STATE_IGNORE, event); + break; + } +} + +static void +tp_button_ignore_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: + 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: + case BUTTON_EVENT_RELEASE: + case BUTTON_EVENT_TIMEOUT: break; } } @@ -288,6 +380,7 @@ tp_button_handle_event(struct tp_dispatch *tp, enum button_event event, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; enum button_state current = t->button.state; switch(t->button.state) { @@ -300,16 +393,23 @@ 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); + 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_BOTTOM_TO_AREA: - tp_button_bottom_to_area_handle_event(tp, t, event); + 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; } if (current != t->button.state) - log_debug("button state: from %s, event %s to %s\n", + log_debug(libinput, + "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)); @@ -327,10 +427,16 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time) if (t->state == TOUCH_END) { tp_button_handle_event(tp, t, BUTTON_EVENT_UP, time); } else if (t->dirty) { - if (is_inside_right_area(tp, t)) + if (is_inside_bottom_right_area(tp, t)) tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_R, time); - else if (is_inside_left_area(tp, t)) + else if (is_inside_bottom_left_area(tp, t)) tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_L, time); + else if (is_inside_top_right_area(tp, t)) + tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_R, time); + else if (is_inside_top_middle_area(tp, t)) + tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_M, time); + else if (is_inside_top_left_area(tp, t)) + tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_L, time); else tp_button_handle_event(tp, t, BUTTON_EVENT_IN_AREA, time); } @@ -344,16 +450,11 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time) } static void -tp_button_handle_timeout(struct tp_dispatch *tp, uint64_t now) +tp_button_handle_timeout(uint64_t now, void *data) { - struct tp_touch *t; + struct tp_touch *t = data; - tp_for_each_touch(tp, t) { - if (t->button.timeout != 0 && t->button.timeout <= now) { - tp_button_clear_timer(tp, t); - tp_button_handle_event(tp, t, BUTTON_EVENT_TIMEOUT, now); - } - } + tp_button_handle_event(t->tp, t, BUTTON_EVENT_TIMEOUT, now); } int @@ -361,12 +462,14 @@ tp_process_button(struct tp_dispatch *tp, const struct input_event *e, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; uint32_t mask = 1 << (e->code - BTN_LEFT); /* Ignore other buttons on clickpads */ if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { - log_bug("received %s button event on a clickpad (kernel bug?)\n", - libevdev_event_code_get_name(EV_KEY, e->code)); + log_bug_kernel(libinput, + "received %s button event on a clickpad\n", + libevdev_event_code_get_name(EV_KEY, e->code)); return 0; } @@ -381,73 +484,119 @@ tp_process_button(struct tp_dispatch *tp, return 0; } -static void -tp_button_timeout_handler(void *data) +void +tp_release_all_buttons(struct tp_dispatch *tp, + uint64_t time) { - struct tp_dispatch *tp = data; - uint64_t expires; - int len; - struct timespec ts; - uint64_t now; - - len = read(tp->buttons.timer_fd, &expires, sizeof expires); - if (len != sizeof expires) - /* This will only happen if the application made the fd - * non-blocking, but this function should only be called - * upon the timeout, so lets continue anyway. */ - log_error("timerfd read error: %s\n", strerror(errno)); + if (tp->buttons.state) { + tp->buttons.state = 0; + tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE; + } +} - clock_gettime(CLOCK_MONOTONIC, &ts); - now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; +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_button_handle_timeout(tp, now); + 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) { + struct libinput *libinput = tp->device->base.seat->libinput; + struct tp_touch *t; int width, height; double diagonal; + const struct input_absinfo *absinfo_x, *absinfo_y; tp->buttons.is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD); + tp->buttons.has_topbuttons = libevdev_has_property(device->evdev, + INPUT_PROP_TOPBUTTONPAD); if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { if (tp->buttons.is_clickpad) - log_bug("clickpad advertising right button (kernel bug?)\n"); + log_bug_kernel(libinput, + "%s: clickpad advertising right button\n", + device->sysname); } else { if (!tp->buttons.is_clickpad) - log_bug("non clickpad without right button (kernel bug)?\n"); + log_bug_kernel(libinput, + "%s: non clickpad without right button?\n", + device->sysname); } - width = abs(device->abs.max_x - device->abs.min_x); - height = abs(device->abs.max_y - device->abs.min_y); + absinfo_x = device->abs.absinfo_x; + absinfo_y = device->abs.absinfo_y; + + width = abs(absinfo_x->maximum - absinfo_x->minimum); + height = abs(absinfo_y->maximum - absinfo_y->minimum); diagonal = sqrt(width*width + height*height); 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) { - tp->buttons.area.top_edge = height * .8 + device->abs.min_y; - tp->buttons.area.rightbutton_left_edge = width/2 + device->abs.min_x; - tp->buttons.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - - if (tp->buttons.timer_fd == -1) - return -1; - - tp->buttons.source = - libinput_add_fd(tp->device->base.seat->libinput, - tp->buttons.timer_fd, - tp_button_timeout_handler, - tp); - if (tp->buttons.source == NULL) - return -1; + tp_init_softbuttons(tp, device, 1.0); } else { - tp->buttons.area.top_edge = INT_MAX; + tp->buttons.bottom_area.top_edge = INT_MAX; + tp->buttons.top_area.bottom_edge = INT_MIN; + } + + tp_for_each_touch(tp, t) { + t->button.state = BUTTON_STATE_NONE; + libinput_timer_init(&t->button.timer, + tp->device->base.seat->libinput, + tp_button_handle_timeout, t); } return 0; @@ -456,22 +605,17 @@ tp_init_buttons(struct tp_dispatch *tp, void tp_destroy_buttons(struct tp_dispatch *tp) { - if (tp->buttons.source) { - libinput_remove_source(tp->device->base.seat->libinput, - tp->buttons.source); - tp->buttons.source = NULL; - } - if (tp->buttons.timer_fd > -1) { - close(tp->buttons.timer_fd); - tp->buttons.timer_fd = -1; - } + struct tp_touch *t; + + tp_for_each_touch(tp, t) + libinput_timer_cancel(&t->button.timer); } static int tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time) { uint32_t current, old, button; - enum libinput_pointer_button_state state; + enum libinput_button_state state; current = tp->buttons.state; old = tp->buttons.old_state; @@ -488,18 +632,19 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time) return 0; } tp->buttons.active = button; - state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + state = LIBINPUT_BUTTON_STATE_PRESSED; } else { button = tp->buttons.active; tp->buttons.active = 0; - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + 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; } @@ -513,18 +658,18 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time) button = BTN_LEFT; while (current || old) { - enum libinput_pointer_button_state state; + enum libinput_button_state state; if ((current & 0x1) ^ (old & 0x1)) { if (!!(current & 0x1)) - state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + state = LIBINPUT_BUTTON_STATE_PRESSED; else - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + state = LIBINPUT_BUTTON_STATE_RELEASED; - pointer_notify_button(&tp->device->base, - time, - button, - state); + evdev_pointer_notify_button(tp->device, + time, + button, + state); } button++; @@ -535,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; - enum libinput_pointer_button_state state; - enum { AREA = 0x01, LEFT = 0x02, RIGHT = 0x04 }; + 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; @@ -557,9 +732,17 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) case BUTTON_EVENT_IN_AREA: button |= AREA; break; + 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_TOP_R: + is_top = 1; case BUTTON_EVENT_IN_BOTTOM_R: button |= RIGHT; break; @@ -568,40 +751,35 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) } } - switch (button) { - case 0: + if (button == 0) { /* No touches, wait for a touch before processing */ tp->buttons.click_pending = true; return 0; - case RIGHT: - case RIGHT | AREA: - /* Some touches in right, no touches in left */ - button = BTN_RIGHT; - break; - case LEFT | RIGHT: - case LEFT | RIGHT | AREA: - /* Some touches in left and some in right */ + } + + if ((button & MIDDLE) || ((button & LEFT) && (button & RIGHT))) button = BTN_MIDDLE; - break; - default: + else if (button & RIGHT) + button = BTN_RIGHT; + else button = BTN_LEFT; - } tp->buttons.active = button; - state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + 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; - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + 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; } @@ -623,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); +}