[PATCH libinput 7/8] tablet: split out tip handling into a separate event

Peter Hutterer peter.hutterer at who-t.net
Wed Nov 11 13:13:01 PST 2015


The tablet tip works like a button in the kernel but is otherwise not really
a button. Split it into an explicit tip up/down event instead.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/libinput-private.h |  7 +++++++
 src/libinput.c         | 42 ++++++++++++++++++++++++++++++++++++++++++
 src/libinput.h         | 41 +++++++++++++++++++++++++++++++++++++++++
 src/libinput.sym       |  1 +
 test/litest.c          |  8 ++++++++
 test/tablet.c          |  4 +++-
 tools/event-debug.c    | 18 ++++++++++++++++++
 tools/event-gui.c      | 34 ++++++++++++++++++++++++++++++++++
 8 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/src/libinput-private.h b/src/libinput-private.h
index 3d61222..0e7ddff 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -477,6 +477,13 @@ tablet_notify_proximity(struct libinput_device *device,
 			double *axes);
 
 void
+tablet_notify_tip(struct libinput_device *device,
+		  uint64_t time,
+		  struct libinput_tool *tool,
+		  enum libinput_tool_tip_state tip_state,
+		  double *axes);
+
+void
 tablet_notify_button(struct libinput_device *device,
 		     uint64_t time,
 		     struct libinput_tool *tool,
diff --git a/src/libinput.c b/src/libinput.c
index 79e4863..c47f9fc 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -137,6 +137,7 @@ struct libinput_event_tablet {
 	unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
 	struct libinput_tool *tool;
 	enum libinput_tool_proximity_state proximity_state;
+	enum libinput_tool_tip_state tip_state;
 };
 
 static void
@@ -313,6 +314,7 @@ libinput_event_get_tablet_event(struct libinput_event *event)
 			   NULL,
 			   LIBINPUT_EVENT_TABLET_AXIS,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_BUTTON);
 
 	return (struct libinput_event_tablet *) event;
@@ -918,6 +920,7 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event,
 			   event->base.type,
 			   0,
 			   LIBINPUT_EVENT_TABLET_AXIS,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY);
 
 	return (NCHARS(axis) <= sizeof(event->changed_axes)) ?
@@ -935,6 +938,7 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event,
 			   event->base.type,
 			   0,
 			   LIBINPUT_EVENT_TABLET_AXIS,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY);
 
 	switch(axis) {
@@ -968,6 +972,7 @@ libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event,
 			   event->base.type,
 			   0,
 			   LIBINPUT_EVENT_TABLET_AXIS,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY);
 
 	switch(axis) {
@@ -999,6 +1004,7 @@ libinput_event_tablet_get_axis_delta_discrete(
 			   event->base.type,
 			   0,
 			   LIBINPUT_EVENT_TABLET_AXIS,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY);
 
 	switch(axis) {
@@ -1028,6 +1034,7 @@ libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event,
 			   event->base.type,
 			   0,
 			   LIBINPUT_EVENT_TABLET_AXIS,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY);
 
 	return evdev_device_transform_x(device,
@@ -1046,6 +1053,7 @@ libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event,
 			   event->base.type,
 			   0,
 			   LIBINPUT_EVENT_TABLET_AXIS,
+			   LIBINPUT_EVENT_TABLET_TIP,
 			   LIBINPUT_EVENT_TABLET_PROXIMITY);
 
 	return evdev_device_transform_y(device,
@@ -1065,6 +1073,12 @@ libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event)
 	return event->proximity_state;
 }
 
+LIBINPUT_EXPORT enum libinput_tool_tip_state
+libinput_event_tablet_get_tip_state(struct libinput_event_tablet *event)
+{
+	return event->tip_state;
+}
+
 LIBINPUT_EXPORT uint32_t
 libinput_event_tablet_get_time(struct libinput_event_tablet *event)
 {
@@ -1970,6 +1984,34 @@ tablet_notify_proximity(struct libinput_device *device,
 }
 
 void
+tablet_notify_tip(struct libinput_device *device,
+		  uint64_t time,
+		  struct libinput_tool *tool,
+		  enum libinput_tool_tip_state tip_state,
+		  double *axes)
+{
+	struct libinput_event_tablet *tip_event;
+
+	tip_event = zalloc(sizeof *tip_event);
+	if (!tip_event)
+		return;
+
+	*tip_event = (struct libinput_event_tablet) {
+		.time = time,
+		.tool = tool,
+		.tip_state = tip_state,
+	};
+	memcpy(tip_event->axes,
+	       axes,
+	       sizeof(tip_event->axes));
+
+	post_device_event(device,
+			  time,
+			  LIBINPUT_EVENT_TABLET_TIP,
+			  &tip_event->base);
+}
+
+void
 tablet_notify_button(struct libinput_device *device,
 		     uint64_t time,
 		     struct libinput_tool *tool,
diff --git a/src/libinput.h b/src/libinput.h
index c5f9da7..dc7e7d8 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -217,6 +217,20 @@ enum libinput_tool_proximity_state {
 };
 
 /**
+ * @ingroup device
+ *
+ * The tip contact state for a tool on a device. The device must have
+ * the @ref LIBINPUT_DEVICE_CAP_TABLET capability.
+ *
+ * The tip contact state of a tool is a binary state signalling whether the tool is
+ * touching the surface of the tablet device.
+ */
+enum libinput_tool_tip_state {
+	LIBINPUT_TOOL_TIP_UP = 0,
+	LIBINPUT_TOOL_TIP_DOWN = 1,
+};
+
+/**
  * @ingroup base
  *
  * Event type for events returned by libinput_get_event().
@@ -301,6 +315,19 @@ enum libinput_event_type {
 	 * proximity out event.
 	 */
 	LIBINPUT_EVENT_TABLET_PROXIMITY,
+	/**
+	 * Signals that a tool has come in contact with the surface of a
+	 * device with the @ref LIBINPUT_DEVICE_CAP_TABLET capability.
+	 *
+	 * On devices without distance proximity detection, the @ref
+	 * LIBINPUT_EVENT_TABLET_TIP is sent immediately after @ref
+	 * LIBINPUT_EVENT_TABLET_PROXIMITY for the tip down event, and
+	 * immediately before for the tip up event.
+	 *
+	 * If a button and/or axis state change occurs at the same time as a
+	 * tip state change, the order of events is device-dependent.
+	 */
+	LIBINPUT_EVENT_TABLET_TIP,
 	LIBINPUT_EVENT_TABLET_BUTTON,
 
 	LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
@@ -1502,6 +1529,20 @@ libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event);
 /**
  * @ingroup event_tablet
  *
+ * Returns the new tip state of a tool from a tip event.
+ * Used to check whether or not a tool came in contact with the tablet
+ * surface or left contact with the tablet surface during an
+ * event of type @ref LIBINPUT_EVENT_TABLET_TIP.
+ *
+ * @param event The libinput tablet event
+ * @return The new tip state of the tool from the event.
+ */
+enum libinput_tool_tip_state
+libinput_event_tablet_get_tip_state(struct libinput_event_tablet *event);
+
+/**
+ * @ingroup event_tablet
+ *
  * Return the button that triggered this event.
  * For tablet events that are not of type @ref LIBINPUT_EVENT_TABLET_BUTTON, this
  * function returns 0.
diff --git a/src/libinput.sym b/src/libinput.sym
index 1c297c7..33d5b33 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -195,6 +195,7 @@ LIBINPUT_TABLET_SUPPORT {
 	libinput_event_tablet_get_proximity_state;
 	libinput_event_tablet_get_seat_button_count;
 	libinput_event_tablet_get_time;
+	libinput_event_tablet_get_tip_state;
 	libinput_event_tablet_get_tool;
 	libinput_event_tablet_get_x_transformed;
 	libinput_event_tablet_get_y_transformed;
diff --git a/test/litest.c b/test/litest.c
index ce2a6a7..4bbabb2 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1887,6 +1887,9 @@ litest_event_type_str(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY:
 		str = "TABLET PROX";
 		break;
+	case LIBINPUT_EVENT_TABLET_TIP:
+		str = "TABLET TIP";
+		break;
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		str = "TABLET BUTTON";
 		break;
@@ -1949,6 +1952,11 @@ litest_print_event(struct libinput_event *event)
 		fprintf(stderr, "proximity %d\n",
 			libinput_event_tablet_get_proximity_state(t));
 		break;
+	case LIBINPUT_EVENT_TABLET_TIP:
+		t = libinput_event_get_tablet_event(event);
+		fprintf(stderr, "tip %d\n",
+			libinput_event_tablet_get_tip_state(t));
+		break;
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		t = libinput_event_get_tablet_event(event);
 		fprintf(stderr, "button %d state %d\n",
diff --git a/test/tablet.c b/test/tablet.c
index 5dcb9d3..444290c 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -118,7 +118,7 @@ START_TEST(proximity_out_clear_buttons)
 	/* Test that proximity out events send button releases for any currently
 	 * pressed stylus buttons
 	 */
-	for (button = BTN_TOUCH; button <= BTN_STYLUS2; button++) {
+	for (button = BTN_TOUCH + 1; button <= BTN_STYLUS2; button++) {
 		bool button_released = false;
 		uint32_t event_button;
 		enum libinput_button_state state;
@@ -155,6 +155,8 @@ START_TEST(proximity_out_clear_buttons)
 			      libevdev_event_code_get_name(EV_KEY, button),
 			      event_button);
 	}
+
+	litest_assert_empty_queue(li);
 }
 END_TEST
 
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 05fb1a7..f0ae1dc 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -115,6 +115,9 @@ print_event_header(struct libinput_event *ev)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY:
 		type = "TABLET_PROXIMITY";
 		break;
+	case LIBINPUT_EVENT_TABLET_TIP:
+		type = "TABLET_TIP";
+		break;
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		type = "TABLET_BUTTON";
 		break;
@@ -279,6 +282,18 @@ print_pointer_button_event(struct libinput_event *ev)
 }
 
 static void
+print_tablet_tip_event(struct libinput_event *ev)
+{
+	struct libinput_event_tablet *p = libinput_event_get_tablet_event(ev);
+	enum libinput_tool_tip_state state;
+
+	print_event_time(libinput_event_tablet_get_time(p));
+
+	state = libinput_event_tablet_get_tip_state(p);
+	printf("%s\n", state == LIBINPUT_TOOL_TIP_DOWN ? "down" : "up");
+}
+
+static void
 print_tablet_button_event(struct libinput_event *ev)
 {
 	struct libinput_event_tablet *p = libinput_event_get_tablet_event(ev);
@@ -667,6 +682,9 @@ handle_and_print_events(struct libinput *li)
 		case LIBINPUT_EVENT_TABLET_PROXIMITY:
 			print_proximity_event(ev);
 			break;
+		case LIBINPUT_EVENT_TABLET_TIP:
+			print_tablet_tip_event(ev);
+			break;
 		case LIBINPUT_EVENT_TABLET_BUTTON:
 			print_tablet_button_event(ev);
 			break;
diff --git a/tools/event-gui.c b/tools/event-gui.c
index c07213f..a7d8dd9 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -88,6 +88,8 @@ struct window {
 	struct {
 		double x, y;
 		double x_in, y_in;
+		double x_down, y_down;
+		double x_up, y_up;
 		double pressure;
 		double distance;
 		double tilt_x, tilt_y;
@@ -234,6 +236,20 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data)
 		cairo_save(cr);
 	}
 
+	if (w->tool.x_down && w->tool.y_down) {
+		cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20);
+		cairo_stroke(cr);
+		cairo_restore(cr);
+		cairo_save(cr);
+	}
+
+	if (w->tool.x_up && w->tool.y_up) {
+		cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20);
+		cairo_stroke(cr);
+		cairo_restore(cr);
+		cairo_save(cr);
+	}
+
 	if (w->tool.pressure)
 		cairo_set_source_rgb(cr, .8, .8, .2);
 
@@ -584,6 +600,7 @@ static void
 handle_event_tablet(struct libinput_event *ev, struct window *w)
 {
 	struct libinput_event_tablet *t = libinput_event_get_tablet_event(ev);
+	double x, y;
 
 	switch (libinput_event_get_type(ev)) {
 	case LIBINPUT_EVENT_TABLET_PROXIMITY:
@@ -591,6 +608,10 @@ handle_event_tablet(struct libinput_event *ev, struct window *w)
 		    LIBINPUT_TOOL_PROXIMITY_OUT) {
 			w->tool.x_in = 0;
 			w->tool.y_in = 0;
+			w->tool.x_down = 0;
+			w->tool.y_down = 0;
+			w->tool.x_up = 0;
+			w->tool.y_up = 0;
 		} else {
 			w->tool.x_in = libinput_event_tablet_get_x_transformed(t,
 								       w->width);
@@ -612,6 +633,18 @@ handle_event_tablet(struct libinput_event *ev, struct window *w)
 		w->tool.tilt_y = libinput_event_tablet_get_axis_value(t,
 							LIBINPUT_TABLET_AXIS_TILT_Y);
 		break;
+	case LIBINPUT_EVENT_TABLET_TIP:
+		x = libinput_event_tablet_get_x_transformed(t, w->width);
+		y = libinput_event_tablet_get_y_transformed(t, w->height);
+		if (libinput_event_tablet_get_tip_state(t) ==
+		    LIBINPUT_TOOL_TIP_DOWN) {
+			w->tool.x_down = x;
+			w->tool.y_down = y;
+		} else {
+			w->tool.x_up = x;
+			w->tool.y_up = y;
+		}
+		break;
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		break;
 	default:
@@ -676,6 +709,7 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
 			break;
 		case LIBINPUT_EVENT_TABLET_AXIS:
 		case LIBINPUT_EVENT_TABLET_PROXIMITY:
+		case LIBINPUT_EVENT_TABLET_TIP:
 		case LIBINPUT_EVENT_TABLET_BUTTON:
 			handle_event_tablet(ev, w);
 			break;
-- 
2.4.3



More information about the wayland-devel mailing list