[PATCH libinput] test: add tablet test for out-of-bounds motion coordinates

Peter Hutterer peter.hutterer at who-t.net
Thu Feb 11 07:31:17 UTC 2016


The newer Cintiqs have a minimum value of 400/400 advertised by the kernel but
the actual sensor goes past the 0/0 origin. Test this, make sure that a value
outside the boundaries generates negative mm values.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Mostly just documenting this and adding a test. The behaviour is that any
out-of-bounds motion may provide negative coordinates, when transformed may
provide something outside the [0, max-range].

Now, this is documenting the API behaviour. For the Cintiq I think it might
be better to put a device-specific quirk in to simply supress those events
since we don't have anything outside of these boundaries. Jason, Carlos, any
comments?

 doc/svg/tablet-out-of-bounds.svg | 271 +++++++++++++++++++++++++++++++++++++++
 doc/tablet-support.dox           |  22 ++++
 src/libinput.h                   |  12 ++
 test/tablet.c                    |  58 +++++++++
 4 files changed, 363 insertions(+)
 create mode 100644 doc/svg/tablet-out-of-bounds.svg

diff --git a/doc/svg/tablet-out-of-bounds.svg b/doc/svg/tablet-out-of-bounds.svg
new file mode 100644
index 0000000..83e5021
--- /dev/null
+++ b/doc/svg/tablet-out-of-bounds.svg
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="134.12477mm"
+   height="73.121971mm"
+   viewBox="0 0 475.24525 259.0936"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="tablet-out-of-bounds.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6"
+     inkscape:cx="105.43109"
+     inkscape:cy="265.46934"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0">
+    <sodipodi:guide
+       position="63.6133,240.91614"
+       orientation="0,1"
+       id="guide4164" />
+    <sodipodi:guide
+       position="61.08792,13.126743"
+       orientation="0,1"
+       id="guide4166" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="tablet"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline"
+     transform="translate(-139.42736,-156.36219)">
+    <rect
+       style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.9201867;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.68074643, 0.92018661;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4136"
+       width="474.32504"
+       height="258.1734"
+       x="139.88745"
+       y="156.82228"
+       rx="5" />
+    <rect
+       y="175.42407"
+       x="199.33878"
+       height="226.52563"
+       width="357.34042"
+       id="rect4140"
+       style="opacity:0.92000002;fill:#a44d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.74800003;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <g
+       id="g7041"
+       transform="translate(12,0)">
+      <g
+         transform="matrix(0.53265351,0,0,0.53265351,92.308091,96.440418)"
+         id="g7023">
+        <circle
+           style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.98900002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1"
+           id="path4158"
+           cx="135.61298"
+           cy="287.06125"
+           r="22.98097" />
+        <ellipse
+           cy="287.06125"
+           cx="135.61298"
+           id="circle4160"
+           style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.52043104;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:2.08172421, 0.52043105;stroke-dashoffset:0;stroke-opacity:1"
+           rx="11.5985"
+           ry="12.608653" />
+      </g>
+      <rect
+         rx="0.5"
+         y="268.93671"
+         x="163.8243"
+         height="8.9902887"
+         width="13.786156"
+         id="rect4162"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.29022256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.16089031, 0.29022258;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         rx="0.5"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.29022256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.16089031, 0.29022258;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7027"
+         width="13.786156"
+         height="8.9902887"
+         x="163.8243"
+         y="280.97675" />
+      <rect
+         rx="0.5"
+         y="293.01678"
+         x="163.8243"
+         height="8.9902887"
+         width="13.786156"
+         id="rect7029"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.29022256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.16089031, 0.29022258;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         rx="0.5"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.44849709;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.79398834, 0.44849708;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7031"
+         width="9.1119308"
+         height="32.483532"
+         x="149.90343"
+         y="269.44443" />
+      <rect
+         rx="0.5"
+         y="269.44443"
+         x="137.90343"
+         height="32.483532"
+         width="9.1119308"
+         id="rect7033"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.44849709;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.79398834, 0.44849708;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         rx="0.5"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.19463234;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.77852936, 0.19463234;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7035"
+         width="9.3657951"
+         height="5.9516821"
+         x="137.77649"
+         y="256.10321" />
+      <rect
+         rx="0.5"
+         y="246.10321"
+         x="137.77649"
+         height="5.9516821"
+         width="9.3657951"
+         id="rect7037"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.19463234;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.77852936, 0.19463234;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         rx="0.5"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.19463234;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.77852936, 0.19463234;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7039"
+         width="9.3657951"
+         height="5.9516821"
+         x="137.77649"
+         y="236.10321" />
+    </g>
+    <g
+       transform="matrix(-1,0,0,1,743.43474,0)"
+       id="g7054">
+      <g
+         id="g7056"
+         transform="matrix(0.53265351,0,0,0.53265351,92.308091,96.440418)">
+        <circle
+           r="22.98097"
+           cy="287.06125"
+           cx="135.61298"
+           id="circle7058"
+           style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.98900002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1" />
+        <ellipse
+           ry="12.608653"
+           rx="11.5985"
+           style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.52043104;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:2.08172421, 0.52043105;stroke-dashoffset:0;stroke-opacity:1"
+           id="ellipse7060"
+           cx="135.61298"
+           cy="287.06125" />
+      </g>
+      <rect
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.29022256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.16089031, 0.29022258;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7062"
+         width="13.786156"
+         height="8.9902887"
+         x="163.8243"
+         y="268.93671"
+         rx="0.5" />
+      <rect
+         y="280.97675"
+         x="163.8243"
+         height="8.9902887"
+         width="13.786156"
+         id="rect7064"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.29022256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.16089031, 0.29022258;stroke-dashoffset:0;stroke-opacity:1"
+         rx="0.5" />
+      <rect
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.29022256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.16089031, 0.29022258;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7066"
+         width="13.786156"
+         height="8.9902887"
+         x="163.8243"
+         y="293.01678"
+         rx="0.5" />
+      <rect
+         y="269.44443"
+         x="149.90343"
+         height="32.483532"
+         width="9.1119308"
+         id="rect7068"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.44849709;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.79398834, 0.44849708;stroke-dashoffset:0;stroke-opacity:1"
+         rx="0.5" />
+      <rect
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.44849709;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.79398834, 0.44849708;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7070"
+         width="9.1119308"
+         height="32.483532"
+         x="137.90343"
+         y="269.44443"
+         rx="0.5" />
+      <rect
+         y="256.10321"
+         x="137.77649"
+         height="5.9516821"
+         width="9.3657951"
+         id="rect7072"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.19463234;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.77852936, 0.19463234;stroke-dashoffset:0;stroke-opacity:1"
+         rx="0.5" />
+      <rect
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.19463234;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.77852936, 0.19463234;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect7074"
+         width="9.3657951"
+         height="5.9516821"
+         x="137.77649"
+         y="246.10321"
+         rx="0.5" />
+      <rect
+         y="236.10321"
+         x="137.77649"
+         height="5.9516821"
+         width="9.3657951"
+         id="rect7076"
+         style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.19463234;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.77852936, 0.19463234;stroke-dashoffset:0;stroke-opacity:1"
+         rx="0.5" />
+    </g>
+    <rect
+       style="opacity:0.92000002;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.6687212;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:2.6748846, 0.66872115;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect7078"
+       width="326.1051"
+       height="198.32079"
+       x="214.95644"
+       y="189.5265" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="stylus"
+     style="display:inline"
+     transform="translate(-139.42736,-156.36219)" />
+</svg>
diff --git a/doc/tablet-support.dox b/doc/tablet-support.dox
index ff4e460..0e719b7 100644
--- a/doc/tablet-support.dox
+++ b/doc/tablet-support.dox
@@ -186,4 +186,26 @@ Intuos 3, 4, 5, Wacon Cintiq and Wacom Intuos Pro series. The tool ID can
 be used to distinguish between e.g. a Wacom Classic Pen or a Wacom Pro Pen.
 It is  the caller's responsibility to interpret the tool ID.
 
+ at section tablet-bounds Out-of-bounds motion events
+
+Some tablets integrated into a screen (e.g. Wacom Cintiq 24HD, 27QHD and
+13HD series, etc.) have a sensor larger than the display area. libinput uses
+the range advertised by the kernel as the valid range unless device-specific
+quirks are present. Events outside this range will produce coordinates that
+may be negative or larger than the tablet's width and/or height. It is up to
+the caller to ignore these events.
+
+ at image html tablet-out-of-bounds.svg "Illustration of the out-of-bounds area on a tablet"
+
+In the image above, the display area is shown in black. The red area around
+the display illustrates the sensor area that generates input events. Events
+within this area will have negative coordinate or coordinates larger than
+the width/height of the tablet.
+
+If events outside the logical bounds of the input area are scaled into a
+custom range with libinput_event_tablet_tool_get_x_transformed() and
+libinput_event_tablet_tool_get_y_transformed() the resulting value may be
+less than 0 or larger than the upper range provided. It is up to the caller
+to test for this and handle or ignore these events accordingly.
+
 */
diff --git a/src/libinput.h b/src/libinput.h
index b14c281..cf33492 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -1562,6 +1562,9 @@ libinput_event_tablet_tool_wheel_has_changed(
  * libinput_event_tablet_tool_get_x_transformed() for transforming the axis
  * value into a different coordinate space.
  *
+ * @note On some devices, returned value may be negative or larger than the
+ * width of the device. See @ref tablet-bounds for more details.
+ *
  * @param event The libinput tablet tool event
  * @return The current value of the the axis
  */
@@ -1576,6 +1579,9 @@ libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event);
  * libinput_event_tablet_tool_get_y_transformed() for transforming the axis
  * value into a different coordinate space.
  *
+ * @note On some devices, returned value may be negative or larger than the
+ * width of the device. See @ref tablet-bounds for more details.
+ *
  * @param event The libinput tablet tool event
  * @return The current value of the the axis
  */
@@ -1754,6 +1760,9 @@ libinput_event_tablet_tool_get_wheel_delta_discrete(
  * libinput_event_tablet_tool_*_has_changed() returns 0 for that axis.
  * libinput always includes all device axes in the event.
  *
+ * @note On some devices, returned value may be negative or larger than the
+ * width of the device. See @ref tablet-bounds for more details.
+ *
  * @param event The libinput tablet tool event
  * @param width The current output screen width
  * @return the current absolute x coordinate transformed to a screen coordinate
@@ -1772,6 +1781,9 @@ libinput_event_tablet_tool_get_x_transformed(struct libinput_event_tablet_tool *
  * libinput_event_tablet_tool_*_has_changed() returns 0 for that axis.
  * libinput always includes all device axes in the event.
  *
+ * @note On some devices, returned value may be negative or larger than the
+ * width of the device. See @ref tablet-bounds for more details.
+ *
  * @param event The libinput tablet tool event
  * @param height The current output screen height
  * @return the current absolute y coordinate transformed to a screen coordinate
diff --git a/test/tablet.c b/test/tablet.c
index 6909f95..c5dc892 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -1655,6 +1655,63 @@ START_TEST(motion_event_state)
 }
 END_TEST
 
+START_TEST(motion_outside_bounds)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libinput_event *event;
+	struct libinput_event_tablet_tool *tablet_event;
+	double val;
+
+	struct axis_replacement axes[] = {
+		{ ABS_DISTANCE, 10 },
+		{ ABS_PRESSURE, 0 },
+		{ -1, -1 }
+	};
+
+	litest_tablet_proximity_in(dev, 50, 50, axes);
+	litest_drain_events(li);
+
+	/* On the 24HD x/y of 0 is outside the limit */
+	litest_event(dev, EV_ABS, ABS_X, 0);
+	litest_event(dev, EV_ABS, ABS_Y, 1000);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+	libinput_dispatch(li);
+
+	event = libinput_get_event(li);
+	tablet_event = litest_is_tablet_event(event,
+					      LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+	val = libinput_event_tablet_tool_get_x(tablet_event);
+	ck_assert_double_lt(val, 0.0);
+	val = libinput_event_tablet_tool_get_y(tablet_event);
+	ck_assert_double_gt(val, 0.0);
+
+	val = libinput_event_tablet_tool_get_x_transformed(tablet_event, 100);
+	ck_assert_double_lt(val, 0.0);
+
+	libinput_event_destroy(event);
+
+	/* On the 24HD x/y of 0 is outside the limit */
+	litest_event(dev, EV_ABS, ABS_X, 1000);
+	litest_event(dev, EV_ABS, ABS_Y, 0);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+	libinput_dispatch(li);
+
+	event = libinput_get_event(li);
+	tablet_event = litest_is_tablet_event(event,
+					      LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+	val = libinput_event_tablet_tool_get_x(tablet_event);
+	ck_assert_double_gt(val, 0.0);
+	val = libinput_event_tablet_tool_get_y(tablet_event);
+	ck_assert_double_lt(val, 0.0);
+
+	val = libinput_event_tablet_tool_get_y_transformed(tablet_event, 100);
+	ck_assert_double_lt(val, 0.0);
+
+	libinput_event_destroy(event);
+}
+END_TEST
+
 START_TEST(bad_distance_events)
 {
 	struct litest_device *dev = litest_current_device();
@@ -3577,6 +3634,7 @@ litest_setup_tests(void)
 	litest_add("tablet:tip", tip_state_button, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:motion", motion, LITEST_TABLET, LITEST_ANY);
 	litest_add("tablet:motion", motion_event_state, LITEST_TABLET, LITEST_ANY);
+	litest_add_for_device("tablet:motion", motion_outside_bounds, LITEST_WACOM_CINTIQ_24HD);
 	litest_add("tablet:tilt", tilt_available, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
 	litest_add("tablet:tilt", tilt_not_available, LITEST_TABLET, LITEST_TILT);
 	litest_add("tablet:tilt", tilt_x, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
-- 
2.5.0



More information about the wayland-devel mailing list