From 8f20c07a1f0c465317f77d21304d7afaadb1b4a8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 16 Sep 2014 16:22:39 +0200 Subject: touchpad: Route top softbuttons through the trackstick if we've one The touchpad top softbuttons such as found on the Lenove T440 are intended for use with the trackstick. Route their events through the trackstick, so that they can be used for e.g. middle button scrolling with the trackstick. Note that sending top button events to a disabled trackpoint makes no sense (and will mess up internal state). Likely a user with a disabled trackpoint will still expect the top buttons to work, so rather than not sending events in that case, simply treat a suspendeded trackpoint as not being there, and send the events directly from the touchpad device. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- doc/touchpad-softbutton-state-machine.svg | 200 +++++++++++++++++------------- src/evdev-mt-touchpad-buttons.c | 47 +++++-- src/evdev-mt-touchpad.c | 17 ++- src/evdev-mt-touchpad.h | 1 + 4 files changed, 165 insertions(+), 100 deletions(-) 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. -- cgit v1.2.3