[PATCH libinput 09/15] tablet: support airbrush wheel as slider

Peter Hutterer peter.hutterer at who-t.net
Tue Feb 17 21:45:10 PST 2015


The little wheel isn't a full wheel, it has a ~90 degree rotation angle with a
range of 1024 values. To avoid confusion with "wheel" elsewhere in the API
name it slider.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-tablet.c     | 12 +++++--
 src/evdev-tablet.h     |  6 ++++
 src/libinput-private.h |  2 +-
 src/libinput.c         |  1 +
 src/libinput.h         |  3 ++
 test/tablet.c          | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/event-debug.c    |  8 ++++-
 7 files changed, 118 insertions(+), 4 deletions(-)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 589cb9c..27589b1 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -76,6 +76,7 @@ tablet_process_absolute(struct tablet_dispatch *tablet,
 	case ABS_TILT_X:
 	case ABS_TILT_Y:
 	case ABS_DISTANCE:
+	case ABS_WHEEL:
 		axis = evcode_to_axis(e->code);
 		if (axis == LIBINPUT_TABLET_AXIS_NONE) {
 			log_bug_libinput(device->base.seat->libinput,
@@ -153,7 +154,7 @@ tablet_update_tool(struct tablet_dispatch *tablet,
 }
 
 static inline double
-normalize_pressure_or_dist(const struct input_absinfo *absinfo)
+normalize_pressure_dist_slider(const struct input_absinfo *absinfo)
 {
 	double range = absinfo->maximum - absinfo->minimum;
 	double value = (absinfo->value - absinfo->minimum) / range;
@@ -251,7 +252,8 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 			break;
 		case LIBINPUT_TABLET_AXIS_DISTANCE:
 		case LIBINPUT_TABLET_AXIS_PRESSURE:
-			tablet->axes[a] = normalize_pressure_or_dist(absinfo);
+		case LIBINPUT_TABLET_AXIS_SLIDER:
+			tablet->axes[a] = normalize_pressure_dist_slider(absinfo);
 			break;
 		case LIBINPUT_TABLET_AXIS_TILT_X:
 		case LIBINPUT_TABLET_AXIS_TILT_Y:
@@ -425,6 +427,8 @@ tablet_get_tool(struct tablet_dispatch *tablet,
 		 * down of the heuristics used here:
 		 * - The Wacom art pen supports all of the extra axes, along
 		 *   with rotation
+		 * - The Wacom airbrush supports a wheel with a ~90 deg
+		 *   range.
 		 * - 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 report any of
@@ -452,6 +456,10 @@ tablet_get_tool(struct tablet_dispatch *tablet,
 				       LIBINPUT_TABLET_AXIS_TILT_Y))
 				set_bit(tool->axis_caps,
 					LIBINPUT_TABLET_AXIS_TILT_Y);
+			if (bit_is_set(tablet->axis_caps,
+				       LIBINPUT_TABLET_AXIS_SLIDER))
+				set_bit(tool->axis_caps,
+					LIBINPUT_TABLET_AXIS_SLIDER);
 			break;
 		case LIBINPUT_TOOL_MOUSE:
 		case LIBINPUT_TOOL_LENS:
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 4f35417..ee2ef08 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -86,6 +86,9 @@ evcode_to_axis(const uint32_t evcode)
 	case ABS_TILT_Y:
 		axis = LIBINPUT_TABLET_AXIS_TILT_Y;
 		break;
+	case ABS_WHEEL:
+		axis = LIBINPUT_TABLET_AXIS_SLIDER;
+		break;
 	default:
 		axis = LIBINPUT_TABLET_AXIS_NONE;
 		break;
@@ -118,6 +121,9 @@ axis_to_evcode(const enum libinput_tablet_axis axis)
 	case LIBINPUT_TABLET_AXIS_TILT_Y:
 		evcode = ABS_TILT_Y;
 		break;
+	case LIBINPUT_TABLET_AXIS_SLIDER:
+		evcode = ABS_WHEEL;
+		break;
 	default:
 		abort();
 	}
diff --git a/src/libinput-private.h b/src/libinput-private.h
index df59d28..0b01029 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -30,7 +30,7 @@
 #include "libinput.h"
 #include "libinput-util.h"
 
-#define LIBINPUT_TABLET_AXIS_MAX LIBINPUT_TABLET_AXIS_ROTATION_Z
+#define LIBINPUT_TABLET_AXIS_MAX LIBINPUT_TABLET_AXIS_SLIDER
 
 struct libinput_source;
 
diff --git a/src/libinput.c b/src/libinput.c
index d2af72f..7c90f37 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -585,6 +585,7 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event,
 		case LIBINPUT_TABLET_AXIS_TILT_X:
 		case LIBINPUT_TABLET_AXIS_TILT_Y:
 		case LIBINPUT_TABLET_AXIS_ROTATION_Z:
+		case LIBINPUT_TABLET_AXIS_SLIDER:
 			return event->axes[axis];
 		default:
 			return 0;
diff --git a/src/libinput.h b/src/libinput.h
index dbd7bc4..7b90e91 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -144,6 +144,7 @@ enum libinput_tablet_axis {
 	LIBINPUT_TABLET_AXIS_TILT_X = 5,
 	LIBINPUT_TABLET_AXIS_TILT_Y = 6,
 	LIBINPUT_TABLET_AXIS_ROTATION_Z = 7,
+	LIBINPUT_TABLET_AXIS_SLIDER = 8,
 };
 
 /**
@@ -1044,6 +1045,8 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event,
  *   @ref LIBINPUT_TOOL_MOUSE and @ref LIBINPUT_TOOL_LENS tools the logical
  *   neutral position is pointing to the current logical north of the
  *   tablet.
+ * - @ref LIBINPUT_TABLET_AXIS_SLIDER - A slider on the tool, normalized
+ *   from 0 to 1. e.g. the wheel-like tool on the Wacom Airbrush.
  *
  * @note This function may be called for a specific axis even if
  * libinput_event_tablet_axis_has_changed() returns 0 for that axis.
diff --git a/test/tablet.c b/test/tablet.c
index 3373f92..3ab9fa3 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -1147,6 +1147,94 @@ START_TEST(mouse_rotation)
 }
 END_TEST
 
+START_TEST(airbrush_tool)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *event;
+	struct libinput_event_tablet *tev;
+	struct libinput_tool *tool;
+
+	if (!libevdev_has_event_code(dev->evdev,
+				    EV_KEY,
+				    BTN_TOOL_AIRBRUSH))
+		return;
+
+	litest_drain_events(li);
+
+	litest_event(dev, EV_KEY, BTN_TOOL_AIRBRUSH, 1);
+	litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	litest_wait_for_event_of_type(li,
+				      LIBINPUT_EVENT_TABLET_PROXIMITY,
+				      -1);
+	event = libinput_get_event(li);
+	tev = libinput_event_get_tablet_event(event);
+	tool = libinput_event_tablet_get_tool(tev);
+	ck_assert_notnull(tool);
+	ck_assert_int_eq(libinput_tool_get_type(tool),
+			 LIBINPUT_TOOL_AIRBRUSH);
+
+	libinput_event_destroy(event);
+}
+END_TEST
+
+START_TEST(airbrush_wheel)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *event;
+	struct libinput_event_tablet *tev;
+	const struct input_absinfo *abs;
+	double val;
+	double scale;
+	int angle;
+
+	if (!libevdev_has_event_code(dev->evdev,
+				    EV_KEY,
+				    BTN_TOOL_AIRBRUSH))
+		return;
+
+	litest_drain_events(li);
+
+	abs = libevdev_get_abs_info(dev->evdev, ABS_WHEEL);
+	ck_assert_notnull(abs);
+
+	litest_event(dev, EV_KEY, BTN_TOOL_AIRBRUSH, 1);
+	litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	/* start with non-zero */
+	litest_event(dev, EV_ABS, ABS_WHEEL, 10);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	litest_drain_events(li);
+
+	scale = (abs->maximum - abs->minimum)/360.0;
+	for (angle = 0; angle < 360; angle += 8) {
+		int a = angle * scale + abs->minimum;
+
+		litest_event(dev, EV_ABS, ABS_WHEEL, a);
+		litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+		litest_wait_for_event_of_type(li,
+					      LIBINPUT_EVENT_TABLET_AXIS,
+					      -1);
+		event = libinput_get_event(li);
+		tev = libinput_event_get_tablet_event(event);
+		ck_assert(libinput_event_tablet_axis_has_changed(tev,
+					 LIBINPUT_TABLET_AXIS_SLIDER));
+		val = libinput_event_tablet_get_axis_value(tev,
+					 LIBINPUT_TABLET_AXIS_SLIDER);
+
+		ck_assert_int_eq(val, angle);
+		libinput_event_destroy(event);
+		litest_assert_empty_queue(li);
+	}
+}
+END_TEST
+
 int
 main(int argc, char **argv)
 {
@@ -1168,6 +1256,8 @@ main(int argc, char **argv)
 	litest_add("tablet:pad", pad_buttons_ignored, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:mouse", mouse_tool, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:mouse", mouse_rotation, LITEST_TABLET, LITEST_ANY);
+	litest_add("tablet:airbrush", airbrush_tool, LITEST_TABLET, LITEST_ANY);
+	litest_add("tablet:airbrush", airbrush_wheel, LITEST_TABLET, LITEST_ANY);
 
 	return litest_run(argc, argv);
 }
diff --git a/tools/event-debug.c b/tools/event-debug.c
index e8186dd..0d25d6a 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -293,7 +293,7 @@ print_tablet_axis_event(struct libinput_event *ev)
 	struct libinput_event_tablet *t = libinput_event_get_tablet_event(ev);
 	double x, y;
 	double dist, pressure;
-	double rotation;
+	double rotation, slider;
 
 	print_event_time(libinput_event_tablet_get_time(t));
 
@@ -324,6 +324,12 @@ print_tablet_axis_event(struct libinput_event *ev)
 	       rotation,
 	       tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_ROTATION_Z));
 
+	slider = libinput_event_tablet_get_axis_value(t,
+					LIBINPUT_TABLET_AXIS_SLIDER);
+	printf(" slider: %.2f%s",
+	       slider,
+	       tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_SLIDER));
+
 	printf("\n");
 }
 
-- 
2.1.0



More information about the wayland-devel mailing list