[PATCH v2 libinput 25/26] tablet: add libinput_tablet_get_axis_delta()

Peter Hutterer peter.hutterer at who-t.net
Wed Feb 25 20:33:00 PST 2015


Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v2:
- delta was stored in tablet->axes[a], causing a wrong axis_value and a
wrong axis_delta. which the test didn' catch because it didn't trigger.
fixed now, store the wheel value in deltas and leave axes at 0


 src/evdev-tablet.c     | 56 +++++++++++++++++++++++++++---
 src/libinput-private.h |  3 +-
 src/libinput.c         | 38 ++++++++++++++++++++-
 src/libinput.h         | 27 +++++++++++++--
 src/libinput.sym       |  1 +
 test/tablet.c          | 93 +++++++++++++++++++++++++++++++++++++++++++-------
 tools/event-debug.c    | 54 +++++++++++++++++++++--------
 7 files changed, 236 insertions(+), 36 deletions(-)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 8de6fc4..f5cd63f 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -264,6 +264,48 @@ normalize_wheel(struct tablet_dispatch *tablet,
 	return value * device->scroll.wheel_click_angle;
 }
 
+static inline double
+guess_wheel_delta(double current, double old)
+{
+       double d1, d2, d3;
+
+       d1 = current - old;
+       d2 = (current + 360.0) - old;
+       d3 = current - (old + 360.0);
+
+       if (fabs(d2) < fabs(d1))
+               d1 = d2;
+
+       if (fabs(d3) < fabs(d1))
+               d1 = d3;
+
+       return d1;
+}
+
+static inline double
+get_delta(enum libinput_tablet_axis axis, double current, double old)
+{
+	double delta = 0;
+
+	switch (axis) {
+	case LIBINPUT_TABLET_AXIS_X:
+	case LIBINPUT_TABLET_AXIS_Y:
+	case LIBINPUT_TABLET_AXIS_DISTANCE:
+	case LIBINPUT_TABLET_AXIS_PRESSURE:
+	case LIBINPUT_TABLET_AXIS_SLIDER:
+	case LIBINPUT_TABLET_AXIS_TILT_X:
+	case LIBINPUT_TABLET_AXIS_TILT_Y:
+		delta = current - old;
+		break;
+	case LIBINPUT_TABLET_AXIS_ROTATION_Z:
+		delta = guess_wheel_delta(current, old);
+		break;
+	default:
+		abort();
+	}
+	return delta;
+}
+
 static void
 tablet_check_notify_axes(struct tablet_dispatch *tablet,
 			 struct evdev_device *device,
@@ -274,6 +316,8 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 	bool axis_update_needed = false;
 	int a;
 	double axes[LIBINPUT_TABLET_AXIS_MAX + 1] = {0};
+	double deltas[LIBINPUT_TABLET_AXIS_MAX + 1] = {0};
+	double oldval;
 
 	for (a = LIBINPUT_TABLET_AXIS_X; a <= LIBINPUT_TABLET_AXIS_MAX; a++) {
 		const struct input_absinfo *absinfo;
@@ -284,6 +328,7 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 		}
 
 		axis_update_needed = true;
+		oldval = tablet->axes[a];
 
 		/* ROTATION_Z is higher than TILT_X/Y so we know that the
 		   tilt axes are already normalized and set */
@@ -294,11 +339,12 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 			axes[LIBINPUT_TABLET_AXIS_TILT_X] = 0;
 			axes[LIBINPUT_TABLET_AXIS_TILT_Y] = 0;
 			axes[a] = tablet->axes[a];
+			deltas[a] = get_delta(a, tablet->axes[a], oldval);
 			continue;
 		} else if (a == LIBINPUT_TABLET_AXIS_REL_WHEEL) {
-			tablet->axes[a] = normalize_wheel(tablet,
-							  tablet->deltas[a]);
-			axes[a] = tablet->axes[a];
+			deltas[a] = normalize_wheel(tablet,
+						    tablet->deltas[a]);
+			axes[a] = 0;
 			continue;
 		}
 
@@ -333,6 +379,7 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 		}
 
 		axes[a] = tablet->axes[a];
+		deltas[a] = get_delta(a, tablet->axes[a], oldval);
 	}
 
 	/* We need to make sure that we check that the tool is not out of
@@ -355,7 +402,8 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
 					   time,
 					   tool,
 					   tablet->changed_axes,
-					   axes);
+					   axes,
+					   deltas);
 	}
 
 	memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 071204e..3a4e4a5 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -349,7 +349,8 @@ tablet_notify_axis(struct libinput_device *device,
 		   uint32_t time,
 		   struct libinput_tool *tool,
 		   unsigned char *changed_axes,
-		   double *axes);
+		   double *axes,
+		   double *deltas);
 
 void
 tablet_notify_proximity(struct libinput_device *device,
diff --git a/src/libinput.c b/src/libinput.c
index 2640321..7127182 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -86,6 +86,7 @@ struct libinput_event_tablet {
 	uint32_t seat_button_count;
 	uint32_t time;
 	double axes[LIBINPUT_TABLET_AXIS_MAX + 1];
+	double deltas[LIBINPUT_TABLET_AXIS_MAX + 1];
 	unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
 	struct libinput_tool *tool;
 	enum libinput_tool_proximity_state proximity_state;
@@ -594,6 +595,37 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event,
 }
 
 LIBINPUT_EXPORT double
+libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event,
+				     enum libinput_tablet_axis axis)
+{
+	struct evdev_device *device =
+		(struct evdev_device *) event->base.device;
+
+	if (event->base.type != LIBINPUT_EVENT_TABLET_AXIS &&
+	    event->base.type != LIBINPUT_EVENT_TABLET_PROXIMITY)
+		return 0;
+
+	switch(axis) {
+		case LIBINPUT_TABLET_AXIS_X:
+			return evdev_convert_to_mm(device->abs.absinfo_x,
+						   event->deltas[axis]);
+		case LIBINPUT_TABLET_AXIS_Y:
+			return evdev_convert_to_mm(device->abs.absinfo_y,
+						   event->deltas[axis]);
+		case LIBINPUT_TABLET_AXIS_DISTANCE:
+		case LIBINPUT_TABLET_AXIS_PRESSURE:
+		case LIBINPUT_TABLET_AXIS_TILT_X:
+		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->deltas[axis];
+		default:
+			return 0;
+	}
+}
+
+LIBINPUT_EXPORT double
 libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event,
 					uint32_t width)
 {
@@ -1400,7 +1432,8 @@ tablet_notify_axis(struct libinput_device *device,
 		   uint32_t time,
 		   struct libinput_tool *tool,
 		   unsigned char *changed_axes,
-		   double *axes)
+		   double *axes,
+		   double *deltas)
 {
 	struct libinput_event_tablet *axis_event;
 
@@ -1417,6 +1450,7 @@ tablet_notify_axis(struct libinput_device *device,
 	       changed_axes,
 	       sizeof(axis_event->changed_axes));
 	memcpy(axis_event->axes, axes, sizeof(axis_event->axes));
+	memcpy(axis_event->deltas, deltas, sizeof(axis_event->deltas));
 
 	post_device_event(device,
 			  time,
@@ -1450,6 +1484,8 @@ tablet_notify_proximity(struct libinput_device *device,
 	       changed_axes,
 	       sizeof(proximity_event->changed_axes));
 
+	/* deltas are always 0 on prox-in/out */
+
 	post_device_event(device,
 			  time,
 			  LIBINPUT_EVENT_TABLET_PROXIMITY,
diff --git a/src/libinput.h b/src/libinput.h
index 5737873..1c8a0a4 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -1062,8 +1062,8 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event,
  * - @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.
+ *   similar or equivalent to a mouse wheel. The value is always 0, use
+ *   libinput_event_tablet_get_axis_delta() instead.
  *
  * @note This function may be called for a specific axis even if
  * libinput_event_tablet_axis_has_changed() returns 0 for that axis.
@@ -1080,6 +1080,29 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event,
 /**
  * @ingroup event_tablet
  *
+ * Return the delta for a given axis for a tablet. The interpretation of the
+ * value is axis-dependent:
+ * - @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.
+ * For all other axes, see libinput_event_tablet_get_axis_value() for
+ * details.
+ *
+ * @note The delta is *not* the delta to the previous event, but the delta
+ * to the previous axis state, i.e. the delta to the last event that
+ * libinput_event_tablet_axis_has_changed() returned true for this axis.
+ *
+ * @param event The libinput tablet event
+ * @param axis The axis to retrieve the value of
+ * @return The delta to the previous axis value
+ */
+double
+libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event,
+				     enum libinput_tablet_axis axis);
+
+/**
+ * @ingroup event_tablet
+ *
  * Return the current absolute x coordinate of the tablet event, transformed to
  * screen coordinates.
  *
diff --git a/src/libinput.sym b/src/libinput.sym
index e674226..cb94d60 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -146,6 +146,7 @@ LIBINPUT_0.12.0 {
 LIBINPUT_TABLET_SUPPORT {
 	libinput_event_get_tablet_event;
 	libinput_event_tablet_axis_has_changed;
+	libinput_event_tablet_get_axis_delta;
 	libinput_event_tablet_get_axis_value;
 	libinput_event_tablet_get_button;
 	libinput_event_tablet_get_button_state;
diff --git a/test/tablet.c b/test/tablet.c
index afc654e..1eb91c6 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -381,6 +381,67 @@ START_TEST(motion)
 }
 END_TEST
 
+START_TEST(motion_delta)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event_tablet *tablet_event;
+	struct libinput_event *event;
+	double x1, y1, x2, y2, dist1, dist2;
+	double delta;
+	struct axis_replacement axes[] = {
+		{ ABS_DISTANCE, 10 },
+		{ -1, -1 }
+	};
+
+	litest_drain_events(li);
+
+	litest_tablet_proximity_in(dev, 5, 100, axes);
+	libinput_dispatch(li);
+
+	litest_wait_for_event_of_type(li,
+				      LIBINPUT_EVENT_TABLET_PROXIMITY,
+				      -1);
+
+	event = libinput_get_event(li);
+	tablet_event = libinput_event_get_tablet_event(event);
+	x1 = libinput_event_tablet_get_axis_value(tablet_event,
+						  LIBINPUT_TABLET_AXIS_X);
+	y1 = libinput_event_tablet_get_axis_value(tablet_event,
+						  LIBINPUT_TABLET_AXIS_Y);
+	dist1 = libinput_event_tablet_get_axis_value(tablet_event,
+					  LIBINPUT_TABLET_AXIS_DISTANCE);
+	libinput_event_destroy(event);
+
+	axes[0].value = 40;
+	litest_tablet_motion(dev, 40, 100, axes);
+
+	litest_wait_for_event_of_type(li,
+				      LIBINPUT_EVENT_TABLET_AXIS,
+				      -1);
+	event = libinput_get_event(li);
+	tablet_event = libinput_event_get_tablet_event(event);
+	x2 = libinput_event_tablet_get_axis_value(tablet_event,
+						  LIBINPUT_TABLET_AXIS_X);
+	y2 = libinput_event_tablet_get_axis_value(tablet_event,
+						  LIBINPUT_TABLET_AXIS_Y);
+	dist2 = libinput_event_tablet_get_axis_value(tablet_event,
+					  LIBINPUT_TABLET_AXIS_DISTANCE);
+
+	delta = libinput_event_tablet_get_axis_delta(tablet_event,
+						  LIBINPUT_TABLET_AXIS_X);
+	litest_assert_double_eq(delta, x2 - x1);
+	delta = libinput_event_tablet_get_axis_delta(tablet_event,
+						  LIBINPUT_TABLET_AXIS_Y);
+	litest_assert_double_eq(delta, y2 - y1);
+	delta = libinput_event_tablet_get_axis_delta(tablet_event,
+						  LIBINPUT_TABLET_AXIS_DISTANCE);
+	litest_assert_double_eq(delta, dist2 - dist1);
+
+	libinput_event_destroy(event);
+}
+END_TEST
+
 START_TEST(left_handed)
 {
 #if HAVE_LIBWACOM
@@ -1415,20 +1476,19 @@ START_TEST(artpen_rotation)
 
 	abs = libevdev_get_abs_info(dev->evdev, ABS_Z);
 	ck_assert_notnull(abs);
-
-	litest_event(dev, EV_KEY, BTN_TOOL_BRUSH, 1);
-	litest_event(dev, EV_ABS, ABS_MISC, 0x804); /* Art Pen */
-	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_Z, 10);
-	litest_event(dev, EV_SYN, SYN_REPORT, 0);
-
-	litest_drain_events(li);
-
 	scale = (abs->maximum - abs->minimum + 1)/360.0;
-	for (angle = 0; angle < 360; angle += 8) {
+
+	litest_event(dev, EV_KEY, BTN_TOOL_BRUSH, 1);
+	litest_event(dev, EV_ABS, ABS_MISC, 0x804); /* Art Pen */
+	litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	litest_event(dev, EV_ABS, ABS_Z, abs->minimum);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	litest_drain_events(li);
+
+	for (angle = 8; angle < 360; angle += 8) {
 		int a = angle * scale + abs->minimum;
 
 		litest_event(dev, EV_ABS, ABS_Z, a);
@@ -1446,8 +1506,14 @@ START_TEST(artpen_rotation)
 
 		/* artpen has a 90 deg offset cw */
 		ck_assert_int_eq(round(val), (angle + 90) % 360);
+
+		val = libinput_event_tablet_get_axis_delta(tev,
+					 LIBINPUT_TABLET_AXIS_ROTATION_Z);
+		ck_assert_int_eq(val, 8);
+
 		libinput_event_destroy(event);
 		litest_assert_empty_queue(li);
+
 	}
 }
 END_TEST
@@ -1467,6 +1533,7 @@ main(int argc, char **argv)
 	litest_add("tablet:proximity", proximity_has_axes, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:proximity", bad_distance_events, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
 	litest_add("tablet:motion", motion, LITEST_TABLET, LITEST_ANY);
+	litest_add("tablet:motion", motion_delta, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:motion", motion_event_state, LITEST_TABLET, LITEST_ANY);
 	litest_add_for_device("tablet:left_handed", left_handed, LITEST_WACOM_INTUOS);
 	litest_add_for_device("tablet:left_handed", no_left_handed, LITEST_WACOM_CINTIQ);
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 09edac0..7b68d96 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -291,15 +291,19 @@ static void
 print_tablet_axes(struct libinput_event_tablet *t)
 {
 	struct libinput_tool *tool = libinput_event_tablet_get_tool(t);
-	double x, y;
+	double x, y, dx, dy;
 	double dist, pressure;
 	double rotation, slider, wheel;
+	double delta;
 
 	x = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_X);
 	y = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_Y);
-	printf("\t%.2f%s/%.2f%s",
+	dx = libinput_event_tablet_get_axis_delta(t, LIBINPUT_TABLET_AXIS_X);
+	dy = libinput_event_tablet_get_axis_delta(t, LIBINPUT_TABLET_AXIS_Y);
+	printf("\t%.2f%s/%.2f%s (%.2f/%.2f)",
 	       x, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_X),
-	       y, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_Y));
+	       y, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_Y),
+	       dx, dy);
 
 	if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_TILT_X) ||
 	    libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_TILT_Y)) {
@@ -307,11 +311,16 @@ print_tablet_axes(struct libinput_event_tablet *t)
 					 LIBINPUT_TABLET_AXIS_TILT_X);
 		y = libinput_event_tablet_get_axis_value(t,
 					 LIBINPUT_TABLET_AXIS_TILT_Y);
-		printf("\ttilt: %.2f%s/%.2f%s ",
+		dx = libinput_event_tablet_get_axis_delta(t,
+					 LIBINPUT_TABLET_AXIS_TILT_X);
+		dy = libinput_event_tablet_get_axis_delta(t,
+					 LIBINPUT_TABLET_AXIS_TILT_Y);
+		printf("\ttilt: %.2f%s/%.2f%s (%.2f/%.2f)",
 		       x, tablet_axis_changed_sym(t,
 					  LIBINPUT_TABLET_AXIS_TILT_X),
 		       y, tablet_axis_changed_sym(t,
-					  LIBINPUT_TABLET_AXIS_TILT_Y));
+					  LIBINPUT_TABLET_AXIS_TILT_Y),
+		       dx, dy);
 	}
 
 	if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_DISTANCE) ||
@@ -321,43 +330,58 @@ print_tablet_axes(struct libinput_event_tablet *t)
 		pressure = libinput_event_tablet_get_axis_value(t,
 					LIBINPUT_TABLET_AXIS_PRESSURE);
 		if (dist) {
-			printf("\tdistance: %.2f%s",
+			delta = libinput_event_tablet_get_axis_delta(t,
+					LIBINPUT_TABLET_AXIS_DISTANCE);
+			printf("\tdistance: %.2f%s (%.2f)",
 			       dist,
 			       tablet_axis_changed_sym(t,
-					       LIBINPUT_TABLET_AXIS_DISTANCE));
+					       LIBINPUT_TABLET_AXIS_DISTANCE),
+			       delta);
 		} else {
-			printf("\tpressure: %.2f%s",
+			delta = libinput_event_tablet_get_axis_delta(t,
+					LIBINPUT_TABLET_AXIS_PRESSURE);
+			printf("\tpressure: %.2f%s (%.2f)",
 			       pressure,
 			       tablet_axis_changed_sym(t,
-					       LIBINPUT_TABLET_AXIS_PRESSURE));
+					       LIBINPUT_TABLET_AXIS_PRESSURE),
+			       delta);
 		}
 	}
 
 	if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_ROTATION_Z)) {
 		rotation = libinput_event_tablet_get_axis_value(t,
 					LIBINPUT_TABLET_AXIS_ROTATION_Z);
-		printf("\trotation: %.2f%s",
+		delta = libinput_event_tablet_get_axis_delta(t,
+					LIBINPUT_TABLET_AXIS_ROTATION_Z);
+		printf("\trotation: %.2f%s (%.2f)",
 		       rotation,
 		       tablet_axis_changed_sym(t,
-				       LIBINPUT_TABLET_AXIS_ROTATION_Z));
+				       LIBINPUT_TABLET_AXIS_ROTATION_Z),
+		       delta);
 	}
 
 	if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_SLIDER)) {
 		slider = libinput_event_tablet_get_axis_value(t,
 					LIBINPUT_TABLET_AXIS_SLIDER);
-		printf("\tslider: %.2f%s",
+		delta = libinput_event_tablet_get_axis_delta(t,
+					LIBINPUT_TABLET_AXIS_SLIDER);
+		printf("\tslider: %.2f%s (%.2f)",
 		       slider,
 		       tablet_axis_changed_sym(t,
-				       LIBINPUT_TABLET_AXIS_SLIDER));
+				       LIBINPUT_TABLET_AXIS_SLIDER),
+		       delta);
 	}
 
 	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",
+		delta = libinput_event_tablet_get_axis_delta(t,
+					LIBINPUT_TABLET_AXIS_REL_WHEEL);
+		printf("\twheel: %.2f%s (%.2f)",
 		       wheel,
 		       tablet_axis_changed_sym(t,
-				       LIBINPUT_TABLET_AXIS_REL_WHEEL));
+				       LIBINPUT_TABLET_AXIS_REL_WHEEL),
+		       delta);
 	}
 }
 
-- 
2.1.0



More information about the wayland-devel mailing list