[PATCH libinput 5/5] touchpad: when disabling a TOPBUTTONPAD, leave the buttons enabled

Peter Hutterer peter.hutterer at who-t.net
Wed Sep 3 23:31:59 PDT 2014


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.hutterer at 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



More information about the wayland-devel mailing list