X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fevdev-mt-touchpad-buttons.c;h=21417ab9fd2e27fb2df68d3cbde53a4618f5c638;hb=c481b47f1776549bbfde325fe68dceb0401b3f59;hp=a124e1263ae1b75b270f4fcaae49a99a42d00b86;hpb=f6c3731f8a28629498f84dc5a0c0d14b82297f7f;p=platform%2Fupstream%2Flibinput.git diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index a124e12..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, uint32_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) { - 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; +} + +static inline bool +is_inside_top_middle_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 && + 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; } } @@ -286,8 +378,9 @@ static void tp_button_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum button_event event, - uint32_t time) + uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; enum button_state current = t->button.state; switch(t->button.state) { @@ -300,23 +393,30 @@ 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)); } int -tp_button_handle_state(struct tp_dispatch *tp, uint32_t time) +tp_button_handle_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; @@ -327,10 +427,16 @@ tp_button_handle_state(struct tp_dispatch *tp, uint32_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); } @@ -343,30 +449,30 @@ tp_button_handle_state(struct tp_dispatch *tp, uint32_t time) return 0; } -static int -tp_button_handle_timeout(struct tp_dispatch *tp, uint32_t now) +static void +tp_button_handle_timeout(uint64_t now, void *data) { - struct tp_touch *t; - uint32_t min_timeout = INT_MAX; + 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); - } - if (t->button.timeout != 0) - min_timeout = min(t->button.timeout, min_timeout); - } - - return min_timeout == INT_MAX ? 0 : min_timeout; + tp_button_handle_event(t->tp, t, BUTTON_EVENT_TIMEOUT, now); } int tp_process_button(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time) + 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_kernel(libinput, + "received %s button event on a clickpad\n", + libevdev_event_code_get_name(EV_KEY, e->code)); + return 0; + } + if (e->value) { tp->buttons.state |= mask; tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS; @@ -378,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; - uint32_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 * 1000 + 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; @@ -453,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, uint32_t time) +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; @@ -485,23 +632,24 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_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; } static int -tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) +tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time) { uint32_t current, old, button; @@ -510,18 +658,18 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint32_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++; @@ -532,66 +680,112 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint32_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, uint32_t time) +tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) { - uint32_t current, old, button; - enum libinput_pointer_button_state state; + 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 (current == old) - return 0; - - if (tp->nfingers_down == 0 || tp->nfingers_down > 2) + if (!tp->buttons.click_pending && current == old) return 0; if (current) { struct tp_touch *t; - button = 0; tp_for_each_touch(tp, t) { - if (t->button.curr == BUTTON_EVENT_IN_BOTTOM_R) - button |= 0x2; - else if (t->button.curr == BUTTON_EVENT_IN_BOTTOM_L) - button |= 0x1; + switch (t->button.curr) { + 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; + default: + break; + } } - switch (button) { - case 0: /* only in area */ - case 1: /* only left area */ - button = BTN_LEFT; - break; - case 2: /* only right area */ - button = BTN_RIGHT; - break; - case 3: /* left + right area */ - button = BTN_MIDDLE; - break; + if (button == 0) { + /* No touches, wait for a touch before processing */ + tp->buttons.click_pending = true; + return 0; } + if ((button & MIDDLE) || ((button & LEFT) && (button & RIGHT))) + button = BTN_MIDDLE; + 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 { - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; 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; } - pointer_notify_button(&tp->device->base, - time, - button, - state); + tp->buttons.click_pending = false; + + if (button) + tp_notify_softbutton(tp, time, button, is_top, state); + return 1; } int -tp_post_button_events(struct tp_dispatch *tp, uint32_t time) +tp_post_button_events(struct tp_dispatch *tp, uint64_t time) { - if ((tp->queued & - (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) - return 0; - if (tp->buttons.is_clickpad) { if (tp->buttons.use_clickfinger) return tp_post_clickfinger_buttons(tp, time); @@ -607,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); +}