On a TOPBUTTONPAD, we can't disable the touchpad altogether - the trackstick relies on the touchpad's top software buttons. On those devices, stretch the top buttons down to INT_MAX on suspend and then route any button click events through the trackstick device.
On resume, restore the original configuration. Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- Obviously the trackpoint detection is a bit rough here, see Hans' patch for how to do this based on the kernel property (once that is merged). src/evdev-mt-touchpad-buttons.c | 17 +++++++++++- src/evdev-mt-touchpad.c | 24 ++++++++++++++++- src/evdev-mt-touchpad.h | 6 +++++ src/evdev.c | 11 ++++++++ src/evdev.h | 1 + test/device.c | 58 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 02d3205..bf2fbc2 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -540,6 +540,16 @@ tp_init_softbuttons(struct tp_dispatch *tp, } } +void +tp_expand_softbuttons(struct tp_dispatch *tp) +{ + /* simply stretch the top software button area down */ + if (tp->buttons.has_topbuttons) { + tp->buttons.top_area.bottom_edge = INT_MAX; + tp->buttons.bottom_area.top_edge = INT_MAX; + } +} + int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device) @@ -737,7 +747,12 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) tp->buttons.click_pending = false; if (button) { - evdev_pointer_notify_button(tp->device, + struct evdev_device *device = tp->device; + + if (tp->sendevents.disabled && tp->buttons.trackpoint) + device = tp->buttons.trackpoint; + + evdev_pointer_notify_button(device, time, button, state); diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index adb3d02..2d3a677 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -667,13 +667,25 @@ tp_suspend(struct tp_dispatch *tp, struct evdev_device *device) tp_handle_state(tp, now); - evdev_device_suspend(device); + tp->sendevents.disabled = true; + + /* On the T440s with top softwarebuttons, don't disable the device, + merely pull the top buttons down to cover the whole touchpad. + */ + if (tp->buttons.has_topbuttons) + tp_expand_softbuttons(tp); + else + evdev_device_suspend(device); } static void tp_resume(struct tp_dispatch *tp, struct evdev_device *device) { evdev_device_resume(device); + + tp->sendevents.disabled = false; + if (tp->buttons.has_topbuttons) + tp_init_softbuttons(tp, device); } static void @@ -682,6 +694,11 @@ tp_device_added(struct evdev_device *device, { struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch; + if (tp->buttons.has_topbuttons && + tp->buttons.trackpoint == NULL && + added_device->tags & EVDEV_TAG_TRACKPOINT) + tp->buttons.trackpoint = added_device; + if (tp->sendevents.current_mode != LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) return; @@ -697,6 +714,9 @@ 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) + tp->buttons.trackpoint = NULL; + if (tp->sendevents.current_mode != LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) return; @@ -924,6 +944,8 @@ tp_init(struct tp_dispatch *tp, if (tp_init_palmdetect(tp, device) != 0) return -1; + tp->sendevents.disabled = false; + device->seat_caps |= EVDEV_DEVICE_POINTER; return 0; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index b67b063..efcfc95 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -198,6 +198,8 @@ struct tp_dispatch { int32_t rightbutton_left_edge; int32_t leftbutton_right_edge; } top_area; + + struct evdev_device *trackpoint; } buttons; /* physical buttons */ struct { @@ -221,6 +223,7 @@ struct tp_dispatch { struct { struct libinput_device_config_send_events config; enum libinput_config_send_events_mode current_mode; + bool disabled; } sendevents; }; @@ -249,6 +252,9 @@ void tp_init_softbuttons(struct tp_dispatch *tp, struct evdev_device *device); void +tp_expand_softbuttons(struct tp_dispatch *tp); + +void tp_destroy_buttons(struct tp_dispatch *tp); int diff --git a/src/evdev.c b/src/evdev.c index 0a8f2ba..0233ec6 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -560,6 +560,16 @@ evdev_tag_external_mouse(struct evdev_device *device, } static void +evdev_tag_trackpoint(struct evdev_device *device, + struct udev_device *udev_device) +{ + const char *name = libevdev_get_name(device->evdev); + + if (strstr(name, "TrackPoint") != NULL) + device->tags |= EVDEV_TAG_TRACKPOINT; +} + +static void fallback_process(struct evdev_dispatch *dispatch, struct evdev_device *device, struct input_event *event, @@ -597,6 +607,7 @@ fallback_tag_device(struct evdev_device *device, struct udev_device *udev_device) { evdev_tag_external_mouse(device, udev_device); + evdev_tag_trackpoint(device, udev_device); } static int diff --git a/src/evdev.h b/src/evdev.h index f5345fa..5101de4 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -51,6 +51,7 @@ enum evdev_device_seat_capability { enum evdev_device_tags { EVDEV_TAG_EXTERNAL_MOUSE = (1 << 0), EVDEV_TAG_INTERNAL_TOUCHPAD = (1 << 1), + EVDEV_TAG_TRACKPOINT = (1 << 2), }; struct mt_slot { diff --git a/test/device.c b/test/device.c index 3f7ec4c..33aae04 100644 --- a/test/device.c +++ b/test/device.c @@ -509,6 +509,62 @@ START_TEST(device_disable_release_softbutton) } END_TEST +START_TEST(device_disable_topsoftbutton) +{ + struct litest_device *dev = litest_current_device(); + struct litest_device *trackpoint; + struct libinput *li = dev->libinput; + struct libinput_device *device; + enum libinput_config_status status; + + struct libinput_event *event; + struct libinput_event_pointer *ptrevent; + + device = dev->libinput_device; + + trackpoint = litest_add_device(li, LITEST_TRACKPOINT); + + status = libinput_device_config_send_events_set_mode(device, + LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + litest_drain_events(li); + + litest_touch_down(dev, 0, 90, 10); + litest_button_click(dev, BTN_LEFT, true); + litest_button_click(dev, BTN_LEFT, false); + litest_touch_up(dev, 0); + + litest_wait_for_event(li); + event = libinput_get_event(li); + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_BUTTON); + ck_assert_int_eq(libinput_event_get_device(event), + trackpoint->libinput_device); + ptrevent = libinput_event_get_pointer_event(event); + ck_assert_int_eq(libinput_event_pointer_get_button(ptrevent), + BTN_RIGHT); + ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrevent), + LIBINPUT_BUTTON_STATE_PRESSED); + libinput_event_destroy(event); + + event = libinput_get_event(li); + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_BUTTON); + ck_assert_int_eq(libinput_event_get_device(event), + trackpoint->libinput_device); + ptrevent = libinput_event_get_pointer_event(event); + ck_assert_int_eq(libinput_event_pointer_get_button(ptrevent), + BTN_RIGHT); + ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrevent), + LIBINPUT_BUTTON_STATE_RELEASED); + libinput_event_destroy(event); + + litest_assert_empty_queue(li); + + litest_delete_device(trackpoint); +} +END_TEST + int main (int argc, char **argv) { litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD); @@ -527,5 +583,7 @@ int main (int argc, char **argv) litest_add("device:sendevents", device_disable_release_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); litest_add("device:sendevents", device_disable_release_softbutton, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); + litest_add("device:sendevents", device_disable_topsoftbutton, LITEST_TOPBUTTONPAD, LITEST_ANY); + return litest_run(argc, argv); } -- 1.9.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel