[PATCH libinput v3] tablet: Add libinput_tool_has_axis() and tests

Stephen Chandler Paul thatslyude at gmail.com
Thu Aug 7 19:02:22 PDT 2014


Because the axes that tool reports can change depending on the tool in use, we
want to be able to provide functionality to determine which axes each tool can
support.

Signed-off-by: Stephen Chandler Paul <thatslyude at gmail.com>
---

===== Changes =====
* Fixed the line width in test/tablet.c
* Removed libinput_tool_axis_flag and used the already existing axis enumerators
  instead

 src/evdev-tablet.c     | 47 +++++++++++++++++++++++++++++++
 src/evdev-tablet.h     |  1 +
 src/libinput-private.h |  1 +
 src/libinput.c         |  7 +++++
 src/libinput.h         | 13 +++++++++
 test/tablet.c          | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 145 insertions(+)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 15f0663..a63b734 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -302,6 +302,44 @@ tablet_get_tool(struct tablet_dispatch *tablet,
 			.refcount = 1,
 		};
 
+		/* Determine the axis capabilities of the tool. Here's a break
+		 * down of the heuristics used here:
+		 * - The Wacom art pen supports all of the extra axes, along
+		 *   with rotation
+		 * - All of normal pens and the airbrush support all of the
+		 *   extra axes if the tablet can report them
+		 * - All of the mouse like devices don't really report any of
+		 *   the extra axes except for rotation.
+		 * (as of writing this comment, rotation isn't supported, so you
+		 * won't see the mouse or art pen here)
+		 */
+		switch (type) {
+		case LIBINPUT_TOOL_PEN:
+		case LIBINPUT_TOOL_ERASER:
+		case LIBINPUT_TOOL_PENCIL:
+		case LIBINPUT_TOOL_BRUSH:
+		case LIBINPUT_TOOL_AIRBRUSH:
+			if (bit_is_set(tablet->axis_caps,
+				       LIBINPUT_TABLET_AXIS_PRESSURE))
+				set_bit(tool->axis_caps,
+					LIBINPUT_TABLET_AXIS_PRESSURE);
+			if (bit_is_set(tablet->axis_caps,
+				       LIBINPUT_TABLET_AXIS_DISTANCE))
+				set_bit(tool->axis_caps,
+					LIBINPUT_TABLET_AXIS_DISTANCE);
+			if (bit_is_set(tablet->axis_caps,
+				       LIBINPUT_TABLET_AXIS_TILT_X))
+				set_bit(tool->axis_caps,
+					LIBINPUT_TABLET_AXIS_TILT_X);
+			if (bit_is_set(tablet->axis_caps,
+				       LIBINPUT_TABLET_AXIS_TILT_Y))
+				set_bit(tool->axis_caps,
+					LIBINPUT_TABLET_AXIS_TILT_Y);
+			break;
+		default:
+			break;
+		}
+
 		list_insert(tool_list, &tool->link);
 	}
 
@@ -510,12 +548,21 @@ static int
 tablet_init(struct tablet_dispatch *tablet,
 	    struct evdev_device *device)
 {
+	enum libinput_tablet_axis axis;
+
 	tablet->base.interface = &tablet_interface;
 	tablet->device = device;
 	tablet->status = TABLET_NONE;
 	tablet->current_tool_type = LIBINPUT_TOOL_NONE;
 	list_init(&tablet->tool_list);
 
+	for (axis = 0; axis < LIBINPUT_TABLET_AXIS_CNT; axis++) {
+		if (libevdev_has_event_code(device->evdev,
+					    EV_ABS,
+					    axis_to_evcode(axis)))
+			set_bit(tablet->axis_caps, axis);
+	}
+
 	tablet_mark_all_axes_changed(tablet, device);
 
 	return 0;
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index adc3aa4..cb37577 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -48,6 +48,7 @@ struct tablet_dispatch {
 	unsigned char status;
 	unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
 	double axes[LIBINPUT_TABLET_AXIS_CNT];
+	unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
 
 	/* Only used for tablets that don't report serial numbers */
 	struct list tool_list;
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 8187564..369bb8f 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -108,6 +108,7 @@ struct libinput_tool {
 	struct list link;
 	uint32_t serial;
 	enum libinput_tool_type type;
+	unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
 	int refcount;
 	void *user_data;
 };
diff --git a/src/libinput.c b/src/libinput.c
index 68187d8..e52527b 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -599,6 +599,13 @@ libinput_tool_get_serial(struct libinput_tool *tool)
 	return tool->serial;
 }
 
+LIBINPUT_EXPORT int
+libinput_tool_has_axis(struct libinput_tool *tool,
+		       enum libinput_tablet_axis axis)
+{
+	return bit_is_set(tool->axis_caps, axis);
+}
+
 LIBINPUT_EXPORT void
 libinput_tool_set_user_data(struct libinput_tool *tool,
 			    void *user_data)
diff --git a/src/libinput.h b/src/libinput.h
index 1d4952b..ed56c0b 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -1010,6 +1010,19 @@ libinput_tool_ref(struct libinput_tool *tool);
 /**
  * @ingroup event_tablet
  *
+ * Return whether or not a tablet tool supports the specified axis
+ *
+ * @param tool The tool to check the axis capabilities of
+ * @param axis The axis to check for support
+ * @return Whether or not the axis is supported
+ */
+int
+libinput_tool_has_axis(struct libinput_tool *tool,
+		       enum libinput_tablet_axis axis);
+
+/**
+ * @ingroup event_tablet
+ *
  * Decrement the ref count of tool by one. When the ref count of tool reaches 0,
  * the memory allocated for tool will be freed.
  *
diff --git a/test/tablet.c b/test/tablet.c
index 2de0989..e903d32 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -766,10 +766,86 @@ START_TEST(tools_without_serials)
 }
 END_TEST
 
+START_TEST(tool_capabilities)
+{
+	struct libinput *li = litest_create_context();
+	struct litest_device *intuos;
+	struct litest_device *bamboo;
+	struct libinput_event *event;
+
+	/* The axis capabilities of a tool can differ depending on the type of
+	 * tablet the tool is being used with */
+	bamboo = litest_create_device_with_overrides(LITEST_WACOM_BAMBOO,
+						     NULL,
+						     NULL,
+						     NULL,
+						     NULL);
+	intuos = litest_create_device_with_overrides(LITEST_WACOM_INTUOS,
+						     NULL,
+						     NULL,
+						     NULL,
+						     NULL);
+
+	litest_event(bamboo, EV_KEY, BTN_TOOL_PEN, 1);
+	litest_event(bamboo, EV_SYN, SYN_REPORT, 0);
+
+	libinput_dispatch(li);
+	while ((event = libinput_get_event(li))) {
+		if (libinput_event_get_type(event) ==
+		    LIBINPUT_EVENT_TABLET_PROXIMITY_IN) {
+			struct libinput_event_tablet *t =
+				libinput_event_get_tablet_event(event);
+			struct libinput_tool *tool =
+				libinput_event_tablet_get_tool(t);
+
+			ck_assert(libinput_tool_has_axis(tool,
+							 LIBINPUT_TABLET_AXIS_PRESSURE));
+			ck_assert(libinput_tool_has_axis(tool,
+							 LIBINPUT_TABLET_AXIS_DISTANCE));
+			ck_assert(!libinput_tool_has_axis(tool,
+							  LIBINPUT_TABLET_AXIS_TILT_X));
+			ck_assert(!libinput_tool_has_axis(tool,
+							  LIBINPUT_TABLET_AXIS_TILT_Y));
+		}
+
+		libinput_event_destroy(event);
+	}
+
+	litest_event(intuos, EV_KEY, BTN_TOOL_PEN, 1);
+	litest_event(intuos, EV_SYN, SYN_REPORT, 0);
+
+	while ((event = libinput_get_event(li))) {
+		if (libinput_event_get_type(event) ==
+		    LIBINPUT_EVENT_TABLET_PROXIMITY_IN) {
+			struct libinput_event_tablet *t =
+				libinput_event_get_tablet_event(event);
+			struct libinput_tool *tool =
+				libinput_event_tablet_get_tool(t);
+
+			ck_assert(libinput_tool_has_axis(tool,
+							 LIBINPUT_TABLET_AXIS_PRESSURE));
+			ck_assert(libinput_tool_has_axis(tool,
+							 LIBINPUT_TABLET_AXIS_DISTANCE));
+			ck_assert(libinput_tool_has_axis(tool,
+							 LIBINPUT_TABLET_AXIS_TILT_X));
+			ck_assert(libinput_tool_has_axis(tool,
+							 LIBINPUT_TABLET_AXIS_TILT_Y));
+		}
+
+		libinput_event_destroy(event);
+	}
+
+	litest_delete_device(bamboo);
+	litest_delete_device(intuos);
+	libinput_unref(li);
+}
+END_TEST
+
 int
 main(int argc, char **argv)
 {
 	litest_add("tablet:tool", tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
+	litest_add_no_device("tablet:tool", tool_capabilities);
 	litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
 	litest_add("tablet:tool_serial", serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
 	litest_add("tablet:tool_serial", invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
-- 
1.8.5.5



More information about the wayland-devel mailing list