[PATCH libinput] Add support for SW_TABLET_MODE

Peter Hutterer peter.hutterer at who-t.net
Wed May 17 03:13:37 UTC 2017


https://bugs.freedesktop.org/show_bug.cgi?id=101008

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
This builds on top of the patch series here
https://lists.freedesktop.org/archives/wayland-devel/2017-April/033942.html
since rebased and available here:
https://github.com/whot/libinput/tree/wip/sw-tablet-mode

 src/evdev.c                                | 48 ++++++++++++---
 src/evdev.h                                |  1 +
 src/libinput.h                             | 16 +++++
 test/litest-device-thinkpad-extrabuttons.c |  1 +
 test/litest.c                              |  3 +
 test/test-switch.c                         | 95 +++++++++++++++---------------
 6 files changed, 108 insertions(+), 56 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 1b4ec934..8cc8a2cc 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -958,6 +958,20 @@ fallback_process_switch(struct fallback_dispatch *dispatch,
 				     LIBINPUT_SWITCH_RF_DISABLED,
 				     state);
 		break;
+	case SW_TABLET_MODE:
+		if (dispatch->sw.tablet_mode_state == e->value)
+			return;
+
+		dispatch->sw.tablet_mode_state = e->value;
+		if (e->value)
+			state = LIBINPUT_SWITCH_STATE_ON;
+		else
+			state = LIBINPUT_SWITCH_STATE_OFF;
+		switch_notify_toggle(&device->base,
+				     time,
+				     LIBINPUT_SWITCH_TABLET_MODE,
+				     state);
+		break;
 	}
 }
 
@@ -1288,14 +1302,21 @@ fallback_sync_initial_state(struct evdev_device *device,
 			    struct evdev_dispatch *evdev_dispatch)
 {
 	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
+	uint64_t time = libinput_now(evdev_libinput_context(device));
 
 	if (dispatch->sw.rfkill_all_state) {
-		uint64_t time = libinput_now(evdev_libinput_context(device));
 		switch_notify_toggle(&device->base,
 				     time,
 				     LIBINPUT_SWITCH_RF_DISABLED,
 				     LIBINPUT_SWITCH_STATE_ON);
 	}
+
+	if (dispatch->sw.tablet_mode_state) {
+		switch_notify_toggle(&device->base,
+				     time,
+				     LIBINPUT_SWITCH_TABLET_MODE,
+				     LIBINPUT_SWITCH_STATE_ON);
+	}
 }
 
 static void
@@ -1845,13 +1866,23 @@ static inline void
 fallback_dispatch_init_switch(struct fallback_dispatch *dispatch,
 			      struct evdev_device *device)
 {
-	if (!libevdev_has_event_code(device->evdev, EV_SW, SW_RFKILL_ALL))
-		return;
+	int val;
 
-	dispatch->sw.rfkill_all_state = libevdev_get_event_value(device->evdev,
-								 EV_SW,
-								 SW_RFKILL_ALL);
-	device->seat_caps |= EVDEV_DEVICE_SWITCH;
+	if (libevdev_has_event_code(device->evdev, EV_SW, SW_RFKILL_ALL)) {
+		val = libevdev_get_event_value(device->evdev,
+					       EV_SW,
+					       SW_RFKILL_ALL);
+		dispatch->sw.rfkill_all_state = val;
+		device->seat_caps |= EVDEV_DEVICE_SWITCH;
+	}
+
+	if (libevdev_has_event_code(device->evdev, EV_SW, SW_TABLET_MODE)) {
+		val = libevdev_get_event_value(device->evdev,
+					       EV_SW,
+					       SW_TABLET_MODE);
+		dispatch->sw.tablet_mode_state = val;
+		device->seat_caps |= EVDEV_DEVICE_SWITCH;
+	}
 }
 
 static struct evdev_dispatch *
@@ -3214,6 +3245,9 @@ evdev_device_has_switch(struct evdev_device *device,
 	case LIBINPUT_SWITCH_RF_DISABLED:
 		code = SW_RFKILL_ALL;
 		break;
+	case LIBINPUT_SWITCH_TABLET_MODE:
+		code = SW_TABLET_MODE;
+		break;
 	default:
 		return -1;
 	}
diff --git a/src/evdev.h b/src/evdev.h
index 02c14e65..0587740d 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -359,6 +359,7 @@ struct fallback_dispatch {
 
 	struct {
 		int rfkill_all_state;
+		int tablet_mode_state;
 	} sw;
 
 	/* Bitmask of pressed keys used to ignore initial release events from
diff --git a/src/libinput.h b/src/libinput.h
index 38abae8e..316f210a 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -639,6 +639,22 @@ enum libinput_switch {
 	 * c) toggle the state to match the switch state (if required)
 	 */
 	LIBINPUT_SWITCH_RF_DISABLED,
+
+	/**
+	 * This switch indicates whether the device is in normal laptop mode
+	 * or behaves like a tablet-like device where the primary
+	 * interaction is usually a touch screen. When in tablet mode, the
+	 * keyboard and touchpad are usually inaccessible.
+	 *
+	 * If the switch is in state @ref LIBINPUT_SWITCH_STATE_OFF, the
+	 * device is in laptop mode. If the switch is in state @ref
+	 * LIBINPUT_SWITCH_STATE_ON, the device is in tablet mode and the
+	 * keyboard or touchpad may not be  accessible.
+	 *
+	 * It is up to the caller to identify which devices are inaccessible
+	 * in tablet mode.
+	 */
+	LIBINPUT_SWITCH_TABLET_MODE,
 };
 
 /**
diff --git a/test/litest-device-thinkpad-extrabuttons.c b/test/litest-device-thinkpad-extrabuttons.c
index d5ff4303..84541493 100644
--- a/test/litest-device-thinkpad-extrabuttons.c
+++ b/test/litest-device-thinkpad-extrabuttons.c
@@ -71,6 +71,7 @@ static int events[] = {
 	EV_KEY, KEY_BRIGHTNESS_MIN,
 
 	EV_SW, SW_RFKILL_ALL,
+	EV_SW, SW_TABLET_MODE,
 
 	-1, -1,
 };
diff --git a/test/litest.c b/test/litest.c
index d0704bec..14eb2722 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -2178,6 +2178,9 @@ litest_switch_action(struct litest_device *dev,
 	case LIBINPUT_SWITCH_RF_DISABLED:
 		code = SW_RFKILL_ALL;
 		break;
+	case LIBINPUT_SWITCH_TABLET_MODE:
+		code = SW_TABLET_MODE;
+		break;
 	default:
 		litest_abort_msg("Invalid switch %d", sw);
 		break;
diff --git a/test/test-switch.c b/test/test-switch.c
index af184607..1fcf61d4 100644
--- a/test/test-switch.c
+++ b/test/test-switch.c
@@ -36,13 +36,6 @@ switch_has_lid(struct litest_device *dev)
 						 LIBINPUT_SWITCH_LID);
 }
 
-static inline bool
-switch_has_rfkill(struct litest_device *dev)
-{
-	return libinput_device_switch_has_switch(dev->libinput_device,
-						 LIBINPUT_SWITCH_RF_DISABLED);
-}
-
 START_TEST(switch_has_lid_switch)
 {
 	struct litest_device *dev = litest_current_device();
@@ -79,35 +72,47 @@ START_TEST(switch_has_rfkill_switch)
 }
 END_TEST
 
+START_TEST(switch_has_tablet_mode_switch)
+{
+	struct litest_device *dev = litest_current_device();
+
+	if (!libevdev_has_event_code(dev->evdev, EV_SW, SW_TABLET_MODE))
+		return;
+
+	ck_assert_int_eq(libinput_device_switch_has_switch(dev->libinput_device,
+							   LIBINPUT_SWITCH_TABLET_MODE),
+			 1);
+}
+END_TEST
+
 START_TEST(switch_toggle)
 {
 	struct litest_device *dev = litest_current_device();
 	struct libinput *li = dev->libinput;
 	struct libinput_event *event;
-	enum libinput_switch sw;
-
-	if (switch_has_lid(dev))
-		sw = LIBINPUT_SWITCH_LID;
-	else if (switch_has_rfkill(dev))
-		sw = LIBINPUT_SWITCH_RF_DISABLED;
-	else
-		litest_abort_msg("Missing switch for test");
+	enum libinput_switch sw = _i; /* ranged test */
 
 	litest_drain_events(li);
 
 	litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON);
 	libinput_dispatch(li);
 
-	event = libinput_get_event(li);
-	litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_ON);
-	libinput_event_destroy(event);
+	if (libinput_device_switch_has_switch(dev->libinput_device, sw)) {
+		event = libinput_get_event(li);
+		litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_ON);
+		libinput_event_destroy(event);
+	} else {
+		litest_assert_empty_queue(li);
+	}
 
 	litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_OFF);
 	libinput_dispatch(li);
 
-	event = libinput_get_event(li);
-	litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_OFF);
-	libinput_event_destroy(event);
+	if (libinput_device_switch_has_switch(dev->libinput_device, sw)) {
+		event = libinput_get_event(li);
+		litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_OFF);
+		libinput_event_destroy(event);
+	}
 
 	litest_assert_empty_queue(li);
 }
@@ -118,14 +123,10 @@ START_TEST(switch_toggle_double)
 	struct litest_device *dev = litest_current_device();
 	struct libinput *li = dev->libinput;
 	struct libinput_event *event;
-	enum libinput_switch sw;
+	enum libinput_switch sw = _i; /* ranged test */
 
-	if (switch_has_lid(dev))
-		sw = LIBINPUT_SWITCH_LID;
-	else if (switch_has_rfkill(dev))
-		sw = LIBINPUT_SWITCH_RF_DISABLED;
-	else
-		litest_abort_msg("Missing switch for test");
+	if (!libinput_device_switch_has_switch(dev->libinput_device, sw))
+		return;
 
 	litest_drain_events(li);
 
@@ -167,17 +168,13 @@ START_TEST(switch_down_on_init)
 	struct litest_device *dev = litest_current_device();
 	struct libinput *li;
 	struct libinput_event *event;
-	enum libinput_switch sw = LIBINPUT_SWITCH_LID;
+	enum libinput_switch sw = _i; /* ranged test */
 
-	if (switch_has_lid(dev)) {
-		sw = LIBINPUT_SWITCH_LID;
-		if (!lid_switch_is_reliable(dev))
-			return;
-	} else if (switch_has_rfkill(dev)) {
-		sw = LIBINPUT_SWITCH_RF_DISABLED;
-	} else {
-		litest_abort_msg("Missing switch for test");
-	}
+	if (!libinput_device_switch_has_switch(dev->libinput_device, sw))
+		return;
+
+	if (sw == LIBINPUT_SWITCH_LID && !lid_switch_is_reliable(dev))
+		return;
 
 	litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON);
 
@@ -217,15 +214,11 @@ START_TEST(switch_not_down_on_init)
 	struct libinput_event *event;
 	enum libinput_switch sw = LIBINPUT_SWITCH_LID;
 
-	if (switch_has_lid(dev)) {
-		sw = LIBINPUT_SWITCH_LID;
-		if (lid_switch_is_reliable(dev))
-			return;
-	} else if (switch_has_rfkill(dev)) {
+	if (!libinput_device_switch_has_switch(dev->libinput_device, sw))
+		return;
+
+	if (sw == LIBINPUT_SWITCH_LID && lid_switch_is_reliable(dev))
 		return;
-	} else {
-		litest_abort_msg("Missing switch for test");
-	}
 
 	litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON);
 
@@ -627,12 +620,16 @@ END_TEST
 void
 litest_setup_tests_lid(void)
 {
+	struct range switches = { LIBINPUT_SWITCH_LID,
+				  LIBINPUT_SWITCH_TABLET_MODE + 1};
+
 	litest_add("switch:has", switch_has_lid_switch, LITEST_SWITCH, LITEST_ANY);
 	litest_add("switch:has", switch_has_rfkill_switch, LITEST_SWITCH, LITEST_ANY);
+	litest_add("switch:has", switch_has_tablet_mode_switch, LITEST_SWITCH, LITEST_ANY);
 	litest_add("switch:has", switch_has_cap, LITEST_SWITCH, LITEST_ANY);
-	litest_add("switch:toggle", switch_toggle, LITEST_SWITCH, LITEST_ANY);
-	litest_add("switch:toggle", switch_toggle_double, LITEST_SWITCH, LITEST_ANY);
-	litest_add("switch:toggle", switch_down_on_init, LITEST_SWITCH, LITEST_ANY);
+	litest_add_ranged("switch:toggle", switch_toggle, LITEST_SWITCH, LITEST_ANY, &switches);
+	litest_add_ranged("switch:toggle", switch_toggle_double, LITEST_SWITCH, LITEST_ANY, &switches);
+	litest_add_ranged("switch:toggle", switch_down_on_init, LITEST_SWITCH, LITEST_ANY, &switches);
 	litest_add("switch:toggle", switch_not_down_on_init, LITEST_SWITCH, LITEST_ANY);
 	litest_add("lid:disable_touchpad", lid_disable_touchpad, LITEST_SWITCH, LITEST_ANY);
 	litest_add("lid:disable_touchpad", lid_disable_touchpad_during_touch, LITEST_SWITCH, LITEST_ANY);
-- 
2.12.2



More information about the wayland-devel mailing list