[PATCH libinput v2 2/5] Add a "switch" interface for parts of the SW_* range

James Ye jye836 at gmail.com
Tue Jan 10 01:24:22 UTC 2017


This will allow switch devices known to libinput to be exposed. Currently,
these are SW_LID and SW_TABLET_MODE.

libinput also handles switch events internally, e.g. a laptop touchpad will
be disabled autmoatically when the lid is closed. This is transparent to
the caller, although the caller will also receive the event. See
https://bugs.freedesktop.org/show_bug.cgi?id=86223
This features is intended to be the main driver for the interface.

Co-Authored-By: Peter Hutterer <peter.hutterer at who-t.net>
Signed-off-by: James Ye <jye836 at gmail.com>
---
Changes since v1:
 - minor doxygen fixes
 - missing @defgroup event_switch
 - missing @ingroup event

 doc/Makefile.am        |   1 +
 doc/switches.dox       |  16 +++++++
 src/libinput-private.h |   5 ++
 src/libinput.c         | 103 +++++++++++++++++++++++++++++++++++++++++
 src/libinput.h         | 121 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/libinput.sym       |   9 ++++
 test/litest.c          |   3 ++
 tools/event-debug.c    |  34 ++++++++++++++
 8 files changed, 292 insertions(+)
 create mode 100644 doc/switches.dox

diff --git a/doc/Makefile.am b/doc/Makefile.am
index 698a316..a92d791 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -22,6 +22,7 @@ header_files = \
 	$(srcdir)/reporting-bugs.dox \
 	$(srcdir)/scrolling.dox \
 	$(srcdir)/seats.dox \
+	$(srcdir)/switches.dox \
 	$(srcdir)/t440-support.dox \
 	$(srcdir)/tablet-support.dox \
 	$(srcdir)/tapping.dox \
diff --git a/doc/switches.dox b/doc/switches.dox
new file mode 100644
index 0000000..4bb2675
--- /dev/null
+++ b/doc/switches.dox
@@ -0,0 +1,16 @@
+/**
+ at page switches Switches
+
+libinput supports a couple of switches. Unlike button events that come in
+press and release pairs, switches are usually toggled once and left at the
+setting for an extended period of time.
+
+Only some switches are handled by libinput, see @ref libinput_switch for a
+list of supported switches. Switch events are exposed to the caller, but
+libinput may handle some switch events internally and enable or disable
+specific features based on a switch state.
+
+The order of switch events is guaranteed to be correct, i.e., a switch will
+never send consecutive switch on, or switch off, events.
+
+*/
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 0c75b3a..7ad02ef 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -618,6 +618,11 @@ tablet_pad_notify_strip(struct libinput_device *device,
 			double value,
 			enum libinput_tablet_pad_strip_axis_source source,
 			struct libinput_tablet_pad_mode_group *group);
+void
+switch_notify_toggle(struct libinput_device *device,
+		     uint64_t time,
+		     enum libinput_switch sw,
+		     enum libinput_switch_state state);
 
 static inline uint64_t
 libinput_now(struct libinput *libinput)
diff --git a/src/libinput.c b/src/libinput.c
index 1e97ad1..98bbec7 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -159,6 +159,13 @@ struct libinput_event_tablet_pad {
 	} strip;
 };
 
+struct libinput_event_switch {
+	struct libinput_event base;
+	uint64_t time;
+	enum libinput_switch sw;
+	enum libinput_switch_state state;
+};
+
 LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
 static void
 libinput_default_log_func(struct libinput *libinput,
@@ -365,6 +372,17 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
 	return (struct libinput_event_device_notify *) event;
 }
 
+LIBINPUT_EXPORT struct libinput_event_switch *
+libinput_event_get_switch_event(struct libinput_event *event)
+{
+	require_event_type(libinput_event_get_context(event),
+			   event->type,
+			   NULL,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return (struct libinput_event_switch *) event;
+}
+
 LIBINPUT_EXPORT uint32_t
 libinput_event_keyboard_get_time(struct libinput_event_keyboard *event)
 {
@@ -1508,6 +1526,61 @@ libinput_tablet_tool_unref(struct libinput_tablet_tool *tool)
 	return NULL;
 }
 
+LIBINPUT_EXPORT struct libinput_event *
+libinput_event_switch_get_base_event(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   NULL,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return &event->base;
+}
+
+LIBINPUT_EXPORT enum libinput_switch
+libinput_event_switch_get_switch(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return event->sw;
+}
+
+LIBINPUT_EXPORT enum libinput_switch_state
+libinput_event_switch_get_switch_state(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return event->state;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_switch_get_time(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return us2ms(event->time);
+}
+
+LIBINPUT_EXPORT uint64_t
+libinput_event_switch_get_time_usec(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return event->time;
+}
+
 struct libinput_source *
 libinput_add_fd(struct libinput *libinput,
 		int fd,
@@ -2024,6 +2097,9 @@ device_has_cap(struct libinput_device *device,
 	case LIBINPUT_DEVICE_CAP_TABLET_PAD:
 		capability = "CAP_TABLET_PAD";
 		break;
+	case LIBINPUT_DEVICE_CAP_SWITCH:
+		capability = "CAP_SWITCH";
+		break;
 	}
 
 	log_bug_libinput(device->seat->libinput,
@@ -2619,6 +2695,7 @@ event_type_to_str(enum libinput_event_type type)
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END);
+	CASE_RETURN_STRING(LIBINPUT_EVENT_SWITCH_TOGGLE);
 	case LIBINPUT_EVENT_NONE:
 		abort();
 	}
@@ -2626,6 +2703,32 @@ event_type_to_str(enum libinput_event_type type)
 	return NULL;
 }
 
+void
+switch_notify_toggle(struct libinput_device *device,
+		     uint64_t time,
+		     enum libinput_switch sw,
+		     enum libinput_switch_state state)
+{
+	struct libinput_event_switch *switch_event;
+
+	if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_SWITCH))
+		return;
+
+	switch_event = zalloc(sizeof *switch_event);
+	if (!switch_event)
+		return;
+
+	*switch_event = (struct libinput_event_switch) {
+		.time = time,
+		.sw = sw,
+		.state = state,
+	};
+
+	post_device_event(device, time,
+			  LIBINPUT_EVENT_SWITCH_TOGGLE,
+			  &switch_event->base);
+}
+
 static void
 libinput_post_event(struct libinput *libinput,
 		    struct libinput_event *event)
diff --git a/src/libinput.h b/src/libinput.h
index 18a96bd..77cb056 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -187,6 +187,7 @@ enum libinput_device_capability {
 	LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
 	LIBINPUT_DEVICE_CAP_TABLET_PAD = 4,
 	LIBINPUT_DEVICE_CAP_GESTURE = 5,
+	LIBINPUT_DEVICE_CAP_SWITCH = 6,
 };
 
 /**
@@ -592,6 +593,47 @@ libinput_tablet_pad_mode_group_get_user_data(
 			struct libinput_tablet_pad_mode_group *group);
 
 /**
+ * @ingroup device
+ *
+ * The state of a switch.
+ */
+enum libinput_switch_state {
+	LIBINPUT_SWITCH_STATE_OFF = 0,
+	LIBINPUT_SWITCH_STATE_ON = 1,
+};
+
+/**
+ * @ingroup device
+ *
+ * The type of a switch.
+ */
+enum libinput_switch {
+	/**
+	 * The laptop lid was closed when the switch state is @ref
+	 * LIBINPUT_SWITCH_STATE_ON, or was opened when it is @ref
+	 * LIBINPUT_SWITCH_STATE_OFF.
+	 */
+	LIBINPUT_SWITCH_LID = 1,
+	/**
+	 * The device was switched to or from tablet mode, usually by
+	 * rotating the screen and fixating it in place over the keyboard so
+	 * that the device now looks like a tablet.
+	 * Tablet mode is on when the switch state is @ref
+	 * LIBINPUT_SWITCH_STATE_ON, or off when it is @ref
+	 * LIBINPUT_SWITCH_STATE_OFF.
+	 */
+	LIBINPUT_SWITCH_TABLET_MODE = 2,
+};
+
+/**
+ * @ingroup event_switch
+ * @struct libinput_event_switch
+ *
+ * A switch event representing a changed state in a switch.
+ */
+struct libinput_event_switch;
+
+/**
  * @ingroup base
  *
  * Event type for events returned by libinput_get_event().
@@ -746,6 +788,8 @@ enum libinput_event_type {
 	LIBINPUT_EVENT_GESTURE_PINCH_BEGIN,
 	LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
 	LIBINPUT_EVENT_GESTURE_PINCH_END,
+
+	LIBINPUT_EVENT_SWITCH_TOGGLE = 900,
 };
 
 /**
@@ -885,6 +929,19 @@ libinput_event_get_tablet_pad_event(struct libinput_event *event);
 /**
  * @ingroup event
  *
+ * Return the switch event that is this input event. If the event type does
+ * not match the switch event types, this function returns NULL.
+ *
+ * The inverse of this function is libinput_event_switch_get_base_event().
+ *
+ * @return A switch event, or NULL for other events
+ */
+struct libinput_event_switch *
+libinput_event_get_switch_event(struct libinput_event *event);
+
+/**
+ * @ingroup event
+ *
  * Return the device event that is this input event. If the event type does
  * not match the device event types, this function returns NULL.
  *
@@ -2684,6 +2741,70 @@ uint64_t
 libinput_event_tablet_pad_get_time_usec(struct libinput_event_tablet_pad *event);
 
 /**
+ * @defgroup event_switch Switch events
+ *
+ * Events that come from switch devices.
+ */
+
+/**
+ * @ingroup event_switch
+ *
+ * Return the switch that triggered this event.
+ * For pointer events that are not of type @ref
+ * LIBINPUT_EVENT_SWITCH_TOGGLE, this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_SWITCH_TOGGLE.
+ *
+ * @param event The libinput switch event
+ * @return The switch triggering this event
+ */
+enum libinput_switch
+libinput_event_switch_get_switch(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * Return the switch state that triggered this event.
+ * For switch events that are not of type @ref
+ * LIBINPUT_EVENT_SWITCH_TOGGLE, this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_SWITCH_TOGGLE.
+ *
+ * @param event The libinput switch event
+ * @return The switch state triggering this event
+ */
+enum libinput_switch_state
+libinput_event_switch_get_switch_state(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @return The generic libinput_event of this event
+ */
+struct libinput_event *
+libinput_event_switch_get_base_event(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @param event The libinput switch event
+ * @return The event time for this event
+ */
+uint32_t
+libinput_event_switch_get_time(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @param event The libinput switch event
+ * @return The event time for this event in microseconds
+ */
+uint64_t
+libinput_event_switch_get_time_usec(struct libinput_event_switch *event);
+
+/**
  * @defgroup base Initialization and manipulation of libinput contexts
  */
 
diff --git a/src/libinput.sym b/src/libinput.sym
index 97bb57f..f440521 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -280,3 +280,12 @@ LIBINPUT_1.5 {
 	libinput_device_config_tap_get_default_button_map;
 	libinput_device_config_tap_set_button_map;
 } LIBINPUT_1.4;
+
+LIBINPUT_SWITCH {
+	libinput_event_get_switch_event;
+	libinput_event_switch_get_base_event;
+	libinput_event_switch_get_switch_state;
+	libinput_event_switch_get_switch;
+	libinput_event_switch_get_time;
+	libinput_event_switch_get_time_usec;
+} LIBINPUT_1.5;
diff --git a/test/litest.c b/test/litest.c
index 0574c0a..98ea0ec 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -2179,6 +2179,9 @@ litest_event_type_str(enum libinput_event_type type)
 	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
 		str = "TABLET PAD STRIP";
 		break;
+	case LIBINPUT_EVENT_SWITCH_TOGGLE:
+		str = "SWITCH TOGGLE";
+		break;
 	}
 	return str;
 }
diff --git a/tools/event-debug.c b/tools/event-debug.c
index d7d2018..179dc12 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -133,6 +133,9 @@ print_event_header(struct libinput_event *ev)
 	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
 		type = "TABLET_PAD_STRIP";
 		break;
+	case LIBINPUT_EVENT_SWITCH_TOGGLE:
+		type = "SWITCH_TOGGLE";
+		break;
 	}
 
 	prefix = (last_device != dev) ? '-' : ' ';
@@ -194,6 +197,9 @@ print_device_notify(struct libinput_event *ev)
 	if (libinput_device_has_capability(dev,
 					   LIBINPUT_DEVICE_CAP_TABLET_PAD))
 		printf("P");
+	if (libinput_device_has_capability(dev,
+					   LIBINPUT_DEVICE_CAP_SWITCH))
+		printf("S");
 
 	if (libinput_device_get_size(dev, &w, &h) == 0)
 		printf("  size %.0fx%.0fmm", w, h);
@@ -703,6 +709,31 @@ print_tablet_pad_strip_event(struct libinput_event *ev)
 	       mode);
 }
 
+static void
+print_switch_event(struct libinput_event *ev)
+{
+	struct libinput_event_switch *sw = libinput_event_get_switch_event(ev);
+	enum libinput_switch_state state;
+	const char *which;
+
+	print_event_time(libinput_event_switch_get_time(sw));
+
+	switch (libinput_event_switch_get_switch(sw)) {
+	case LIBINPUT_SWITCH_LID:
+		which = "lid";
+		break;
+	case LIBINPUT_SWITCH_TABLET_MODE:
+		which = "tablet-mode";
+		break;
+	default:
+		abort();
+	}
+
+	state = libinput_event_switch_get_switch_state(sw);
+
+	printf("switch %s state %d\n", which, state);
+}
+
 static int
 handle_and_print_events(struct libinput *li)
 {
@@ -791,6 +822,9 @@ handle_and_print_events(struct libinput *li)
 		case LIBINPUT_EVENT_TABLET_PAD_STRIP:
 			print_tablet_pad_strip_event(ev);
 			break;
+		case LIBINPUT_EVENT_SWITCH_TOGGLE:
+			print_switch_event(ev);
+			break;
 		}
 
 		libinput_event_destroy(ev);
-- 
2.9.3



More information about the wayland-devel mailing list