[PATCH libinput 24/26] tablet: support the rel wheel on the mouse device

Peter Hutterer peter.hutterer at who-t.net
Mon Feb 23 22:21:27 PST 2015


Providing a relative axis in the axis_get_value() is inconsistent with the
other axes, this will be fixed in a follow-up commit.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-tablet.c     | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/evdev-tablet.h     | 18 ++++++++++++++++
 src/libinput-private.h |  2 +-
 src/libinput.c         |  1 +
 src/libinput.h         |  4 ++++
 test/tablet.c          | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/event-debug.c    | 11 +++++++++-
 7 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index d05b6c2..0fd5033 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -82,6 +82,10 @@ tablet_device_has_axis(struct tablet_dispatch *tablet,
 			    libevdev_has_event_code(evdev,
 						    EV_ABS,
 						    ABS_TILT_Y));
+	} else if (axis == LIBINPUT_TABLET_AXIS_REL_WHEEL) {
+		has_axis = libevdev_has_event_code(evdev,
+						   EV_REL,
+						   REL_WHEEL);
 	} else {
 		code = axis_to_evcode(axis);
 		has_axis = libevdev_has_event_code(evdev,
@@ -251,6 +255,15 @@ convert_to_degrees(const struct input_absinfo *absinfo, double offset)
 	return fmod(value * 360.0 + offset, 360.0);
 }
 
+static inline double
+normalize_wheel(struct tablet_dispatch *tablet,
+		int value)
+{
+	struct evdev_device *device = tablet->device;
+
+	return value * device->scroll.wheel_click_angle;
+}
+
 static void
 tablet_check_notify_axes(struct tablet_dispatch *tablet,
 			 struct evdev_device *device,
@@ -282,6 +295,11 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 			axes[LIBINPUT_TABLET_AXIS_TILT_Y] = 0;
 			axes[a] = tablet->axes[a];
 			continue;
+		} else if (a == LIBINPUT_TABLET_AXIS_REL_WHEEL) {
+			tablet->axes[a] = normalize_wheel(tablet,
+							  tablet->deltas[a]);
+			axes[a] = tablet->axes[a];
+			break;
 		}
 
 		absinfo = libevdev_get_abs_info(device->evdev,
@@ -442,6 +460,35 @@ tablet_process_key(struct tablet_dispatch *tablet,
 }
 
 static void
+tablet_process_relative(struct tablet_dispatch *tablet,
+			struct evdev_device *device,
+			struct input_event *e,
+			uint32_t time)
+{
+	enum libinput_tablet_axis axis;
+	switch (e->code) {
+	case REL_WHEEL:
+		axis = rel_evcode_to_axis(e->code);
+		if (axis == LIBINPUT_TABLET_AXIS_NONE) {
+			log_bug_libinput(device->base.seat->libinput,
+					 "Invalid ABS event code %#x\n",
+					 e->code);
+			break;
+		}
+		set_bit(tablet->changed_axes, axis);
+		tablet->deltas[axis] = e->value;
+		tablet_set_status(tablet, TABLET_AXES_UPDATED);
+		break;
+	default:
+		log_info(tablet->device->base.seat->libinput,
+			 "Unhandled relative axis %s (%#x)\n",
+			 libevdev_event_code_get_name(EV_REL, e->code),
+			 e->code);
+		return;
+	}
+}
+
+static void
 tablet_process_misc(struct tablet_dispatch *tablet,
 		    struct evdev_device *device,
 		    struct input_event *e,
@@ -535,6 +582,11 @@ tool_set_bits_from_libwacom(const struct tablet_dispatch *tablet,
 		break;
 	case WSTYLUS_PUCK:
 		copy_axis_cap(tablet, tool, LIBINPUT_TABLET_AXIS_ROTATION_Z);
+		/* lens cursors don't have a wheel */
+		if (!libwacom_stylus_has_lens(s))
+			copy_axis_cap(tablet,
+				      tool,
+				      LIBINPUT_TABLET_AXIS_REL_WHEEL);
 		break;
 	default:
 		break;
@@ -578,6 +630,7 @@ tool_set_bits(const struct tablet_dispatch *tablet,
 	case LIBINPUT_TOOL_MOUSE:
 	case LIBINPUT_TOOL_LENS:
 		copy_axis_cap(tablet, tool, LIBINPUT_TABLET_AXIS_ROTATION_Z);
+		copy_axis_cap(tablet, tool, LIBINPUT_TABLET_AXIS_REL_WHEEL);
 		break;
 	default:
 		break;
@@ -824,6 +877,9 @@ tablet_process(struct evdev_dispatch *dispatch,
 	case EV_ABS:
 		tablet_process_absolute(tablet, device, e, time);
 		break;
+	case EV_REL:
+		tablet_process_relative(tablet, device, e, time);
+		break;
 	case EV_KEY:
 		tablet_process_key(tablet, device, e, time);
 		break;
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 7c472cf..ea103b0 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -50,6 +50,7 @@ struct tablet_dispatch {
 	unsigned char status;
 	unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
 	double axes[LIBINPUT_TABLET_AXIS_MAX + 1];
+	double deltas[LIBINPUT_TABLET_AXIS_MAX + 1];
 	unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
 
 	/* Only used for tablets that don't report serial numbers */
@@ -101,6 +102,23 @@ evcode_to_axis(const uint32_t evcode)
 	return axis;
 }
 
+static inline enum libinput_tablet_axis
+rel_evcode_to_axis(const uint32_t evcode)
+{
+	enum libinput_tablet_axis axis;
+
+	switch (evcode) {
+	case REL_WHEEL:
+		axis = LIBINPUT_TABLET_AXIS_REL_WHEEL;
+		break;
+	default:
+		axis = LIBINPUT_TABLET_AXIS_NONE;
+		break;
+	}
+
+	return axis;
+}
+
 static inline uint32_t
 axis_to_evcode(const enum libinput_tablet_axis axis)
 {
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 84e5aaa..071204e 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_SLIDER
+#define LIBINPUT_TABLET_AXIS_MAX LIBINPUT_TABLET_AXIS_REL_WHEEL
 
 struct libinput_source;
 
diff --git a/src/libinput.c b/src/libinput.c
index 9df3d48..2640321 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -586,6 +586,7 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event,
 		case LIBINPUT_TABLET_AXIS_TILT_Y:
 		case LIBINPUT_TABLET_AXIS_ROTATION_Z:
 		case LIBINPUT_TABLET_AXIS_SLIDER:
+		case LIBINPUT_TABLET_AXIS_REL_WHEEL:
 			return event->axes[axis];
 		default:
 			return 0;
diff --git a/src/libinput.h b/src/libinput.h
index 87d220b..5737873 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -144,6 +144,7 @@ enum libinput_tablet_axis {
 	LIBINPUT_TABLET_AXIS_TILT_Y = 6,
 	LIBINPUT_TABLET_AXIS_ROTATION_Z = 7,
 	LIBINPUT_TABLET_AXIS_SLIDER = 8,
+	LIBINPUT_TABLET_AXIS_REL_WHEEL = 9,
 };
 
 /**
@@ -1060,6 +1061,9 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event,
  *   position is with the buttons pointing up.
  * - @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.
+ * - @ref LIBINPUT_TABLET_AXIS_REL_WHEEL - A relative wheel on the tool,
+ *   similar or equivalent to a mouse wheel. The value is a delta from the
+ *   device's previous position, in degrees.
  *
  * @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 afc654e..e46314a 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -1273,6 +1273,59 @@ START_TEST(mouse_rotation)
 }
 END_TEST
 
+START_TEST(mouse_wheel)
+{
+	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;
+	double val;
+
+	if (!libevdev_has_event_code(dev->evdev,
+				     EV_REL,
+				     REL_WHEEL))
+		return;
+
+	litest_drain_events(li);
+
+	litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
+	litest_event(dev, EV_ABS, ABS_MISC, 0x806); /* 5-button mouse tool_id */
+	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);
+	libinput_tool_ref(tool);
+
+	libinput_event_destroy(event);
+
+	ck_assert(libinput_tool_has_axis(tool,
+					 LIBINPUT_TABLET_AXIS_REL_WHEEL));
+
+	litest_event(dev, EV_REL, REL_WHEEL, -1);
+	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_REL_WHEEL));
+	val = libinput_event_tablet_get_axis_value(tev,
+					LIBINPUT_TABLET_AXIS_REL_WHEEL);
+	ck_assert_int_eq(val, 15);
+	libinput_event_destroy(event);
+
+	libinput_tool_unref(tool);
+}
+END_TEST
+
 START_TEST(airbrush_tool)
 {
 	struct litest_device *dev = litest_current_device();
@@ -1475,6 +1528,7 @@ main(int argc, char **argv)
 	litest_add("tablet:mouse", mouse_tool, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:mouse", mouse_buttons, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:mouse", mouse_rotation, LITEST_TABLET, LITEST_ANY);
+	litest_add("tablet:mouse", mouse_wheel, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:airbrush", airbrush_tool, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:airbrush", airbrush_wheel, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:artpen", artpen_tool, LITEST_TABLET, LITEST_ANY);
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 94a90ec..09edac0 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -293,7 +293,7 @@ print_tablet_axes(struct libinput_event_tablet *t)
 	struct libinput_tool *tool = libinput_event_tablet_get_tool(t);
 	double x, y;
 	double dist, pressure;
-	double rotation, slider;
+	double rotation, slider, wheel;
 
 	x = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_X);
 	y = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_Y);
@@ -350,6 +350,15 @@ print_tablet_axes(struct libinput_event_tablet *t)
 		       tablet_axis_changed_sym(t,
 				       LIBINPUT_TABLET_AXIS_SLIDER));
 	}
+
+	if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_REL_WHEEL)) {
+		wheel = libinput_event_tablet_get_axis_value(t,
+					LIBINPUT_TABLET_AXIS_REL_WHEEL);
+		printf("\twheel: %.2f%s",
+		       wheel,
+		       tablet_axis_changed_sym(t,
+				       LIBINPUT_TABLET_AXIS_REL_WHEEL));
+	}
 }
 
 static void
-- 
2.1.0



More information about the wayland-devel mailing list