[PATCH v2 libinput 5/5] test: tablet pad tests

Peter Hutterer peter.hutterer at who-t.net
Mon Apr 11 04:15:31 UTC 2016


Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Adjusted for the new API in 2/5

 test/Makefile.am                       |   7 +
 test/litest-device-wacom-intuos3-pad.c | 117 +++++++++
 test/litest-device-wacom-intuos5-pad.c | 122 ++++++++++
 test/litest-int.h                      |  16 ++
 test/litest.c                          | 219 ++++++++++++++++-
 test/litest.h                          |  40 +++
 test/misc.c                            |  51 ++++
 test/pad.c                             | 431 +++++++++++++++++++++++++++++++++
 8 files changed, 1002 insertions(+), 1 deletion(-)
 create mode 100644 test/litest-device-wacom-intuos3-pad.c
 create mode 100644 test/litest-device-wacom-intuos5-pad.c
 create mode 100644 test/pad.c

diff --git a/test/Makefile.am b/test/Makefile.am
index d328c92..ba78b96 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -48,6 +48,8 @@ liblitest_la_SOURCES = \
 	litest-device-wacom-cintiq-tablet.c \
 	litest-device-wacom-cintiq-24hd.c \
 	litest-device-wacom-intuos-tablet.c \
+	litest-device-wacom-intuos3-pad.c \
+	litest-device-wacom-intuos5-pad.c \
 	litest-device-wacom-isdv4-tablet.c \
 	litest-device-wacom-touch.c \
 	litest-device-wacom-intuos-finger.c \
@@ -71,6 +73,7 @@ run_tests = \
 	test-touchpad \
 	test-touchpad-tap \
 	test-touchpad-buttons \
+	test-pad \
 	test-tablet \
 	test-device \
 	test-gestures \
@@ -120,6 +123,10 @@ test_tablet_SOURCES = tablet.c
 test_tablet_LDADD = $(TEST_LIBS)
 test_tablet_LDFLAGS = -static
 
+test_pad_SOURCES = pad.c
+test_pad_LDADD = $(TEST_LIBS)
+test_pad_LDFLAGS = -static
+
 test_touchpad_SOURCES = touchpad.c
 test_touchpad_LDADD = $(TEST_LIBS)
 test_touchpad_LDFLAGS = -no-install
diff --git a/test/litest-device-wacom-intuos3-pad.c b/test/litest-device-wacom-intuos3-pad.c
new file mode 100644
index 0000000..0622ddc
--- /dev/null
+++ b/test/litest-device-wacom-intuos3-pad.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void
+litest_wacom_intuos3_pad_setup(void)
+{
+	struct litest_device *d = litest_create_device(LITEST_WACOM_INTUOS3_PAD);
+	litest_set_current_device(d);
+}
+
+static struct input_event down[] = {
+	{ .type = -1, .code = -1 },
+};
+
+static struct input_event move[] = {
+	{ .type = -1, .code = -1 },
+};
+
+static struct input_event strip_start[] = {
+	{ .type = EV_ABS, .code = ABS_RX, .value = LITEST_AUTO_ASSIGN },
+	{ .type = EV_ABS, .code = ABS_MISC, .value = 15 },
+	{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+	{ .type = -1, .code = -1 },
+} ;
+
+static struct input_event strip_change[] = {
+	{ .type = EV_ABS, .code = ABS_RX, .value = LITEST_AUTO_ASSIGN },
+	{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+	{ .type = -1, .code = -1 },
+} ;
+
+static struct input_event strip_end[] = {
+	{ .type = EV_ABS, .code = ABS_RX, .value = 0 },
+	{ .type = EV_ABS, .code = ABS_MISC, .value = 0 },
+	{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+	{ .type = -1, .code = -1 },
+} ;
+
+static struct litest_device_interface interface = {
+	.touch_down_events = down,
+	.touch_move_events = move,
+	.pad_strip_start_events = strip_start,
+	.pad_strip_change_events = strip_change,
+	.pad_strip_end_events = strip_end,
+};
+
+static struct input_absinfo absinfo[] = {
+	{ ABS_X, 0, 1, 0, 0, 0 },
+	{ ABS_Y, 0, 1, 0, 0, 0 },
+	{ ABS_RX, 0, 4096, 0, 0, 0 },
+	{ ABS_MISC, 0, 0, 0, 0, 0 },
+	{ .value = -1 },
+};
+
+static struct input_id input_id = {
+	.bustype = 0x3,
+	.vendor = 0x56a,
+	.product = 0xb7,
+};
+
+static int events[] = {
+	EV_KEY, BTN_0,
+	EV_KEY, BTN_1,
+	EV_KEY, BTN_2,
+	EV_KEY, BTN_3,
+	EV_KEY, BTN_STYLUS,
+	-1, -1,
+};
+
+static const char udev_rule[] =
+"ACTION==\"remove\", GOTO=\"pad_end\"\n"
+"KERNEL!=\"event*\", GOTO=\"pad_end\"\n"
+"\n"
+"ATTRS{name}==\"litest Wacom Intuos3 4x6 Pad*\",\\\n"
+"    ENV{ID_INPUT_TABLET_PAD}=\"1\"\n"
+"\n"
+"LABEL=\"pad_end\"";
+
+struct litest_test_device litest_wacom_intuos3_pad_device = {
+	.type = LITEST_WACOM_INTUOS3_PAD,
+	.features = LITEST_TABLET_PAD | LITEST_STRIP,
+	.shortname = "wacom-intuos3-pad",
+	.setup = litest_wacom_intuos3_pad_setup,
+	.interface = &interface,
+
+	.name = "Wacom Intuos3 4x6 Pad",
+	.id = &input_id,
+	.events = events,
+	.absinfo = absinfo,
+	.udev_rule = udev_rule,
+};
diff --git a/test/litest-device-wacom-intuos5-pad.c b/test/litest-device-wacom-intuos5-pad.c
new file mode 100644
index 0000000..7cff412
--- /dev/null
+++ b/test/litest-device-wacom-intuos5-pad.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void
+litest_wacom_intuos5_pad_setup(void)
+{
+	struct litest_device *d = litest_create_device(LITEST_WACOM_INTUOS5_PAD);
+	litest_set_current_device(d);
+}
+
+static struct input_event down[] = {
+	{ .type = -1, .code = -1 },
+};
+
+static struct input_event move[] = {
+	{ .type = -1, .code = -1 },
+};
+
+static struct input_event ring_start[] = {
+	{ .type = EV_ABS, .code = ABS_WHEEL, .value = LITEST_AUTO_ASSIGN },
+	{ .type = EV_ABS, .code = ABS_MISC, .value = 15 },
+	{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+	{ .type = -1, .code = -1 },
+} ;
+
+static struct input_event ring_change[] = {
+	{ .type = EV_ABS, .code = ABS_WHEEL, .value = LITEST_AUTO_ASSIGN },
+	{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+	{ .type = -1, .code = -1 },
+} ;
+
+static struct input_event ring_end[] = {
+	{ .type = EV_ABS, .code = ABS_WHEEL, .value = 0 },
+	{ .type = EV_ABS, .code = ABS_MISC, .value = 0 },
+	{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+	{ .type = -1, .code = -1 },
+} ;
+
+static struct litest_device_interface interface = {
+	.touch_down_events = down,
+	.touch_move_events = move,
+	.pad_ring_start_events = ring_start,
+	.pad_ring_change_events = ring_change,
+	.pad_ring_end_events = ring_end,
+};
+
+static struct input_absinfo absinfo[] = {
+	{ ABS_X, 0, 1, 0, 0, 0 },
+	{ ABS_Y, 0, 1, 0, 0, 0 },
+	{ ABS_WHEEL, 0, 71, 0, 0, 0 },
+	{ ABS_MISC, 0, 0, 0, 0, 10 },
+	{ .value = -1 },
+};
+
+static struct input_id input_id = {
+	.bustype = 0x3,
+	.vendor = 0x56a,
+	.product = 0x27,
+};
+
+static int events[] = {
+	EV_KEY, BTN_0,
+	EV_KEY, BTN_1,
+	EV_KEY, BTN_2,
+	EV_KEY, BTN_3,
+	EV_KEY, BTN_4,
+	EV_KEY, BTN_5,
+	EV_KEY, BTN_6,
+	EV_KEY, BTN_7,
+	EV_KEY, BTN_8,
+	EV_KEY, BTN_STYLUS,
+	-1, -1,
+};
+
+static const char udev_rule[] =
+"ACTION==\"remove\", GOTO=\"pad_end\"\n"
+"KERNEL!=\"event*\", GOTO=\"pad_end\"\n"
+"\n"
+"ATTRS{name}==\"litest Wacom Intuos5 touch M Pad*\",\\\n"
+"    ENV{ID_INPUT_TABLET_PAD}=\"1\"\n"
+"\n"
+"LABEL=\"pad_end\"";
+
+struct litest_test_device litest_wacom_intuos5_pad_device = {
+	.type = LITEST_WACOM_INTUOS5_PAD,
+	.features = LITEST_TABLET_PAD | LITEST_RING,
+	.shortname = "wacom-pad",
+	.setup = litest_wacom_intuos5_pad_setup,
+	.interface = &interface,
+
+	.name = "Wacom Intuos5 touch M Pad",
+	.id = &input_id,
+	.events = events,
+	.absinfo = absinfo,
+	.udev_rule = udev_rule,
+};
diff --git a/test/litest-int.h b/test/litest-int.h
index 8d0308b..1a9060d 100644
--- a/test/litest-int.h
+++ b/test/litest-int.h
@@ -105,6 +105,22 @@ struct litest_device_interface {
 	struct input_event *tablet_proximity_out_events;
 	struct input_event *tablet_motion_events;
 
+	/**
+	 * Pad events, LITEST_AUTO_ASSIGN is allowed on event values
+	 * for ABS_WHEEL
+	 */
+	struct input_event *pad_ring_start_events;
+	struct input_event *pad_ring_change_events;
+	struct input_event *pad_ring_end_events;
+
+	/**
+	 * Pad events, LITEST_AUTO_ASSIGN is allowed on event values
+	 * for ABS_RX
+	 */
+	struct input_event *pad_strip_start_events;
+	struct input_event *pad_strip_change_events;
+	struct input_event *pad_strip_end_events;
+
 	int min[2]; /* x/y axis minimum */
 	int max[2]; /* x/y axis maximum */
 };
diff --git a/test/litest.c b/test/litest.c
index 70b4bd3..b10c42e 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -379,6 +379,8 @@ extern struct litest_test_device litest_cyborg_rat_device;
 extern struct litest_test_device litest_yubikey_device;
 extern struct litest_test_device litest_synaptics_i2c_device;
 extern struct litest_test_device litest_wacom_cintiq_24hd_device;
+extern struct litest_test_device litest_wacom_intuos3_pad_device;
+extern struct litest_test_device litest_wacom_intuos5_pad_device;
 
 struct litest_test_device* devices[] = {
 	&litest_synaptics_clickpad_device,
@@ -424,6 +426,8 @@ struct litest_test_device* devices[] = {
 	&litest_yubikey_device,
 	&litest_synaptics_i2c_device,
 	&litest_wacom_cintiq_24hd_device,
+	&litest_wacom_intuos3_pad_device,
+	&litest_wacom_intuos5_pad_device,
 	NULL,
 };
 
@@ -1809,6 +1813,15 @@ litest_scale_axis(const struct litest_device *d,
 	return (abs->maximum - abs->minimum) * val/100.0 + abs->minimum;
 }
 
+static inline int
+litest_scale_range(int min, int max, double val)
+{
+	litest_assert_int_ge((int)val, 0);
+	litest_assert_int_le((int)val, 100);
+
+	return (max - min) * val/100.0 + min;
+}
+
 int
 litest_scale(const struct litest_device *d, unsigned int axis, double val)
 {
@@ -1819,12 +1832,120 @@ litest_scale(const struct litest_device *d, unsigned int axis, double val)
 	if (axis <= ABS_Y) {
 		min = d->interface->min[axis];
 		max = d->interface->max[axis];
-		return (max - min) * val/100.0 + min;
+
+		return litest_scale_range(min, max, val);
 	} else {
 		return litest_scale_axis(d, axis, val);
 	}
 }
 
+static inline int
+auto_assign_pad_value(struct litest_device *dev,
+		      struct input_event *ev,
+		      double value)
+{
+	const struct input_absinfo *abs;
+
+	if (ev->value != LITEST_AUTO_ASSIGN ||
+	    ev->type != EV_ABS)
+		return value;
+
+	abs = libevdev_get_abs_info(dev->evdev, ev->code);
+	litest_assert_notnull(abs);
+
+	if (ev->code == ABS_RX || ev->code == ABS_RY) {
+		double min = abs->minimum != 0 ? log2(abs->minimum) : 0,
+		       max = abs->maximum != 0 ? log2(abs->maximum) : 0;
+
+		/* Value 0 is reserved for finger up, so a value of 0% is
+		 * actually 1 */
+		if (value == 0.0) {
+			return 1;
+		} else {
+			value = litest_scale_range(min, max, value);
+			return pow(2, value);
+		}
+	} else {
+		return litest_scale_range(abs->minimum, abs->maximum, value);
+	}
+}
+
+void
+litest_pad_ring_start(struct litest_device *d, double value)
+{
+	struct input_event *ev;
+
+	ev = d->interface->pad_ring_start_events;
+	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
+		value = auto_assign_pad_value(d, ev, value);
+		litest_event(d, ev->type, ev->code, value);
+		ev++;
+	}
+}
+
+void
+litest_pad_ring_change(struct litest_device *d, double value)
+{
+	struct input_event *ev;
+
+	ev = d->interface->pad_ring_change_events;
+	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
+		value = auto_assign_pad_value(d, ev, value);
+		litest_event(d, ev->type, ev->code, value);
+		ev++;
+	}
+}
+
+void
+litest_pad_ring_end(struct litest_device *d)
+{
+	struct input_event *ev;
+
+	ev = d->interface->pad_ring_end_events;
+	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
+		litest_event(d, ev->type, ev->code, ev->value);
+		ev++;
+	}
+}
+
+void
+litest_pad_strip_start(struct litest_device *d, double value)
+{
+	struct input_event *ev;
+
+	ev = d->interface->pad_strip_start_events;
+	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
+		value = auto_assign_pad_value(d, ev, value);
+		litest_event(d, ev->type, ev->code, value);
+		ev++;
+	}
+}
+
+void
+litest_pad_strip_change(struct litest_device *d, double value)
+{
+	struct input_event *ev;
+
+	ev = d->interface->pad_strip_change_events;
+	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
+		value = auto_assign_pad_value(d, ev, value);
+		litest_event(d, ev->type, ev->code, value);
+		ev++;
+	}
+}
+
+void
+litest_pad_strip_end(struct litest_device *d)
+{
+	struct input_event *ev;
+
+	ev = d->interface->pad_strip_end_events;
+	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
+		litest_event(d, ev->type, ev->code, ev->value);
+		ev++;
+	}
+}
+
 void
 litest_wait_for_event(struct libinput *li)
 {
@@ -1981,6 +2102,7 @@ litest_print_event(struct libinput_event *event)
 {
 	struct libinput_event_pointer *p;
 	struct libinput_event_tablet_tool *t;
+	struct libinput_event_tablet_pad *pad;
 	struct libinput_device *dev;
 	enum libinput_event_type type;
 	double x, y;
@@ -2042,6 +2164,26 @@ litest_print_event(struct libinput_event *event)
 			libinput_event_tablet_tool_get_button(t),
 			libinput_event_tablet_tool_get_button_state(t));
 		break;
+	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+		pad = libinput_event_get_tablet_pad_event(event);
+		fprintf(stderr, "button %d state %d",
+			libinput_event_tablet_pad_get_button_number(pad),
+			libinput_event_tablet_pad_get_button_state(pad));
+		break;
+	case LIBINPUT_EVENT_TABLET_PAD_RING:
+		pad = libinput_event_get_tablet_pad_event(event);
+		fprintf(stderr, "ring %d position %.2f source %d",
+			libinput_event_tablet_pad_get_ring_number(pad),
+			libinput_event_tablet_pad_get_ring_position(pad),
+			libinput_event_tablet_pad_get_ring_source(pad));
+		break;
+	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+		pad = libinput_event_get_tablet_pad_event(event);
+		fprintf(stderr, "strip %d position %.2f source %d",
+			libinput_event_tablet_pad_get_ring_number(pad),
+			libinput_event_tablet_pad_get_ring_position(pad),
+			libinput_event_tablet_pad_get_ring_source(pad));
+		break;
 	default:
 		break;
 	}
@@ -2463,6 +2605,81 @@ void litest_assert_tablet_proximity_event(struct libinput *li,
 	libinput_event_destroy(event);
 }
 
+struct libinput_event_tablet_pad *
+litest_is_pad_button_event(struct libinput_event *event,
+			   unsigned int button,
+			   enum libinput_button_state state)
+{
+	struct libinput_event_tablet_pad *p;
+	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_BUTTON;
+
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
+
+	p = libinput_event_get_tablet_pad_event(event);
+	litest_assert(p != NULL);
+
+	litest_assert_int_eq(libinput_event_tablet_pad_get_button_number(p),
+			     button);
+
+	return p;
+}
+
+struct libinput_event_tablet_pad *
+litest_is_pad_ring_event(struct libinput_event *event,
+			 unsigned int number,
+			 enum libinput_tablet_pad_ring_axis_source source)
+{
+	struct libinput_event_tablet_pad *p;
+	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_RING;
+
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
+	p = libinput_event_get_tablet_pad_event(event);
+
+	litest_assert_int_eq(libinput_event_tablet_pad_get_ring_number(p),
+			     number);
+	litest_assert_int_eq(libinput_event_tablet_pad_get_ring_source(p),
+			     source);
+
+	return p;
+}
+
+struct libinput_event_tablet_pad *
+litest_is_pad_strip_event(struct libinput_event *event,
+			  unsigned int number,
+			  enum libinput_tablet_pad_strip_axis_source source)
+{
+	struct libinput_event_tablet_pad *p;
+	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_STRIP;
+
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
+	p = libinput_event_get_tablet_pad_event(event);
+
+	litest_assert_int_eq(libinput_event_tablet_pad_get_strip_number(p),
+			     number);
+	litest_assert_int_eq(libinput_event_tablet_pad_get_strip_source(p),
+			     source);
+
+	return p;
+}
+
+void
+litest_assert_pad_button_event(struct libinput *li,
+			       unsigned int button,
+			       enum libinput_button_state state)
+{
+	struct libinput_event *event;
+	struct libinput_event_tablet_pad *pev;
+
+	litest_wait_for_event(li);
+	event = libinput_get_event(li);
+
+	pev = litest_is_pad_button_event(event, button, state);
+	libinput_event_destroy(libinput_event_tablet_pad_get_base_event(pev));
+}
+
 void
 litest_assert_scroll(struct libinput *li,
 		     enum libinput_pointer_axis axis,
diff --git a/test/litest.h b/test/litest.h
index c218361..81ce44d 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -196,6 +196,8 @@ enum litest_device_type {
 	LITEST_YUBIKEY = -42,
 	LITEST_SYNAPTICS_I2C = -43,
 	LITEST_WACOM_CINTIQ_24HD = -44,
+	LITEST_WACOM_INTUOS3_PAD = -45,
+	LITEST_WACOM_INTUOS5_PAD = -46,
 };
 
 enum litest_device_feature {
@@ -222,6 +224,9 @@ enum litest_device_feature {
 	LITEST_DISTANCE = 1 << 18,
 	LITEST_TOOL_SERIAL = 1 << 19,
 	LITEST_TILT = 1 << 20,
+	LITEST_TABLET_PAD = 1 << 21,
+	LITEST_RING = 1 << 22,
+	LITEST_STRIP = 1 << 23,
 };
 
 struct litest_device {
@@ -440,6 +445,24 @@ litest_tablet_motion(struct litest_device *d,
 		     struct axis_replacement *axes);
 
 void
+litest_pad_ring_start(struct litest_device *d, double value);
+
+void
+litest_pad_ring_change(struct litest_device *d, double value);
+
+void
+litest_pad_ring_end(struct litest_device *d);
+
+void
+litest_pad_strip_start(struct litest_device *d, double value);
+
+void
+litest_pad_strip_change(struct litest_device *d, double value);
+
+void
+litest_pad_strip_end(struct litest_device *d);
+
+void
 litest_hover_start(struct litest_device *d,
 		   unsigned int slot,
 		   double x,
@@ -525,6 +548,19 @@ struct libinput_event_tablet_tool *
 litest_is_tablet_event(struct libinput_event *event,
 		       enum libinput_event_type type);
 
+struct libinput_event_tablet_pad *
+litest_is_pad_button_event(struct libinput_event *event,
+			   unsigned int button,
+			   enum libinput_button_state state);
+struct libinput_event_tablet_pad *
+litest_is_pad_ring_event(struct libinput_event *event,
+			 unsigned int number,
+			 enum libinput_tablet_pad_ring_axis_source source);
+struct libinput_event_tablet_pad *
+litest_is_pad_strip_event(struct libinput_event *event,
+			  unsigned int number,
+			  enum libinput_tablet_pad_strip_axis_source source);
+
 void
 litest_assert_button_event(struct libinput *li,
 			   unsigned int button,
@@ -548,6 +584,10 @@ void
 litest_assert_tablet_proximity_event(struct libinput *li,
 				     enum libinput_tablet_tool_proximity_state state);
 
+void
+litest_assert_pad_button_event(struct libinput *li,
+				    unsigned int button,
+				    enum libinput_button_state state);
 struct libevdev_uinput *
 litest_create_uinput_device(const char *name,
 			    struct input_id *id,
diff --git a/test/misc.c b/test/misc.c
index e8b41e5..304710f 100644
--- a/test/misc.c
+++ b/test/misc.c
@@ -134,6 +134,7 @@ START_TEST(event_conversion_device_notify)
 			ck_assert(libinput_event_get_touch_event(event) == NULL);
 			ck_assert(libinput_event_get_gesture_event(event) == NULL);
 			ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 
@@ -190,6 +191,7 @@ START_TEST(event_conversion_pointer)
 			ck_assert(libinput_event_get_touch_event(event) == NULL);
 			ck_assert(libinput_event_get_gesture_event(event) == NULL);
 			ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 		libinput_event_destroy(event);
@@ -240,6 +242,7 @@ START_TEST(event_conversion_pointer_abs)
 			ck_assert(libinput_event_get_touch_event(event) == NULL);
 			ck_assert(libinput_event_get_gesture_event(event) == NULL);
 			ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 		libinput_event_destroy(event);
@@ -283,6 +286,7 @@ START_TEST(event_conversion_key)
 			ck_assert(libinput_event_get_touch_event(event) == NULL);
 			ck_assert(libinput_event_get_gesture_event(event) == NULL);
 			ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 		libinput_event_destroy(event);
@@ -333,6 +337,7 @@ START_TEST(event_conversion_touch)
 			ck_assert(libinput_event_get_keyboard_event(event) == NULL);
 			ck_assert(libinput_event_get_gesture_event(event) == NULL);
 			ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 		libinput_event_destroy(event);
@@ -381,6 +386,7 @@ START_TEST(event_conversion_gesture)
 			ck_assert(libinput_event_get_pointer_event(event) == NULL);
 			ck_assert(libinput_event_get_keyboard_event(event) == NULL);
 			ck_assert(libinput_event_get_touch_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 		libinput_event_destroy(event);
@@ -427,6 +433,50 @@ START_TEST(event_conversion_tablet)
 			ck_assert(libinput_event_get_pointer_event(event) == NULL);
 			ck_assert(libinput_event_get_keyboard_event(event) == NULL);
 			ck_assert(libinput_event_get_touch_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+			litest_restore_log_handler(li);
+		}
+		libinput_event_destroy(event);
+	}
+
+	ck_assert_int_gt(events, 0);
+}
+END_TEST
+
+START_TEST(event_conversion_tablet_pad)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *event;
+	int events = 0;
+
+	litest_button_click(dev, BTN_0, true);
+	litest_pad_ring_start(dev, 10);
+	litest_pad_ring_end(dev);
+
+	libinput_dispatch(li);
+
+	while ((event = libinput_get_event(li))) {
+		enum libinput_event_type type;
+		type = libinput_event_get_type(event);
+
+		if (type >= LIBINPUT_EVENT_TABLET_PAD_BUTTON &&
+		    type <= LIBINPUT_EVENT_TABLET_PAD_STRIP) {
+			struct libinput_event_tablet_pad *p;
+			struct libinput_event *base;
+
+			p = libinput_event_get_tablet_pad_event(event);
+			base = libinput_event_tablet_pad_get_base_event(p);
+			ck_assert(event == base);
+
+			events++;
+
+			litest_disable_log_handler(li);
+			ck_assert(libinput_event_get_device_notify_event(event) == NULL);
+			ck_assert(libinput_event_get_pointer_event(event) == NULL);
+			ck_assert(libinput_event_get_keyboard_event(event) == NULL);
+			ck_assert(libinput_event_get_touch_event(event) == NULL);
+			ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
 			litest_restore_log_handler(li);
 		}
 		libinput_event_destroy(event);
@@ -895,6 +945,7 @@ litest_setup_tests(void)
 	litest_add_for_device("events:conversion", event_conversion_touch, LITEST_WACOM_TOUCH);
 	litest_add_for_device("events:conversion", event_conversion_gesture, LITEST_BCM5974);
 	litest_add_for_device("events:conversion", event_conversion_tablet, LITEST_WACOM_CINTIQ);
+	litest_add_for_device("events:conversion", event_conversion_tablet_pad, LITEST_WACOM_INTUOS5_PAD);
 	litest_add_no_device("bitfield_helpers", bitfield_helpers);
 
 	litest_add_no_device("context:refcount", context_ref_counting);
diff --git a/test/pad.c b/test/pad.c
new file mode 100644
index 0000000..63bd2d7
--- /dev/null
+++ b/test/pad.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <check.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libinput.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include "libinput-util.h"
+#include "litest.h"
+
+START_TEST(pad_cap)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+
+	ck_assert(libinput_device_has_capability(device,
+						 LIBINPUT_DEVICE_CAP_TABLET_PAD));
+
+}
+END_TEST
+
+START_TEST(pad_no_cap)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+
+	ck_assert(!libinput_device_has_capability(device,
+						  LIBINPUT_DEVICE_CAP_TABLET_PAD));
+}
+END_TEST
+
+START_TEST(pad_num_buttons)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+	unsigned int code;
+	unsigned int nbuttons = 0;
+
+	for (code = BTN_0; code < KEY_MAX; code++) {
+		/* BTN_STYLUS is set for compatibility reasons but not
+		 * actually hooked up */
+		if (code == BTN_STYLUS)
+			continue;
+
+		if (libevdev_has_event_code(dev->evdev, EV_KEY, code))
+			nbuttons++;
+	}
+
+	ck_assert_int_eq(libinput_device_tablet_pad_get_num_buttons(device),
+			 nbuttons);
+}
+END_TEST
+
+START_TEST(pad_button)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	unsigned int code;
+	unsigned int expected_number = 0;
+	struct libinput_event *ev;
+	struct libinput_event_tablet_pad *pev;
+
+	litest_drain_events(li);
+
+	for (code = BTN_LEFT; code < KEY_MAX; code++) {
+		if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
+			continue;
+
+		litest_button_click(dev, code, 1);
+		litest_button_click(dev, code, 0);
+		libinput_dispatch(li);
+
+		switch (code) {
+		case BTN_STYLUS:
+			litest_assert_empty_queue(li);
+			continue;
+		default:
+			break;
+		}
+
+		ev = libinput_get_event(li);
+		pev = litest_is_pad_button_event(ev,
+						 expected_number,
+						 LIBINPUT_BUTTON_STATE_PRESSED);
+		ev = libinput_event_tablet_pad_get_base_event(pev);
+		libinput_event_destroy(ev);
+
+		ev = libinput_get_event(li);
+		pev = litest_is_pad_button_event(ev,
+						 expected_number,
+						 LIBINPUT_BUTTON_STATE_RELEASED);
+		ev = libinput_event_tablet_pad_get_base_event(pev);
+		libinput_event_destroy(ev);
+
+		expected_number++;
+	}
+
+	litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(pad_has_ring)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+	int nrings;
+
+	nrings = libinput_device_tablet_pad_get_num_rings(device);
+	ck_assert_int_ge(nrings, 1);
+}
+END_TEST
+
+START_TEST(pad_ring)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *ev;
+	struct libinput_event_tablet_pad *pev;
+	int val;
+	double degrees, expected;
+
+	litest_pad_ring_start(dev, 10);
+
+	litest_drain_events(li);
+
+	/* Wacom's 0 value is at 275 degrees */
+	expected = 270;
+
+	for (val = 0; val < 100; val += 10) {
+		litest_pad_ring_change(dev, val);
+		libinput_dispatch(li);
+
+		ev = libinput_get_event(li);
+		pev = litest_is_pad_ring_event(ev,
+					       0,
+					       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
+
+		degrees = libinput_event_tablet_pad_get_ring_position(pev);
+		ck_assert_double_ge(degrees, 0.0);
+		ck_assert_double_lt(degrees, 360.0);
+
+		/* rounding errors, mostly caused by small physical range */
+		ck_assert_double_ge(degrees, expected - 2);
+		ck_assert_double_le(degrees, expected + 2);
+
+		libinput_event_destroy(ev);
+
+		expected = fmod(degrees + 36, 360);
+	}
+
+	litest_pad_ring_end(dev);
+}
+END_TEST
+
+START_TEST(pad_ring_finger_up)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *ev;
+	struct libinput_event_tablet_pad *pev;
+	double degrees;
+
+	litest_pad_ring_start(dev, 10);
+
+	litest_drain_events(li);
+
+	litest_pad_ring_end(dev);
+	libinput_dispatch(li);
+
+	ev = libinput_get_event(li);
+	pev = litest_is_pad_ring_event(ev,
+				       0,
+				       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
+
+	degrees = libinput_event_tablet_pad_get_ring_position(pev);
+	ck_assert_double_eq(degrees, -1.0);
+	libinput_event_destroy(ev);
+
+	litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(pad_has_strip)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+	int nstrips;
+
+	nstrips = libinput_device_tablet_pad_get_num_strips(device);
+	ck_assert_int_ge(nstrips, 1);
+}
+END_TEST
+
+START_TEST(pad_strip)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *ev;
+	struct libinput_event_tablet_pad *pev;
+	int val;
+	double pos, expected;
+
+	litest_pad_strip_start(dev, 10);
+
+	litest_drain_events(li);
+
+	expected = 0;
+
+	/* 9.5 works with the generic axis scaling without jumping over a
+	 * value. */
+	for (val = 0; val < 100; val += 9.5) {
+		litest_pad_strip_change(dev, val);
+		libinput_dispatch(li);
+
+		ev = libinput_get_event(li);
+		pev = litest_is_pad_strip_event(ev,
+						0,
+						LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
+
+		pos = libinput_event_tablet_pad_get_strip_position(pev);
+		ck_assert_double_ge(pos, 0.0);
+		ck_assert_double_lt(pos, 1.0);
+
+		/* rounding errors, mostly caused by small physical range */
+		ck_assert_double_ge(pos, expected - 0.02);
+		ck_assert_double_le(pos, expected + 0.02);
+
+		libinput_event_destroy(ev);
+
+		expected = pos + 0.08;
+	}
+
+	litest_pad_strip_change(dev, 100);
+	libinput_dispatch(li);
+
+	ev = libinput_get_event(li);
+	pev = litest_is_pad_strip_event(ev,
+					   0,
+					   LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
+	pos = libinput_event_tablet_pad_get_strip_position(pev);
+	ck_assert_double_eq(pos, 1.0);
+	libinput_event_destroy(ev);
+
+	litest_pad_strip_end(dev);
+}
+END_TEST
+
+START_TEST(pad_strip_finger_up)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *ev;
+	struct libinput_event_tablet_pad *pev;
+	double pos;
+
+	litest_pad_strip_start(dev, 10);
+	litest_drain_events(li);
+
+	litest_pad_strip_end(dev);
+	libinput_dispatch(li);
+
+	ev = libinput_get_event(li);
+	pev = litest_is_pad_strip_event(ev,
+					0,
+					LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
+
+	pos = libinput_event_tablet_pad_get_strip_position(pev);
+	ck_assert_double_eq(pos, -1.0);
+	libinput_event_destroy(ev);
+
+	litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(pad_left_handed_default)
+{
+#if HAVE_LIBWACOM
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+	enum libinput_config_status status;
+
+	ck_assert(libinput_device_config_left_handed_is_available(device));
+
+	ck_assert_int_eq(libinput_device_config_left_handed_get_default(device),
+			 0);
+	ck_assert_int_eq(libinput_device_config_left_handed_get(device),
+			 0);
+
+	status = libinput_device_config_left_handed_set(dev->libinput_device, 1);
+	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+
+	ck_assert_int_eq(libinput_device_config_left_handed_get(device),
+			 1);
+	ck_assert_int_eq(libinput_device_config_left_handed_get_default(device),
+			 0);
+
+	status = libinput_device_config_left_handed_set(dev->libinput_device, 0);
+	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+
+	ck_assert_int_eq(libinput_device_config_left_handed_get(device),
+			 0);
+	ck_assert_int_eq(libinput_device_config_left_handed_get_default(device),
+			 0);
+
+#endif
+}
+END_TEST
+
+START_TEST(pad_no_left_handed)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput_device *device = dev->libinput_device;
+	enum libinput_config_status status;
+
+	ck_assert(!libinput_device_config_left_handed_is_available(device));
+
+	ck_assert_int_eq(libinput_device_config_left_handed_get_default(device),
+			 0);
+	ck_assert_int_eq(libinput_device_config_left_handed_get(device),
+			 0);
+
+	status = libinput_device_config_left_handed_set(dev->libinput_device, 1);
+	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
+
+	ck_assert_int_eq(libinput_device_config_left_handed_get(device),
+			 0);
+	ck_assert_int_eq(libinput_device_config_left_handed_get_default(device),
+			 0);
+
+	status = libinput_device_config_left_handed_set(dev->libinput_device, 0);
+	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
+
+	ck_assert_int_eq(libinput_device_config_left_handed_get(device),
+			 0);
+	ck_assert_int_eq(libinput_device_config_left_handed_get_default(device),
+			 0);
+}
+END_TEST
+
+START_TEST(pad_left_handed_ring)
+{
+#if HAVE_LIBWACOM
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *ev;
+	struct libinput_event_tablet_pad *pev;
+	int val;
+	double degrees, expected;
+
+	libinput_device_config_left_handed_set(dev->libinput_device, 1);
+
+	litest_pad_ring_start(dev, 10);
+
+	litest_drain_events(li);
+
+	/* Wacom's 0 value is at 275 degrees -> 90 in left-handed mode*/
+	expected = 90;
+
+	for (val = 0; val < 100; val += 10) {
+		litest_pad_ring_change(dev, val);
+		libinput_dispatch(li);
+
+		ev = libinput_get_event(li);
+		pev = litest_is_pad_ring_event(ev,
+					       0,
+					       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
+
+		degrees = libinput_event_tablet_pad_get_ring_position(pev);
+		ck_assert_double_ge(degrees, 0.0);
+		ck_assert_double_lt(degrees, 360.0);
+
+		/* rounding errors, mostly caused by small physical range */
+		ck_assert_double_ge(degrees, expected - 2);
+		ck_assert_double_le(degrees, expected + 2);
+
+		libinput_event_destroy(ev);
+
+		expected = fmod(degrees + 36, 360);
+	}
+
+	litest_pad_ring_end(dev);
+#endif
+}
+END_TEST
+
+void
+litest_setup_tests(void)
+{
+	litest_add("pad:cap", pad_cap, LITEST_TABLET_PAD, LITEST_ANY);
+	litest_add("pad:cap", pad_no_cap, LITEST_ANY, LITEST_TABLET_PAD);
+
+	litest_add("pad:button", pad_num_buttons, LITEST_TABLET_PAD, LITEST_ANY);
+	litest_add("pad:button", pad_button, LITEST_TABLET_PAD, LITEST_ANY);
+
+	litest_add("pad:ring", pad_has_ring, LITEST_RING, LITEST_ANY);
+	litest_add("pad:ring", pad_ring, LITEST_RING, LITEST_ANY);
+	litest_add("pad:ring", pad_ring_finger_up, LITEST_RING, LITEST_ANY);
+
+	litest_add("pad:strip", pad_has_strip, LITEST_STRIP, LITEST_ANY);
+	litest_add("pad:strip", pad_strip, LITEST_STRIP, LITEST_ANY);
+	litest_add("pad:strip", pad_strip_finger_up, LITEST_STRIP, LITEST_ANY);
+
+	litest_add_for_device("pad:left_handed", pad_left_handed_default, LITEST_WACOM_INTUOS5_PAD);
+	litest_add_for_device("pad:left_handed", pad_no_left_handed, LITEST_WACOM_INTUOS3_PAD);
+	litest_add_for_device("pad:left_handed", pad_left_handed_ring, LITEST_WACOM_INTUOS5_PAD);
+	/* None of the current strip tablets are left-handed */
+}
-- 
2.5.5



More information about the wayland-devel mailing list