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

Reply via email to