diff --git a/doc/touchpad-softbutton-state-machine.svg b/doc/touchpad-softbutton-state-machine.svg index 1d569bf6..ffa17a29 100644 --- a/doc/touchpad-softbutton-state-machine.svg +++ b/doc/touchpad-softbutton-state-machine.svg @@ -1,5 +1,5 @@ - + @@ -68,13 +68,13 @@ - + - Check state of - all touches + Check state of + all touches - - + + @@ -82,88 +82,89 @@ tp_post_softbutton_buttons() - + - !buttons.click_pend - && current == old + !buttons.click_pend + && current == old - - + + - - yes + + yes - - + + - - no + + no - - - + + + - current = buttons.state & 0x01 - old = buttons.old_state & 0x01 - button = 0 + current = buttons.state & 0x01 + old = buttons.old_state & 0x01 + button = 0 + is_top = 0 - - - + + + - All touches are in state none + All touches are in state none - - + + - - no + + no - - + + - - yes + + yes - + - buttons.click_pend = 1 + buttons.click_pend = 1 - - - + + + - (Some touches are in middle) || - ((Some touches are in right) && - (Some touches are in left)) + (Some touches are in middle) || + ((Some touches are in right) && + (Some touches are in left)) - - + + - - yes + + yes - + - button = BTN_MIDDLE + button = BTN_MIDDLE - - - + + + - current + current - - + + - - no + + no - - + + - - yes + + yes @@ -172,13 +173,13 @@ - + yes - + - + no @@ -192,25 +193,28 @@ - + no - + - buttons.active = button - state = BUTTON_PRESSED + buttons.active = button + buttons.active_is_top = is_top + state = BUTTON_PRESSED - + - - - - - + + + + + - button = buttons.active - buttons.active = 0 - state = BUTTON_RELEASED + button = buttons.active + is_top = buttons.active_is_top + buttons.active = 0 + buttons.active_is_top = 0 + state = BUTTON_RELEASED @@ -218,7 +222,7 @@ - + @@ -227,26 +231,26 @@ - + no - + yes - pointer_notify_button( - button, state) + tp_notify_softbutton( + button, is_top, state) - - + + finger in @@ -261,8 +265,8 @@ curr = button start enter timeout - - + + @@ -356,5 +360,27 @@ + + + touches in top? + + + + + + yes + + + + is_top = 1 + + + + + + + + no + diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 02d3205a..b6aee24d 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -675,16 +675,42 @@ 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; + } + + 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; @@ -697,15 +723,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: @@ -727,21 +756,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) { - evdev_pointer_notify_button(tp->device, - time, - button, - state); - } + if (button) + tp_notify_softbutton(tp, time, button, is_top, state); + return 1; } diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 4639231b..bed62569 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -643,8 +643,11 @@ tp_device_added(struct evdev_device *device, struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch; if (tp->buttons.trackpoint == NULL && - (added_device->tags & EVDEV_TAG_TRACKPOINT)) + (added_device->tags & EVDEV_TAG_TRACKPOINT)) { + /* Don't send any pending releases to the new trackpoint */ + tp->buttons.active_is_topbutton = false; tp->buttons.trackpoint = added_device; + } if (tp->sendevents.current_mode != LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) @@ -661,8 +664,14 @@ tp_device_removed(struct evdev_device *device, struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch; struct libinput_device *dev; - if (removed_device == tp->buttons.trackpoint) + if (removed_device == tp->buttons.trackpoint) { + /* Clear any pending releases for the trackpoint */ + if (tp->buttons.active && tp->buttons.active_is_topbutton) { + tp->buttons.active = 0; + tp->buttons.active_is_topbutton = false; + } tp->buttons.trackpoint = NULL; + } if (tp->sendevents.current_mode != LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) @@ -703,8 +712,8 @@ static struct evdev_dispatch_interface tp_interface = { tp_destroy, tp_device_added, tp_device_removed, - NULL, /* device_suspended */ - NULL, /* device_resumed */ + tp_device_removed, /* device_suspended, treat as remove */ + tp_device_added, /* device_resumed, treat as add */ tp_tag_device, }; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 4a16db9d..3d3932b5 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -183,6 +183,7 @@ struct tp_dispatch { uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ unsigned int active; /* currently active button, for release event */ + bool active_is_topbutton; /* is active a top button? */ /* Only used for clickpads. The software button areas are * always 2 horizontal stripes across the touchpad.