Merge branch 'tablet-support'

This commit is contained in:
Peter Hutterer 2016-01-27 16:02:47 +10:00
commit 4b4172a8e6
40 changed files with 10054 additions and 82 deletions

View file

@ -189,6 +189,16 @@ if test "x$build_tests" = "xyes"; then
AC_PATH_PROG(VALGRIND, [valgrind])
fi
AC_ARG_ENABLE(libwacom,
AS_HELP_STRING([--enable-libwacom],
[Use libwacom for tablet identification (default=enabled)]),
[use_libwacom="$enableval"],
[use_libwacom="yes"])
if test "x$use_libwacom" = "xyes"; then
PKG_CHECK_MODULES(LIBWACOM, [libwacom >= 0.12], [HAVE_LIBWACOM="yes"])
AC_DEFINE(HAVE_LIBWACOM, 1, [Build with libwacom])
fi
AM_CONDITIONAL(HAVE_VALGRIND, [test "x$VALGRIND" != "x"])
AM_CONDITIONAL(BUILD_TESTS, [test "x$build_tests" = "xyes"])
AM_CONDITIONAL(BUILD_DOCS, [test "x$build_documentation" = "xyes"])
@ -218,6 +228,7 @@ AC_MSG_RESULT([
Prefix ${prefix}
udev base dir ${UDEV_DIR}
libwacom enabled ${use_libwacom}
Build documentation ${build_documentation}
Build tests ${build_tests}
Tests use valgrind ${VALGRIND}

View file

@ -23,6 +23,7 @@ header_files = \
$(srcdir)/scrolling.dox \
$(srcdir)/seats.dox \
$(srcdir)/t440-support.dox \
$(srcdir)/tablet-support.dox \
$(srcdir)/tapping.dox \
$(srcdir)/test-suite.dox \
$(srcdir)/tools.dox \

View file

@ -10,7 +10,7 @@ libinput supports three types of devices with absolute axes:
- multi-touch screens
- single-touch screens
- graphics tablets (currently WIP)
- @ref tablet-support "graphics tablets"
Touchpads are technically absolute devices but libinput converts the axis values
to directional motion and posts events as relative events. Touchpads do not count
@ -18,7 +18,10 @@ as absolute devices in libinput.
For all absolute devices in libinput, the default unit for x/y coordinates is
in mm off the top left corner on the device, or more specifically off the
device's sensor.
device's sensor. If the device is physically rotated from its natural
position and this rotation was communicated to libinput (e.g.
@ref libinput_device_config_left_handed_set "by setting the device left-handed"),
the coordinate origin is the top left corner of in the current rotation.
@section absolute_axes_handling Handling of absolute coordinates
@ -40,7 +43,7 @@ coordinate.
@section absolute_axes_nores Devices without x/y resolution
An absolute device that does not provide a valid resolution is considered
buggy and must be fixed in the kernel. Some touchpad devices that do not
buggy and must be fixed in the kernel. Some touchpad devices do not
provide resolution, those devices are correctly handled within libinput
(touchpads are not absolute devices, as mentioned above).
@ -107,11 +110,14 @@ The most common matrices are:
See Wikipedia's
<a href="http://en.wikipedia.org/wiki/Transformation_matrix">Transformation
Matrix article</a> for more information on the matrix maths.
See libinput_device_config_calibration_get_default_matrix() for how these
Matrix article</a> for more information on the matrix maths. See
libinput_device_config_calibration_get_default_matrix() for how these
matrices must be supplied to libinput.
Once applied, any x and y axis value has the calibration applied before it
is made available to the caller. libinput does not provide access to the
raw coordinates before the calibration is applied.
@section absolute_axes_nonorm Why x/y coordinates are not normalized
x/y are not given in @ref motion_normalization "normalized coordinates"

View file

@ -64,11 +64,11 @@ libinput_pointer_get_axis_source() for details.
<dd>A constant (linear) acceleration factor to apply to pointingstick deltas
to normalize them.
<dt>LIBINPUT_MODEL_*</dt>
<dd><b>This prefix is reserved as private API, do not use.</b>. See @ref
<dd><b>This prefix is reserved as private API, do not use.</b> See @ref
model_specific_configuration for details.
</dd>
<dt>LIBINPUT_ATTR_*</dt>
<dd><b>This prefix is reserved as private API, do not use.</b>. See @ref
<dd><b>This prefix is reserved as private API, do not use.</b> See @ref
model_specific_configuration for details.
</dd>
</dl>

View file

@ -38,6 +38,10 @@ libinput scales unaccelerated touchpad motion to the resolution of the
touchpad's x axis, i.e. the unaccelerated value for the y axis is:
y = (x / resolution_x) * resolution_y
@section motion_normalization_tablet Normalization of tablet coordinates
See @ref tablet-relative-motion
@section motion_normalization_customization Setting custom DPI settings
Devices usually do not advertise their resolution and libinput relies on

View file

@ -124,4 +124,10 @@ velocity of the pointer and each delta (dx, dy) results in an accelerated delta
(dx * factor, dy * factor). This provides 1:1 movement between the device
and the pointer on-screen.
@section ptraccel-tablet Pointer acceleration on tablets
Pointer acceleration for relative motion on tablet devices is a flat
acceleration, with the speed seeting slowing down or speeding up the pointer
motion by a constant factor. Tablets do not allow for switchable profiles.
*/

563
doc/svg/tablet-axes.svg Normal file
View file

@ -0,0 +1,563 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="161.49548mm"
height="76.025978mm"
viewBox="0 0 572.22809 269.38339"
id="svg4321"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="tablet-axes.svg">
<defs
id="defs4323">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4966"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7788"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path7790"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7664"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="StopL">
<path
transform="scale(0.8,0.8)"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,5.65 0,-5.65"
id="path7666"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="TriangleOutM"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5111"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="scale(0.4,0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="StopL"
orient="auto"
refY="0"
refX="0"
id="StopL"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path5135"
d="M 0,5.65 0,-5.65"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.8,0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="DotM"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5030"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,2.96,0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="SquareS"
orient="auto"
refY="0"
refX="0"
id="SquareS"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5042"
d="M -5,-5 -5,5 5,5 5,-5 -5,-5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.2,0.2)"
inkscape:connector-curvature="0" />
</marker>
<marker
style="overflow:visible"
id="DistanceEnd"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="DistanceEnd"
inkscape:isstock="true">
<g
id="g2301"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1">
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.14999998;stroke-linecap:square;stroke-opacity:1"
d="M 0,0 -2,0"
id="path2316"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-opacity:1"
d="M 0,0 -13,4 -9,0 -13,-4 0,0 Z"
id="path2312"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-opacity:1"
d="M 0,-4 0,40"
id="path2314"
inkscape:connector-curvature="0" />
</g>
</marker>
<marker
style="overflow:visible"
id="DistanceStart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="DistanceStart"
inkscape:isstock="true">
<g
id="g2300"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1">
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.14999998;stroke-linecap:square;stroke-opacity:1"
d="M 0,0 2,0"
id="path2306"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-opacity:1"
d="M 0,0 13,4 9,0 13,-4 0,0 Z"
id="path2302"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-opacity:1"
d="M 0,-4 0,40"
id="path2304"
inkscape:connector-curvature="0" />
</g>
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="Arrow2Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4999"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4987"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4969"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6024"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6,-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path6026"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5972"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6,-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5974"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5782"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6,-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5784"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5754"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
transform="scale(0.6,0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5756"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4993"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6,-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4990"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6,0.6)"
inkscape:connector-curvature="0" />
</marker>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4294"
id="linearGradient4300"
x1="465.81339"
y1="666.13727"
x2="454.82117"
y2="658.65521"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient4294">
<stop
style="stop-color:#1a1a1a;stop-opacity:1;"
offset="0"
id="stop4296" />
<stop
style="stop-color:#808080;stop-opacity:1"
offset="1"
id="stop4298" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4294"
id="linearGradient5721"
gradientUnits="userSpaceOnUse"
x1="465.81339"
y1="666.13727"
x2="454.82117"
y2="658.65521" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4294"
id="linearGradient7662"
gradientUnits="userSpaceOnUse"
x1="465.81339"
y1="666.13727"
x2="454.82117"
y2="658.65521" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="468.45173"
inkscape:cy="131.02294"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
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" />
<metadata
id="metadata4326">
<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="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-64.198799,-423.87021)">
<g
id="g5688">
<g
transform="matrix(0.35596319,-0.1450925,0.14027908,0.34415419,-92.870773,417.67084)"
id="g4304"
style="display:inline">
<path
style="display:inline;fill:#cccccc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 387.83544,799.76093 c -1.1128,3.61694 -3.2211,13.05163 -1.08543,14.07769 2.13567,1.02606 7.81039,-3.72162 10.99756,-6.69095 z"
id="path4286"
inkscape:connector-curvature="0"
sodipodi:nodetypes="czcc" />
<path
style="display:inline;fill:#000000"
d="m 392.64431,804.79039 c -8.52094,-5.90399 -8.49394,-11.01546 0.22879,-43.30647 1.03999,-3.85 2.46829,-9.67602 3.17399,-12.9467 0.99731,-4.62219 2.39455,-7.29497 6.27321,-12 2.74456,-3.32932 5.25157,-6.2783 5.57113,-6.5533 40.78433,-60.97488 80.48307,-125.1652 118.27253,-184 9.86283,-15.675 26.59424,-42.225 37.18089,-59 10.58666,-16.775 34.01422,-53.9 52.06125,-82.5 18.04703,-28.6 35.04505,-55.31677 37.77338,-59.37059 l 4.9606,-7.3706 4.1828,0.57332 c 4.16371,0.5707 4.19706,0.54958 7.30887,-4.62941 3.75631,-6.2516 8.82067,-11.57582 12.2516,-12.88026 5.99391,-2.27888 14.03303,2.9506 14.03303,9.12854 0,3.90203 -2.51704,10.62127 -6.02878,16.09385 -1.63417,2.54664 -2.97122,4.85949 -2.97122,5.13969 0,0.28019 0.9,1.54715 2,2.81546 2.28453,2.63408 2.47267,4.21918 0.86833,7.31574 -1.28218,2.47476 -26.61383,45.18798 -55.85724,94.18426 -10.83283,18.15 -25.72943,43.1137 -33.10357,55.47489 -7.37413,12.3612 -13.69273,23.17153 -14.04131,24.02297 -0.34859,0.85144 -7.50972,12.78774 -15.91363,26.52511 -15.54138,25.40455 -32.24417,52.9052 -70.74345,116.47703 -40.26028,66.47968 -43.66308,72.46026 -49.21634,86.5 -1.74036,4.4 -3.92035,8.675 -4.8444,9.5 -0.92405,0.825 -4.36246,3.75 -7.6409,6.5 -3.27845,2.75 -9.57132,8.3067 -13.98415,12.34823 -10.62726,9.73304 -16.99729,13.87361 -22.52334,14.64034 -3.99187,0.55386 -5.03885,0.251 -9.27207,-2.6821 z"
id="path4283"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssccssscsssssssssssssssssss" />
<path
style="fill:url(#linearGradient4300);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 450.89044,688.88586 c 8.71518,5.62513 45.74035,-59.18436 43.57923,-75.43494 l -7.07107,-6.56599 c -29.93081,25.86352 -47.78438,74.72281 -47.78438,74.72281 0,0 0,0 11.27622,7.27812 z"
id="path4292"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scccs" />
</g>
<rect
transform="scale(1,-1)"
y="-693.18524"
x="67.81031"
height="16.036251"
width="168.54825"
id="rect4136"
style="opacity:1;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.13670856;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:0.54683419, 0.13670855;stroke-dashoffset:0;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4960"
d="m 136.32111,642.81599 0,34.04419"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80699879px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend)" />
<text
sodipodi:linespacing="125%"
id="text5286"
y="665.58148"
x="62.726631"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="665.58148"
x="62.726631"
id="tspan5288"
sodipodi:role="line">Distance</tspan></text>
<path
inkscape:connector-curvature="0"
id="path5290"
d="m 136.42857,641.82649 58.75,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.40000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
transform="matrix(0.35596319,-0.1450925,0.14027908,0.34415419,107.12923,453.67084)"
id="g5701"
style="display:inline">
<path
style="display:inline;fill:#cccccc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 387.83544,799.76093 c -1.1128,3.61694 -3.2211,13.05163 -1.08543,14.07769 2.13567,1.02606 7.81039,-3.72162 10.99756,-6.69095 z"
id="path5703"
inkscape:connector-curvature="0"
sodipodi:nodetypes="czcc" />
<path
style="display:inline;fill:#000000"
d="m 392.64431,804.79039 c -8.52094,-5.90399 -8.49394,-11.01546 0.22879,-43.30647 1.03999,-3.85 2.46829,-9.67602 3.17399,-12.9467 0.99731,-4.62219 2.39455,-7.29497 6.27321,-12 2.74456,-3.32932 5.25157,-6.2783 5.57113,-6.5533 40.78433,-60.97488 80.48307,-125.1652 118.27253,-184 9.86283,-15.675 26.59424,-42.225 37.18089,-59 10.58666,-16.775 34.01422,-53.9 52.06125,-82.5 18.04703,-28.6 35.04505,-55.31677 37.77338,-59.37059 l 4.9606,-7.3706 4.1828,0.57332 c 4.16371,0.5707 4.19706,0.54958 7.30887,-4.62941 3.75631,-6.2516 8.82067,-11.57582 12.2516,-12.88026 5.99391,-2.27888 14.03303,2.9506 14.03303,9.12854 0,3.90203 -2.51704,10.62127 -6.02878,16.09385 -1.63417,2.54664 -2.97122,4.85949 -2.97122,5.13969 0,0.28019 0.9,1.54715 2,2.81546 2.28453,2.63408 2.47267,4.21918 0.86833,7.31574 -1.28218,2.47476 -26.61383,45.18798 -55.85724,94.18426 -10.83283,18.15 -25.72943,43.1137 -33.10357,55.47489 -7.37413,12.3612 -13.69273,23.17153 -14.04131,24.02297 -0.34859,0.85144 -7.50972,12.78774 -15.91363,26.52511 -15.54138,25.40455 -32.24417,52.9052 -70.74345,116.47703 -40.26028,66.47968 -43.66308,72.46026 -49.21634,86.5 -1.74036,4.4 -3.92035,8.675 -4.8444,9.5 -0.92405,0.825 -4.36246,3.75 -7.6409,6.5 -3.27845,2.75 -9.57132,8.3067 -13.98415,12.34823 -10.62726,9.73304 -16.99729,13.87361 -22.52334,14.64034 -3.99187,0.55386 -5.03885,0.251 -9.27207,-2.6821 z"
id="path5705"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssccssscsssssssssssssssssss" />
<path
style="fill:url(#linearGradient5721);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 450.89044,688.88586 c 8.71518,5.62513 45.74035,-59.18436 43.57923,-75.43494 l -7.07107,-6.56599 c -29.93081,25.86352 -47.78438,74.72281 -47.78438,74.72281 0,0 0,0 11.27622,7.27812 z"
id="path5707"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scccs" />
</g>
<rect
transform="scale(1,-1)"
y="-693.18524"
x="267.8103"
height="16.036251"
width="168.54825"
id="rect5709"
style="opacity:1;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.13670856;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:0.54683419, 0.13670855;stroke-dashoffset:0;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5711"
d="m 336.32111,642.81599 0,34.04419"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80699879px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#StopL);marker-end:url(#Arrow2Lend)" />
<text
sodipodi:linespacing="125%"
id="text5713"
y="665.58148"
x="262.72662"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="665.58148"
x="262.72662"
id="tspan5715"
sodipodi:role="line">Pressure</tspan></text>
<g
style="display:inline"
id="g7646"
transform="matrix(0.35596319,-0.1450925,0.14027908,0.34415419,307.12923,445.67084)">
<path
sodipodi:nodetypes="czcc"
inkscape:connector-curvature="0"
id="path7648"
d="m 387.83544,799.76093 c -1.1128,3.61694 -3.2211,13.05163 -1.08543,14.07769 2.13567,1.02606 7.81039,-3.72162 10.99756,-6.69095 z"
style="display:inline;fill:#cccccc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ssssccssscsssssssssssssssssss"
inkscape:connector-curvature="0"
id="path7650"
d="m 392.64431,804.79039 c -8.52094,-5.90399 -8.49394,-11.01546 0.22879,-43.30647 1.03999,-3.85 2.46829,-9.67602 3.17399,-12.9467 0.99731,-4.62219 2.39455,-7.29497 6.27321,-12 2.74456,-3.32932 5.25157,-6.2783 5.57113,-6.5533 40.78433,-60.97488 80.48307,-125.1652 118.27253,-184 9.86283,-15.675 26.59424,-42.225 37.18089,-59 10.58666,-16.775 34.01422,-53.9 52.06125,-82.5 18.04703,-28.6 35.04505,-55.31677 37.77338,-59.37059 l 4.9606,-7.3706 4.1828,0.57332 c 4.16371,0.5707 4.19706,0.54958 7.30887,-4.62941 3.75631,-6.2516 8.82067,-11.57582 12.2516,-12.88026 5.99391,-2.27888 14.03303,2.9506 14.03303,9.12854 0,3.90203 -2.51704,10.62127 -6.02878,16.09385 -1.63417,2.54664 -2.97122,4.85949 -2.97122,5.13969 0,0.28019 0.9,1.54715 2,2.81546 2.28453,2.63408 2.47267,4.21918 0.86833,7.31574 -1.28218,2.47476 -26.61383,45.18798 -55.85724,94.18426 -10.83283,18.15 -25.72943,43.1137 -33.10357,55.47489 -7.37413,12.3612 -13.69273,23.17153 -14.04131,24.02297 -0.34859,0.85144 -7.50972,12.78774 -15.91363,26.52511 -15.54138,25.40455 -32.24417,52.9052 -70.74345,116.47703 -40.26028,66.47968 -43.66308,72.46026 -49.21634,86.5 -1.74036,4.4 -3.92035,8.675 -4.8444,9.5 -0.92405,0.825 -4.36246,3.75 -7.6409,6.5 -3.27845,2.75 -9.57132,8.3067 -13.98415,12.34823 -10.62726,9.73304 -16.99729,13.87361 -22.52334,14.64034 -3.99187,0.55386 -5.03885,0.251 -9.27207,-2.6821 z"
style="display:inline;fill:#000000" />
<path
sodipodi:nodetypes="scccs"
inkscape:connector-curvature="0"
id="path7652"
d="m 450.89044,688.88586 c 8.71518,5.62513 45.74035,-59.18436 43.57923,-75.43494 l -7.07107,-6.56599 c -29.93081,25.86352 -47.78438,74.72281 -47.78438,74.72281 0,0 0,0 11.27622,7.27812 z"
style="fill:url(#linearGradient7662);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<rect
style="opacity:1;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.13670856;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:0.54683419, 0.13670855;stroke-dashoffset:0;stroke-opacity:1"
id="rect7654"
width="168.54825"
height="16.036251"
x="467.8103"
y="-693.18524"
transform="scale(1,-1)" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="567.2774"
y="435.26669"
id="text7658"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7660"
x="567.2774"
y="435.26669">Tilt</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#727272;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="m 559.28572,676.29078 0,-230.49149"
id="path7954"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#727272;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="M 557.43833,676.12153 600.28315,446.14441"
id="path7956"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5754);marker-end:url(#marker5972)"
d="m 600.17857,445.75506 -40.71428,0"
id="path7958"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

199
doc/svg/tablet.svg Normal file
View file

@ -0,0 +1,199 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="147.67236mm"
height="86.663628mm"
viewBox="0 0 523.24853 307.07585"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="tablet.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4294">
<stop
style="stop-color:#1a1a1a;stop-opacity:1;"
offset="0"
id="stop4296" />
<stop
style="stop-color:#808080;stop-opacity:1"
offset="1"
id="stop4298" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4294"
id="linearGradient4300"
x1="465.81339"
y1="666.13727"
x2="454.82117"
y2="658.65521"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="605.97861"
inkscape:cy="-35.324315"
inkscape:document-units="px"
inkscape:current-layer="layer3"
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="127.77903,266.16996"
orientation="0,1"
id="guide4164" />
<sodipodi:guide
position="125.25365,38.380555"
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(-75.261625,-133.63374)">
<g
id="g4309"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<rect
y="134.15933"
x="75.787216"
height="306.02466"
width="522.19733"
id="rect4136"
style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:1.05118144;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:4.20472551, 1.05118138;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="opacity:0.92000002;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.74813837;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:2.99255325, 0.74813831;stroke-dashoffset:0;stroke-opacity:1"
id="rect4140"
width="357.34042"
height="226.52563"
x="199.33878"
y="175.42407" />
<rect
y="175.72914"
x="103.10225"
height="22.142857"
width="65"
id="rect4142"
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" />
<rect
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="rect4148"
width="65"
height="22.142857"
x="103.10225"
y="203.72914" />
<rect
y="231.72913"
x="103.10225"
height="22.142857"
width="65"
id="rect4150"
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" />
<rect
y="323.72913"
x="103.10225"
height="22.142857"
width="65"
id="rect4154"
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" />
<rect
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="rect4156"
width="65"
height="22.142857"
x="103.10225"
y="351.72913" />
<circle
r="22.98097"
cy="287.06125"
cx="135.61298"
id="path4158"
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="circle4160"
cx="135.61298"
cy="287.06125" />
<rect
y="379.72913"
x="103.10225"
height="22.142857"
width="65"
id="rect4162"
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" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="stylus"
style="display:inline"
transform="translate(-75.261625,-133.63374)">
<g
id="g4304"
transform="matrix(0.37129971,0.09948946,-0.09618892,0.35898192,295.60339,7.6883643)">
<path
sodipodi:nodetypes="czcc"
inkscape:connector-curvature="0"
id="path4286"
d="m 387.83544,799.76093 c -1.1128,3.61694 -3.2211,13.05163 -1.08543,14.07769 2.13567,1.02606 7.81039,-3.72162 10.99756,-6.69095 z"
style="display:inline;fill:#cccccc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ssssccssscsssssssssssssssssss"
inkscape:connector-curvature="0"
id="path4283"
d="m 392.64431,804.79039 c -8.52094,-5.90399 -8.49394,-11.01546 0.22879,-43.30647 1.03999,-3.85 2.46829,-9.67602 3.17399,-12.9467 0.99731,-4.62219 2.39455,-7.29497 6.27321,-12 2.74456,-3.32932 5.25157,-6.2783 5.57113,-6.5533 40.78433,-60.97488 80.48307,-125.1652 118.27253,-184 9.86283,-15.675 26.59424,-42.225 37.18089,-59 10.58666,-16.775 34.01422,-53.9 52.06125,-82.5 18.04703,-28.6 35.04505,-55.31677 37.77338,-59.37059 l 4.9606,-7.3706 4.1828,0.57332 c 4.16371,0.5707 4.19706,0.54958 7.30887,-4.62941 3.75631,-6.2516 8.82067,-11.57582 12.2516,-12.88026 5.99391,-2.27888 14.03303,2.9506 14.03303,9.12854 0,3.90203 -2.51704,10.62127 -6.02878,16.09385 -1.63417,2.54664 -2.97122,4.85949 -2.97122,5.13969 0,0.28019 0.9,1.54715 2,2.81546 2.28453,2.63408 2.47267,4.21918 0.86833,7.31574 -1.28218,2.47476 -26.61383,45.18798 -55.85724,94.18426 -10.83283,18.15 -25.72943,43.1137 -33.10357,55.47489 -7.37413,12.3612 -13.69273,23.17153 -14.04131,24.02297 -0.34859,0.85144 -7.50972,12.78774 -15.91363,26.52511 -15.54138,25.40455 -32.24417,52.9052 -70.74345,116.47703 -40.26028,66.47968 -43.66308,72.46026 -49.21634,86.5 -1.74036,4.4 -3.92035,8.675 -4.8444,9.5 -0.92405,0.825 -4.36246,3.75 -7.6409,6.5 -3.27845,2.75 -9.57132,8.3067 -13.98415,12.34823 -10.62726,9.73304 -16.99729,13.87361 -22.52334,14.64034 -3.99187,0.55386 -5.03885,0.251 -9.27207,-2.6821 z"
style="display:inline;fill:#000000" />
<path
sodipodi:nodetypes="scccs"
inkscape:connector-curvature="0"
id="path4292"
d="m 450.89044,688.88586 c 8.71518,5.62513 45.74035,-59.18436 43.57923,-75.43494 l -7.07107,-6.56599 c -29.93081,25.86352 -47.78438,74.72281 -47.78438,74.72281 0,0 0,0 11.27622,7.27812 z"
style="fill:url(#linearGradient4300);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

185
doc/tablet-support.dox Normal file
View file

@ -0,0 +1,185 @@
/**
@page tablet-support Tablet support
This page provides details about the graphics tablet
support in libinput. Note that the term "tablet" in libinput refers to
graphics tablets only (e.g. Wacom Intuos), not to tablet devices like the
Apple iPad.
@image html tablet.svg "Illustration of a graphics tablet"
@section tablet-tools Tablet buttons vs. tablet tools
Most tablets provide two types of devices. The pysical tablet often provides
a number of buttons and a touch ring or strip. Interaction on the drawing
surface of the tablet requires a tool, usually in the shape of a stylus.
The libinput interface exposed by devices with the @ref
LIBINPUT_DEVICE_CAP_TABLET_TOOL applies only to events generated by tools.
Touch events on the tablet integrated into a screen itself are exposed
through the @ref LIBINPUT_DEVICE_CAP_TOUCH capability. Touch events on a
standalone tablet are exposed through the @ref LIBINPUT_DEVICE_CAP_POINTER
capability. In both cases, the kernel usually provides a separate event
node for the touch device, resulting in a separate libinput device.
See libinput_device_get_device_group() for information on how to associate
the touch part with other devices exposed by the same physical hardware.
@section tablet-tip Tool tip events vs. button events
The primary use of a tablet tool is to draw on the surface of the tablet.
When the tool tip comes into contact with the surface, libinput sends an
event of type @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, and again when the tip
ceases contact with the surface.
Tablet tools may send button events; these are exclusively for extra buttons
unrelated to the tip. A button event is independent of the tip and can while
the tip is down or up.
Some tablet tools' pressure detection is too sensitive, causing phantom
touches when the user only slightly brushes the surfaces. For example, some
tools are capable of detecting 1 gram of pressure.
libinput uses a device-specific pressure threshold to determine when the tip
is considered logically down. As a result, libinput may send a nonzero
pressure value while the tip is logically up. Most application can and
should ignore pressure information until they receive the event of type @ref
LIBINPUT_EVENT_TABLET_TOOL_TIP. Applications that require extremely
fine-grained pressure sensitivity should use the pressure data instead of
the tip events to determine a logical tip down state and treat the tip
events like axis events otherwise.
Note that the pressure threshold to trigger a logical tip event may be zero
on some devices. On tools without pressure sensitivity, determining when a
tip is down is device-specific.
@section tablet-relative-motion Relative motion for tablet tools
libinput calculates the relative motion vector for each event and converts
it to the same coordinate space that a normal mouse device would use. For
the caller, this means that the delta coordinates returned by
libinput_event_tablet_tool_get_dx() and
libinput_event_tablet_tool_get_dy() can be used identical to the delta
coordinates from any other pointer event. Any resolution differences between
the x and y axes are accommodated for, a delta of N/N represents a 45 degree
diagonal move on the tablet.
The delta coordinates are available for all tablet events, it is up to the
caller to decide when a tool should be used in relative mode. It is
recommended that mouse and lens cursor tool default to relative mode and
all pen-like tools to absolute mode.
If a tool in relative mode must not use pointer acceleration, callers
should use the absolute coordinates returned by
libinput_event_tablet_tool_get_x() and libinput_event_tablet_tool_get_y()
and calculate the delta themselves. Callers that require exact physical
distance should also use these functions to calculate delta movements.
@section tablet-axes Special axes on tablet tools
A tablet tool usually provides additional information beyond x/y positional
information and the tip state. A tool may provide the distance to the tablet
surface and the pressure exerted on the tip when in contact. Some tablets
additionally provide tilt information along the x and y axis.
@image html tablet-axes.svg "Illustration of the distance, pressure and tilt axes"
The granularity and precision of these axes varies between tablet devices
and cannot usually be mapped into a physical unit.
libinput normalizes distance and pressure into the [0, 1] range and the tilt
axes into the [-1, 1] range with 0 as the neutral point.
While the normalization range is identical for these axes, a caller should
not interpret identical values as identical across axes, i.e. a value v1 on
the distance axis has no relation to the same value v1 on the pressure axis.
@section tablet-fake-proximity Handling of proximity events
libinput's @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY events notify a caller
when a tool comes into sensor range or leaves the sensor range. On some
tools this range does not represent the physical range but a reduced
tool-specific logical range. If the range is reduced, this is done
transparent to the caller.
For example, the Wacom mouse and lens cursor tools are usually
used in relative mode, lying flat on the tablet. Movement typically follows
the interaction normal mouse movements have, i.e. slightly lift the tool and
place it in a separate location. The proximity detection on Wacom
tablets however extends further than the user may lift the mouse, i.e. the
tool may not be lifted out of physical proximity. For such tools, libinput
provides software-emulated proximity.
@section tablet-pressure-offset Pressure offset on worn-out tools
When a tool is used for an extended period it can wear down physically. A
worn-down tool may never return a zero pressure value. Even when hovering
above the surface, the pressure value returned by the tool is nonzero,
creating a fake surface touch and making interaction with the tablet less
predictable.
libinput automatically detects pressure offsets and rescales the remaining
pressure range into the available range, making pressure-offsets transparent
to the caller. A tool with a pressure offset will thus send a 0 pressure
value for the detected offset and nonzero pressure values for values higher
than that offset.
Some limitations apply to avoid misdetection of pressure offsets,
specifically:
- pressure offset is only detected on proximity in, and if a device is
capable of detection distances,
- pressure offset is only detected if the distance between the tool and the
tablet is high enough,
- pressure offset is only used if it is 20% or less of the pressure range
available to the tool. A pressure offset higher than 20% indicates either
a misdetection or a tool that should be replaced, and
- if a pressure value less than the current pressure offset is seen, the
offset resets to that value.
Pressure offsets are not detected on @ref LIBINPUT_TABLET_TOOL_TYPE_MOUSE
and @ref LIBINPUT_TABLET_TOOL_TYPE_LENS tools.
@section tablet-serial-numbers Tracking unique tools
Some tools provide hardware information that enables libinput to uniquely
identify the physical device. For example, tools compatible with the Wacom
Intuos 4, Intuos 5, Intuos Pro and Cintiq series are uniquely identifiable
through a serial number. libinput does not specify how a tool can be
identified uniquely, a caller should use libinput_tablet_tool_is_unique() to
check if the tool is unique.
libinput creates a struct libinput_tablet_tool on the first proximity in of
this tool. By default, this struct is destroyed on proximity out and
re-initialized on the next proximity in. If a caller keeps a reference to
the tool by using libinput_tablet_tool_ref() libinput re-uses this struct
whenever that same physical tool comes into proximity on any tablet
recognized by libinput. It is possible to attach tool-specific virtual state
to the tool. For example, a graphics program such as the GIMP may assign a
specific color to each tool, allowing the artist to use the tools like
physical pens of different color. In multi-tablet setups it is also
possible to track the tool across devices.
If the tool does not have a unique identifier, libinput creates a single
struct libinput_tablet_tool per tool type on each tablet the tool is used
on.
@section tablet-tool-types Vendor-specific tablet tool types
libinput supports a number of high-level tool types that describe the
general interaction expected with the tool. For example, a user would expect
a tool of type @ref LIBINPUT_TABLET_TOOL_TYPE_PEN to interact with a
graphics application taking pressure and tilt into account. The default
virtual tool assigned should be a drawing tool, e.g. a virtual pen or brush.
A tool of type @ref LIBINPUT_TABLET_TOOL_TYPE_ERASER would normally be
mapped to an eraser-like virtual tool. See @ref libinput_tablet_tool_type
for the list of all available tools.
Vendors may provide more fine-grained information about the tool in use by
adding a hardware-specific tool ID. libinput provides this ID to the caller
with libinput_tablet_tool_get_tool_id() but makes no promises about the
content or format of the ID.
libinput currently supports Wacom-style tool IDs as provided on the Wacom
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.
*/

View file

@ -18,6 +18,8 @@ libinput_la_SOURCES = \
evdev-mt-touchpad-buttons.c \
evdev-mt-touchpad-edge-scroll.c \
evdev-mt-touchpad-gestures.c \
evdev-tablet.c \
evdev-tablet.h \
filter.c \
filter.h \
filter-private.h \
@ -32,12 +34,14 @@ libinput_la_SOURCES = \
libinput_la_LIBADD = $(MTDEV_LIBS) \
$(LIBUDEV_LIBS) \
$(LIBEVDEV_LIBS) \
$(LIBWACOM_LIBS) \
libinput-util.la
libinput_la_CFLAGS = -I$(top_srcdir)/include \
$(MTDEV_CFLAGS) \
$(LIBUDEV_CFLAGS) \
$(LIBEVDEV_CFLAGS) \
$(LIBWACOM_CFLAGS) \
$(GCC_CFLAGS)
EXTRA_libinput_la_DEPENDENCIES = $(srcdir)/libinput.sym

View file

@ -1436,6 +1436,7 @@ static struct evdev_dispatch_interface tp_interface = {
tp_interface_device_removed,
tp_interface_device_removed, /* device_suspended, treat as remove */
tp_interface_device_added, /* device_resumed, treat as add */
NULL, /* post_added */
};
static void

1655
src/evdev-tablet.c Normal file

File diff suppressed because it is too large Load diff

204
src/evdev-tablet.h Normal file
View file

@ -0,0 +1,204 @@
/*
* Copyright © 2014 Red Hat, Inc.
* Copyright © 2014 Stephen Chandler "Lyude" Paul
*
* 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.
*/
#ifndef EVDEV_TABLET_H
#define EVDEV_TABLET_H
#include "evdev.h"
#define LIBINPUT_TABLET_TOOL_AXIS_NONE 0
#define LIBINPUT_TOOL_NONE 0
#define LIBINPUT_TABLET_TOOL_TYPE_MAX LIBINPUT_TABLET_TOOL_TYPE_LENS
enum tablet_status {
TABLET_NONE = 0,
TABLET_AXES_UPDATED = 1 << 0,
TABLET_BUTTONS_PRESSED = 1 << 1,
TABLET_BUTTONS_RELEASED = 1 << 2,
TABLET_TOOL_IN_CONTACT = 1 << 3,
TABLET_TOOL_LEAVING_PROXIMITY = 1 << 4,
TABLET_TOOL_OUT_OF_PROXIMITY = 1 << 5,
TABLET_TOOL_ENTERING_PROXIMITY = 1 << 6,
TABLET_TOOL_ENTERING_CONTACT = 1 << 7,
TABLET_TOOL_LEAVING_CONTACT = 1 << 8,
TABLET_TOOL_OUT_OF_RANGE = 1 << 9,
};
struct button_state {
unsigned char stylus_buttons[NCHARS(KEY_CNT)];
};
struct tablet_dispatch {
struct evdev_dispatch base;
struct evdev_device *device;
unsigned int status;
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
struct tablet_axes axes;
unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
/* Only used for tablets that don't report serial numbers */
struct list tool_list;
struct button_state button_state;
struct button_state prev_button_state;
enum libinput_tablet_tool_type current_tool_type;
uint32_t current_tool_id;
uint32_t current_tool_serial;
uint32_t cursor_proximity_threshold;
};
static inline enum libinput_tablet_tool_axis
evcode_to_axis(const uint32_t evcode)
{
enum libinput_tablet_tool_axis axis;
switch (evcode) {
case ABS_X:
axis = LIBINPUT_TABLET_TOOL_AXIS_X;
break;
case ABS_Y:
axis = LIBINPUT_TABLET_TOOL_AXIS_Y;
break;
case ABS_Z:
axis = LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z;
break;
case ABS_DISTANCE:
axis = LIBINPUT_TABLET_TOOL_AXIS_DISTANCE;
break;
case ABS_PRESSURE:
axis = LIBINPUT_TABLET_TOOL_AXIS_PRESSURE;
break;
case ABS_TILT_X:
axis = LIBINPUT_TABLET_TOOL_AXIS_TILT_X;
break;
case ABS_TILT_Y:
axis = LIBINPUT_TABLET_TOOL_AXIS_TILT_Y;
break;
case ABS_WHEEL:
axis = LIBINPUT_TABLET_TOOL_AXIS_SLIDER;
break;
default:
axis = LIBINPUT_TABLET_TOOL_AXIS_NONE;
break;
}
return axis;
}
static inline enum libinput_tablet_tool_axis
rel_evcode_to_axis(const uint32_t evcode)
{
enum libinput_tablet_tool_axis axis;
switch (evcode) {
case REL_WHEEL:
axis = LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL;
break;
default:
axis = LIBINPUT_TABLET_TOOL_AXIS_NONE;
break;
}
return axis;
}
static inline uint32_t
axis_to_evcode(const enum libinput_tablet_tool_axis axis)
{
uint32_t evcode;
switch (axis) {
case LIBINPUT_TABLET_TOOL_AXIS_X:
evcode = ABS_X;
break;
case LIBINPUT_TABLET_TOOL_AXIS_Y:
evcode = ABS_Y;
break;
case LIBINPUT_TABLET_TOOL_AXIS_DISTANCE:
evcode = ABS_DISTANCE;
break;
case LIBINPUT_TABLET_TOOL_AXIS_PRESSURE:
evcode = ABS_PRESSURE;
break;
case LIBINPUT_TABLET_TOOL_AXIS_TILT_X:
evcode = ABS_TILT_X;
break;
case LIBINPUT_TABLET_TOOL_AXIS_TILT_Y:
evcode = ABS_TILT_Y;
break;
case LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z:
evcode = ABS_Z;
break;
case LIBINPUT_TABLET_TOOL_AXIS_SLIDER:
evcode = ABS_WHEEL;
break;
default:
abort();
}
return evcode;
}
static inline int
tablet_tool_to_evcode(enum libinput_tablet_tool_type type)
{
int code;
switch (type) {
case LIBINPUT_TABLET_TOOL_TYPE_PEN: code = BTN_TOOL_PEN; break;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER: code = BTN_TOOL_RUBBER; break;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: code = BTN_TOOL_BRUSH; break;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: code = BTN_TOOL_PENCIL; break;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: code = BTN_TOOL_AIRBRUSH; break;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: code = BTN_TOOL_MOUSE; break;
case LIBINPUT_TABLET_TOOL_TYPE_LENS: code = BTN_TOOL_LENS; break;
default:
abort();
}
return code;
}
static inline const char *
tablet_tool_type_to_string(enum libinput_tablet_tool_type type)
{
const char *str;
switch (type) {
case LIBINPUT_TABLET_TOOL_TYPE_PEN: str = "pen"; break;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER: str = "eraser"; break;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: str = "brush"; break;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: str = "pencil"; break;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: str = "airbrush"; break;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: str = "mouse"; break;
case LIBINPUT_TABLET_TOOL_TYPE_LENS: str = "lens"; break;
default:
abort();
}
return str;
}
#endif

View file

@ -212,9 +212,9 @@ evdev_device_led_update(struct evdev_device *device, enum libinput_led leds)
(void)i; /* no, we really don't care about the return value */
}
static void
transform_absolute(struct evdev_device *device,
struct device_coords *point)
void
evdev_transform_absolute(struct evdev_device *device,
struct device_coords *point)
{
if (!device->abs.apply_calibration)
return;
@ -222,6 +222,19 @@ transform_absolute(struct evdev_device *device,
matrix_mult_vec(&device->abs.calibration, &point->x, &point->y);
}
void
evdev_transform_relative(struct evdev_device *device,
struct device_coords *point)
{
struct matrix rel_matrix;
if (!device->abs.apply_calibration)
return;
matrix_to_relative(&rel_matrix, &device->abs.calibration);
matrix_mult_vec(&rel_matrix, &point->x, &point->y);
}
static inline double
scale_axis(const struct input_absinfo *absinfo, double val, double to_range)
{
@ -340,7 +353,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
seat->slot_map |= 1 << seat_slot;
point = device->mt.slots[slot].point;
transform_absolute(device, &point);
evdev_transform_absolute(device, &point);
touch_notify_touch_down(base, time, slot, seat_slot,
&point);
@ -355,7 +368,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
if (seat_slot == -1)
break;
transform_absolute(device, &point);
evdev_transform_absolute(device, &point);
touch_notify_touch_motion(base, time, slot, seat_slot,
&point);
break;
@ -394,13 +407,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
seat->slot_map |= 1 << seat_slot;
point = device->abs.point;
transform_absolute(device, &point);
evdev_transform_absolute(device, &point);
touch_notify_touch_down(base, time, -1, seat_slot, &point);
break;
case EVDEV_ABSOLUTE_MOTION:
point = device->abs.point;
transform_absolute(device, &point);
evdev_transform_absolute(device, &point);
if (device->seat_caps & EVDEV_DEVICE_TOUCH) {
seat_slot = device->abs.seat_slot;
@ -962,6 +975,7 @@ struct evdev_dispatch_interface fallback_interface = {
NULL, /* device_removed */
NULL, /* device_suspended */
NULL, /* device_resumed */
NULL, /* post_added */
};
static uint32_t
@ -1191,7 +1205,7 @@ evdev_init_button_scroll(struct evdev_device *device,
return 0;
}
static void
void
evdev_init_calibration(struct evdev_device *device,
struct evdev_dispatch *dispatch)
{
@ -1986,6 +2000,7 @@ evdev_configure_device(struct evdev_device *device)
struct libevdev *evdev = device->evdev;
const char *devnode = udev_device_get_devnode(device->udev_device);
enum evdev_device_udev_tags udev_tags;
unsigned int tablet_tags;
udev_tags = evdev_device_get_udev_tags(device, device->udev_device);
@ -2063,6 +2078,21 @@ evdev_configure_device(struct evdev_device *device)
}
}
/* libwacom assigns touchpad (or touchscreen) _and_ tablet to the
tablet touch bits, so make sure we don't initialize the tablet
interface for the touch device */
tablet_tags = EVDEV_UDEV_TAG_TABLET |
EVDEV_UDEV_TAG_TOUCHPAD |
EVDEV_UDEV_TAG_TOUCHSCREEN;
if ((udev_tags & tablet_tags) == EVDEV_UDEV_TAG_TABLET) {
device->dispatch = evdev_tablet_create(device);
device->seat_caps |= EVDEV_DEVICE_TABLET;
log_info(libinput,
"input device '%s', %s is a tablet\n",
device->devname, devnode);
return device->dispatch == NULL ? -1 : 0;
}
if (udev_tags & EVDEV_UDEV_TAG_TOUCHPAD) {
device->dispatch = evdev_mt_touchpad_create(device);
log_info(libinput,
@ -2153,6 +2183,10 @@ evdev_notify_added_device(struct evdev_device *device)
}
notify_added_device(&device->base);
if (device->dispatch->interface->post_added)
device->dispatch->interface->post_added(device,
device->dispatch);
}
static bool
@ -2442,6 +2476,8 @@ evdev_device_has_capability(struct evdev_device *device,
return !!(device->seat_caps & EVDEV_DEVICE_TOUCH);
case LIBINPUT_DEVICE_CAP_GESTURE:
return !!(device->seat_caps & EVDEV_DEVICE_GESTURE);
case LIBINPUT_DEVICE_CAP_TABLET_TOOL:
return !!(device->seat_caps & EVDEV_DEVICE_TABLET);
default:
return 0;
}

View file

@ -60,6 +60,7 @@ enum evdev_device_seat_capability {
EVDEV_DEVICE_POINTER = (1 << 0),
EVDEV_DEVICE_KEYBOARD = (1 << 1),
EVDEV_DEVICE_TOUCH = (1 << 2),
EVDEV_DEVICE_TABLET = (1 << 3),
EVDEV_DEVICE_GESTURE = (1 << 5),
};
@ -266,6 +267,11 @@ struct evdev_dispatch_interface {
/* A device was resumed */
void (*device_resumed)(struct evdev_device *device,
struct evdev_device *resumed_device);
/* Called immediately after the LIBINPUT_EVENT_DEVICE_ADDED event
* was sent */
void (*post_added)(struct evdev_device *device,
struct evdev_dispatch *dispatch);
};
struct evdev_dispatch {
@ -282,6 +288,18 @@ struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
struct udev_device *device);
void
evdev_transform_absolute(struct evdev_device *device,
struct device_coords *point);
void
evdev_transform_relative(struct evdev_device *device,
struct device_coords *point);
void
evdev_init_calibration(struct evdev_device *device,
struct evdev_dispatch *dispatch);
int
evdev_device_init_pointer_acceleration(struct evdev_device *device,
struct motion_filter *filter);
@ -292,6 +310,9 @@ evdev_touchpad_create(struct evdev_device *device);
struct evdev_dispatch *
evdev_mt_touchpad_create(struct evdev_device *device);
struct evdev_dispatch *
evdev_tablet_create(struct evdev_device *device);
void
evdev_tag_touchpad(struct evdev_device *device,
struct udev_device *udev_device);

View file

@ -163,6 +163,13 @@ struct pointer_accelerator_flat {
double dpi_factor;
};
struct tablet_accelerator_flat {
struct motion_filter base;
double factor;
int xres, yres;
};
static void
feed_trackers(struct pointer_accelerator *accel,
const struct normalized_coords *delta,
@ -964,3 +971,90 @@ create_pointer_accelerator_filter_flat(int dpi)
return &filter->base;
}
/* The tablet accel code uses mm as input */
static struct normalized_coords
tablet_accelerator_filter_flat(struct motion_filter *filter,
const struct normalized_coords *mm,
void *data, uint64_t time)
{
struct tablet_accelerator_flat *accel_filter =
(struct tablet_accelerator_flat *)filter;
struct normalized_coords accelerated;
/* Tablet input is in mm, output is supposed to be in logical
* pixels roughly equivalent to a mouse/touchpad.
*
* This is a magical constant found by trial and error. On a 96dpi
* screen 0.4mm of movement correspond to 1px logical pixel which
* is almost identical to the tablet mapped to screen in absolute
* mode. Tested on a Intuos5, other tablets may vary.
*/
const double DPI_CONVERSION = 96.0/25.4 * 2.5; /* unitless factor */
accelerated.x = mm->x * accel_filter->factor * DPI_CONVERSION;
accelerated.y = mm->y * accel_filter->factor * DPI_CONVERSION;
return accelerated;
}
static bool
tablet_accelerator_set_speed(struct motion_filter *filter,
double speed_adjustment)
{
struct tablet_accelerator_flat *accel_filter =
(struct tablet_accelerator_flat *)filter;
assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
accel_filter->factor = speed_adjustment + 1.0;
return true;
}
static void
tablet_accelerator_destroy(struct motion_filter *filter)
{
struct tablet_accelerator_flat *accel_filter =
(struct tablet_accelerator_flat *)filter;
free(accel_filter);
}
struct motion_filter_interface accelerator_interface_tablet = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
.filter = tablet_accelerator_filter_flat,
.filter_constant = NULL,
.restart = NULL,
.destroy = tablet_accelerator_destroy,
.set_speed = tablet_accelerator_set_speed,
};
static struct tablet_accelerator_flat *
create_tablet_filter_flat(int xres, int yres)
{
struct tablet_accelerator_flat *filter;
filter = zalloc(sizeof *filter);
if (filter == NULL)
return NULL;
filter->xres = xres;
filter->yres = yres;
return filter;
}
struct motion_filter *
create_pointer_accelerator_filter_tablet(int xres, int yres)
{
struct tablet_accelerator_flat *filter;
filter = create_tablet_filter_flat(xres, yres);
if (!filter)
return NULL;
filter->base.interface = &accelerator_interface_tablet;
return &filter->base;
}

View file

@ -101,6 +101,9 @@ create_pointer_accelerator_filter_lenovo_x230(int dpi);
struct motion_filter *
create_pointer_accelerator_filter_trackpoint(int dpi);
struct motion_filter *
create_pointer_accelerator_filter_tablet(int xres, int yres);
/*
* Pointer acceleration profiles.
*/

View file

@ -58,6 +58,29 @@ struct discrete_coords {
int x, y;
};
/* A pair of coordinates normalized to a [0,1] or [-1, 1] range */
struct normalized_range_coords {
double x, y;
};
/* A threshold with an upper and lower limit */
struct threshold {
int upper;
int lower;
};
struct tablet_axes {
struct device_coords point;
struct normalized_coords delta;
double distance;
double pressure;
struct normalized_range_coords tilt;
double rotation;
double slider;
double wheel;
int wheel_discrete;
};
struct libinput_interface_backend {
int (*resume)(struct libinput *libinput);
void (*suspend)(struct libinput *libinput);
@ -84,6 +107,8 @@ struct libinput {
size_t events_in;
size_t events_out;
struct list tool_list;
const struct libinput_interface *interface;
const struct libinput_interface_backend *interface_backend;
@ -251,6 +276,36 @@ struct libinput_device {
struct libinput_device_config config;
};
enum libinput_tablet_tool_axis {
LIBINPUT_TABLET_TOOL_AXIS_X = 1,
LIBINPUT_TABLET_TOOL_AXIS_Y = 2,
LIBINPUT_TABLET_TOOL_AXIS_DISTANCE = 3,
LIBINPUT_TABLET_TOOL_AXIS_PRESSURE = 4,
LIBINPUT_TABLET_TOOL_AXIS_TILT_X = 5,
LIBINPUT_TABLET_TOOL_AXIS_TILT_Y = 6,
LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z = 7,
LIBINPUT_TABLET_TOOL_AXIS_SLIDER = 8,
LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL = 9,
};
#define LIBINPUT_TABLET_TOOL_AXIS_MAX LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL
struct libinput_tablet_tool {
struct list link;
uint32_t serial;
uint32_t tool_id;
enum libinput_tablet_tool_type type;
unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
unsigned char buttons[NCHARS(KEY_MAX) + 1];
int refcount;
void *user_data;
/* The pressure threshold assumes a pressure_offset of 0 */
struct threshold pressure_threshold;
int pressure_offset; /* in device coordinates */
bool has_pressure_offset;
};
struct libinput_event {
enum libinput_event_type type;
struct libinput_device *device;
@ -451,6 +506,39 @@ void
touch_notify_frame(struct libinput_device *device,
uint64_t time);
void
tablet_notify_axis(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
const struct tablet_axes *axes);
void
tablet_notify_proximity(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_proximity_state state,
unsigned char *changed_axes,
const struct tablet_axes *axes);
void
tablet_notify_tip(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
const struct tablet_axes *axes);
void
tablet_notify_button(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
const struct tablet_axes *axes,
int32_t button,
enum libinput_button_state state);
static inline uint64_t
libinput_now(struct libinput *libinput)
{

View file

@ -96,6 +96,8 @@ int list_empty(const struct list *list);
#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
#define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
#define NCHARS(x) ((size_t)(((x) + 7) / 8))
#ifdef DEBUG_TRACE
#define debug_trace(...) \
do { \
@ -105,6 +107,7 @@ int list_empty(const struct list *list);
#else
#define debug_trace(...) { }
#endif
#define LIBINPUT_EXPORT __attribute__ ((visibility("default")))
static inline void *
@ -113,6 +116,28 @@ zalloc(size_t size)
return calloc(1, size);
}
/* This bitfield helper implementation is taken from from libevdev-util.h,
* except that it has been modified to work with arrays of unsigned chars
*/
static inline int
bit_is_set(const unsigned char *array, int bit)
{
return !!(array[bit / 8] & (1 << (bit % 8)));
}
static inline void
set_bit(unsigned char *array, int bit)
{
array[bit / 8] |= (1 << (bit % 8));
}
static inline void
clear_bit(unsigned char *array, int bit)
{
array[bit / 8] &= ~(1 << (bit % 8));
}
static inline void
msleep(unsigned int ms)
{
@ -245,6 +270,16 @@ matrix_to_farray6(const struct matrix *m, float out[6])
out[5] = m->val[1][2];
}
static inline void
matrix_to_relative(struct matrix *dest, const struct matrix *src)
{
matrix_init_identity(dest);
dest->val[0][0] = src->val[0][0];
dest->val[0][1] = src->val[0][1];
dest->val[1][0] = src->val[1][0];
dest->val[1][1] = src->val[1][1];
}
/**
* Simple wrapper for asprintf that ensures the passed in-pointer is set
* to NULL upon error.

View file

@ -125,6 +125,19 @@ struct libinput_event_gesture {
double angle;
};
struct libinput_event_tablet_tool {
struct libinput_event base;
uint32_t button;
enum libinput_button_state state;
uint32_t seat_button_count;
uint64_t time;
struct tablet_axes axes;
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
struct libinput_tablet_tool *tool;
enum libinput_tablet_tool_proximity_state proximity_state;
enum libinput_tablet_tool_tip_state tip_state;
};
static void
libinput_default_log_func(struct libinput *libinput,
enum libinput_log_priority priority,
@ -272,7 +285,6 @@ libinput_event_get_touch_event(struct libinput_event *event)
LIBINPUT_EVENT_TOUCH_MOTION,
LIBINPUT_EVENT_TOUCH_CANCEL,
LIBINPUT_EVENT_TOUCH_FRAME);
return (struct libinput_event_touch *) event;
}
@ -292,6 +304,20 @@ libinput_event_get_gesture_event(struct libinput_event *event)
return (struct libinput_event_gesture *) event;
}
LIBINPUT_EXPORT struct libinput_event_tablet_tool *
libinput_event_get_tablet_tool_event(struct libinput_event *event)
{
require_event_type(libinput_event_get_context(event),
event->type,
NULL,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
return (struct libinput_event_tablet_tool *) event;
}
LIBINPUT_EXPORT struct libinput_event_device_notify *
libinput_event_get_device_notify_event(struct libinput_event *event)
{
@ -884,6 +910,569 @@ libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event)
return event->angle;
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_x_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_X);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_y_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_Y);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_pressure_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_distance_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_DISTANCE);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_tilt_x_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_tilt_y_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_TILT_Y);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_rotation_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_slider_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_SLIDER);
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_wheel_has_changed(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return bit_is_set(event->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL);
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event)
{
struct evdev_device *device =
(struct evdev_device *) event->base.device;
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return evdev_convert_to_mm(device->abs.absinfo_x,
event->axes.point.x);
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_y(struct libinput_event_tablet_tool *event)
{
struct evdev_device *device =
(struct evdev_device *) event->base.device;
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return evdev_convert_to_mm(device->abs.absinfo_y,
event->axes.point.y);
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_dx(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.delta.x;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_dy(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.delta.y;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_pressure(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.pressure;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_distance(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.distance;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_tilt_x(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.tilt.x;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_tilt_y(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.tilt.y;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_rotation(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.rotation;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_slider_position(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.slider;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_wheel_delta(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.wheel;
}
LIBINPUT_EXPORT int
libinput_event_tablet_tool_get_wheel_delta_discrete(
struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->axes.wheel_discrete;
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_x_transformed(struct libinput_event_tablet_tool *event,
uint32_t width)
{
struct evdev_device *device =
(struct evdev_device *) event->base.device;
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return evdev_device_transform_x(device,
event->axes.point.x,
width);
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_y_transformed(struct libinput_event_tablet_tool *event,
uint32_t height)
{
struct evdev_device *device =
(struct evdev_device *) event->base.device;
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return evdev_device_transform_y(device,
event->axes.point.y,
height);
}
LIBINPUT_EXPORT struct libinput_tablet_tool *
libinput_event_tablet_tool_get_tool(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->tool;
}
LIBINPUT_EXPORT enum libinput_tablet_tool_proximity_state
libinput_event_tablet_tool_get_proximity_state(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->proximity_state;
}
LIBINPUT_EXPORT enum libinput_tablet_tool_tip_state
libinput_event_tablet_tool_get_tip_state(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->tip_state;
}
LIBINPUT_EXPORT uint32_t
libinput_event_tablet_tool_get_time(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return us2ms(event->time);
}
LIBINPUT_EXPORT uint64_t
libinput_event_tablet_tool_get_time_usec(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
return event->time;
}
LIBINPUT_EXPORT uint32_t
libinput_event_tablet_tool_get_button(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
return event->button;
}
LIBINPUT_EXPORT enum libinput_button_state
libinput_event_tablet_tool_get_button_state(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
return event->state;
}
LIBINPUT_EXPORT uint32_t
libinput_event_tablet_tool_get_seat_button_count(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
return event->seat_button_count;
}
LIBINPUT_EXPORT enum libinput_tablet_tool_type
libinput_tablet_tool_get_type(struct libinput_tablet_tool *tool)
{
return tool->type;
}
LIBINPUT_EXPORT uint64_t
libinput_tablet_tool_get_tool_id(struct libinput_tablet_tool *tool)
{
return tool->tool_id;
}
LIBINPUT_EXPORT int
libinput_tablet_tool_is_unique(struct libinput_tablet_tool *tool)
{
return tool->serial != 0;
}
LIBINPUT_EXPORT uint64_t
libinput_tablet_tool_get_serial(struct libinput_tablet_tool *tool)
{
return tool->serial;
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_pressure(struct libinput_tablet_tool *tool)
{
return bit_is_set(tool->axis_caps,
LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_distance(struct libinput_tablet_tool *tool)
{
return bit_is_set(tool->axis_caps,
LIBINPUT_TABLET_TOOL_AXIS_DISTANCE);
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_tilt(struct libinput_tablet_tool *tool)
{
return bit_is_set(tool->axis_caps,
LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_rotation(struct libinput_tablet_tool *tool)
{
return bit_is_set(tool->axis_caps,
LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_slider(struct libinput_tablet_tool *tool)
{
return bit_is_set(tool->axis_caps,
LIBINPUT_TABLET_TOOL_AXIS_SLIDER);
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_wheel(struct libinput_tablet_tool *tool)
{
return bit_is_set(tool->axis_caps,
LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL);
}
LIBINPUT_EXPORT int
libinput_tablet_tool_has_button(struct libinput_tablet_tool *tool,
uint32_t code)
{
if (NCHARS(code) > sizeof(tool->buttons))
return 0;
return bit_is_set(tool->buttons, code);
}
LIBINPUT_EXPORT void
libinput_tablet_tool_set_user_data(struct libinput_tablet_tool *tool,
void *user_data)
{
tool->user_data = user_data;
}
LIBINPUT_EXPORT void *
libinput_tablet_tool_get_user_data(struct libinput_tablet_tool *tool)
{
return tool->user_data;
}
LIBINPUT_EXPORT struct libinput_tablet_tool *
libinput_tablet_tool_ref(struct libinput_tablet_tool *tool)
{
tool->refcount++;
return tool;
}
LIBINPUT_EXPORT struct libinput_tablet_tool *
libinput_tablet_tool_unref(struct libinput_tablet_tool *tool)
{
assert(tool->refcount > 0);
tool->refcount--;
if (tool->refcount > 0)
return tool;
list_remove(&tool->link);
free(tool);
return NULL;
}
struct libinput_source *
libinput_add_fd(struct libinput *libinput,
int fd,
@ -948,6 +1537,7 @@ libinput_init(struct libinput *libinput,
list_init(&libinput->source_destroy_list);
list_init(&libinput->seat_list);
list_init(&libinput->device_group_list);
list_init(&libinput->tool_list);
if (libinput_timer_subsys_init(libinput) != 0) {
free(libinput->events);
@ -987,6 +1577,7 @@ libinput_unref(struct libinput *libinput)
struct libinput_event *event;
struct libinput_device *device, *next_device;
struct libinput_seat *seat, *next_seat;
struct libinput_tablet_tool *tool, *next_tool;
struct libinput_device_group *group, *next_group;
if (libinput == NULL)
@ -1022,6 +1613,10 @@ libinput_unref(struct libinput *libinput)
libinput_device_group_destroy(group);
}
list_for_each_safe(tool, next_tool, &libinput->tool_list, link) {
libinput_tablet_tool_unref(tool);
}
libinput_timer_subsys_destroy(libinput);
libinput_drop_destroyed_sources(libinput);
close(libinput->epoll_fd);
@ -1355,6 +1950,9 @@ device_has_cap(struct libinput_device *device,
case LIBINPUT_DEVICE_CAP_GESTURE:
capability = "CAP_GESTURE";
break;
case LIBINPUT_DEVICE_CAP_TABLET_TOOL:
capability = "CAP_TABLET";
break;
}
log_bug_libinput(device->seat->libinput,
@ -1611,6 +2209,137 @@ touch_notify_frame(struct libinput_device *device,
&touch_event->base);
}
void
tablet_notify_axis(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
const struct tablet_axes *axes)
{
struct libinput_event_tablet_tool *axis_event;
axis_event = zalloc(sizeof *axis_event);
if (!axis_event)
return;
*axis_event = (struct libinput_event_tablet_tool) {
.time = time,
.tool = tool,
.proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
.tip_state = tip_state,
.axes = *axes,
};
memcpy(axis_event->changed_axes,
changed_axes,
sizeof(axis_event->changed_axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
&axis_event->base);
}
void
tablet_notify_proximity(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_proximity_state proximity_state,
unsigned char *changed_axes,
const struct tablet_axes *axes)
{
struct libinput_event_tablet_tool *proximity_event;
proximity_event = zalloc(sizeof *proximity_event);
if (!proximity_event)
return;
*proximity_event = (struct libinput_event_tablet_tool) {
.time = time,
.tool = tool,
.tip_state = LIBINPUT_TABLET_TOOL_TIP_UP,
.proximity_state = proximity_state,
.axes = *axes,
};
memcpy(proximity_event->changed_axes,
changed_axes,
sizeof(proximity_event->changed_axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY,
&proximity_event->base);
}
void
tablet_notify_tip(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
const struct tablet_axes *axes)
{
struct libinput_event_tablet_tool *tip_event;
tip_event = zalloc(sizeof *tip_event);
if (!tip_event)
return;
*tip_event = (struct libinput_event_tablet_tool) {
.time = time,
.tool = tool,
.tip_state = tip_state,
.proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
.axes = *axes,
};
memcpy(tip_event->changed_axes,
changed_axes,
sizeof(tip_event->changed_axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
&tip_event->base);
}
void
tablet_notify_button(struct libinput_device *device,
uint64_t time,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
const struct tablet_axes *axes,
int32_t button,
enum libinput_button_state state)
{
struct libinput_event_tablet_tool *button_event;
int32_t seat_button_count;
button_event = zalloc(sizeof *button_event);
if (!button_event)
return;
seat_button_count = update_seat_button_count(device->seat,
button,
state);
*button_event = (struct libinput_event_tablet_tool) {
.time = time,
.tool = tool,
.button = button,
.state = state,
.seat_button_count = seat_button_count,
.proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
.tip_state = tip_state,
.axes = *axes,
};
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
&button_event->base);
}
static void
gesture_notify(struct libinput_device *device,
uint64_t time,
@ -1696,6 +2425,39 @@ gesture_notify_pinch_end(struct libinput_device *device,
finger_count, cancelled, &zero, &zero, scale, 0.0);
}
static inline const char *
event_type_to_str(enum libinput_event_type type)
{
switch(type) {
CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_ADDED);
CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_REMOVED);
CASE_RETURN_STRING(LIBINPUT_EVENT_KEYBOARD_KEY);
CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION);
CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE);
CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_BUTTON);
CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_AXIS);
CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_DOWN);
CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_UP);
CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_MOTION);
CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_CANCEL);
CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_FRAME);
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_AXIS);
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_TIP);
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_END);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END);
case LIBINPUT_EVENT_NONE:
abort();
}
return NULL;
}
static void
libinput_post_event(struct libinput *libinput,
struct libinput_event *event)
@ -1706,6 +2468,10 @@ libinput_post_event(struct libinput *libinput,
size_t move_len;
size_t new_out;
#if 0
log_debug(libinput, "Queuing %s\n", event_type_to_str(event->type));
#endif
events_count++;
if (events_count > events_len) {
events_len *= 2;
@ -1968,6 +2734,20 @@ libinput_event_gesture_get_base_event(struct libinput_event_gesture *event)
return &event->base;
}
LIBINPUT_EXPORT struct libinput_event *
libinput_event_tablet_tool_get_base_event(struct libinput_event_tablet_tool *event)
{
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
NULL,
LIBINPUT_EVENT_TABLET_TOOL_AXIS,
LIBINPUT_EVENT_TABLET_TOOL_TIP,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
return &event->base;
}
LIBINPUT_EXPORT struct libinput_device_group *
libinput_device_group_ref(struct libinput_device_group *group)
{

View file

@ -58,6 +58,7 @@ enum libinput_device_capability {
LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
LIBINPUT_DEVICE_CAP_POINTER = 1,
LIBINPUT_DEVICE_CAP_TOUCH = 2,
LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
LIBINPUT_DEVICE_CAP_GESTURE = 5,
};
@ -133,6 +134,87 @@ enum libinput_pointer_axis_source {
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
};
/**
* @ingroup device
* @struct libinput_tablet_tool
*
* An object representing a tool being used by a device with the @ref
* LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
*
* Tablet events generated by such a device are bound to a specific tool
* rather than coming from the device directly. Depending on the hardware it
* is possible to track the same physical tool across multiple
* struct libinput_device devices, see @ref tablet-serial-numbers.
*
* This struct is refcounted, use libinput_tablet_tool_ref() and
* libinput_tablet_tool_unref().
*/
struct libinput_tablet_tool;
/**
* @ingroup device
*
* Available tool types for a device with the @ref
* LIBINPUT_DEVICE_CAP_TABLET_TOOL capability. The tool type defines the default
* usage of the tool as advertised by the manufacturer. Multiple different
* physical tools may share the same tool type, e.g. a Wacom Classic Pen,
* Wacom Pro Pen and a Wacom Grip Pen are all of type @ref
* LIBINPUT_TABLET_TOOL_TYPE_PEN.
* Use libinput_tablet_tool_get_tool_id() to get a specific model where applicable.
*
* Note that on some device, the eraser tool is on the tail end of a pen
* device. On other devices, e.g. MS Surface 3, the eraser is the pen tip
* while a button is held down.
*
* @note The @ref libinput_tablet_tool_type can only describe the default physical
* type of the device. For devices with adjustible physical properties
* the tool type remains the same, i.e. putting a Wacom stroke nib into a
* classic pen leaves the tool type as @ref LIBINPUT_TABLET_TOOL_TYPE_PEN.
*/
enum libinput_tablet_tool_type {
LIBINPUT_TABLET_TOOL_TYPE_PEN = 1, /**< A generic pen */
LIBINPUT_TABLET_TOOL_TYPE_ERASER, /**< Eraser */
LIBINPUT_TABLET_TOOL_TYPE_BRUSH, /**< A paintbrush-like tool */
LIBINPUT_TABLET_TOOL_TYPE_PENCIL, /**< Physical drawing tool, e.g.
Wacom Inking Pen */
LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH, /**< An airbrush-like tool */
LIBINPUT_TABLET_TOOL_TYPE_MOUSE, /**< A mouse bound to the tablet */
LIBINPUT_TABLET_TOOL_TYPE_LENS, /**< A mouse tool with a lens */
};
/**
* @ingroup device
*
* The state of proximity for a tool on a device. The device must have the @ref
* LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
*
* The proximity of a tool is a binary state signalling whether the tool is
* within detectable distance of the tablet device. A tool that is out of
* proximity cannot generate events.
*
* On some hardware a tool goes out of proximity when it ceases to touch the
* surface. On other hardware, the tool is still detectable within a short
* distance (a few cm) off the surface.
*/
enum libinput_tablet_tool_proximity_state {
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT = 0,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN = 1,
};
/**
* @ingroup device
*
* The tip contact state for a tool on a device. The device must have
* the @ref LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
*
* The tip contact state of a tool is a binary state signalling whether the tool is
* touching the surface of the tablet device.
*/
enum libinput_tablet_tool_tip_state {
LIBINPUT_TABLET_TOOL_TIP_UP = 0,
LIBINPUT_TABLET_TOOL_TIP_DOWN = 1,
};
/**
* @ingroup base
*
@ -179,6 +261,84 @@ enum libinput_event_type {
*/
LIBINPUT_EVENT_TOUCH_FRAME,
/**
* One or more axes have changed state on a device with the @ref
* LIBINPUT_DEVICE_CAP_TABLET_TOOL capability. This event is only sent
* when the tool is in proximity, see @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY for details.
*
* The proximity event contains the initial state of the axis as the
* tool comes into proximity. An event of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS is only sent when an axis value
* changes from this initial state. It is possible for a tool to
* enter and leave proximity without sending an event of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS.
*
* An event of type @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS is sent
* when the tip state does not change. See the documentation for
* @ref LIBINPUT_EVENT_TABLET_TOOL_TIP for more details.
*/
LIBINPUT_EVENT_TABLET_TOOL_AXIS = 600,
/**
* Signals that a tool has come in or out of proximity of a device with
* the @ref LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
*
* Proximity events contain each of the current values for each axis,
* and these values may be extracted from them in the same way they are
* with @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS events.
*
* Some tools may always be in proximity. For these tools, events of
* type @ref LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN are sent only once after @ref
* LIBINPUT_EVENT_DEVICE_ADDED, and events of type @ref
* LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT are sent only once before @ref
* LIBINPUT_EVENT_DEVICE_REMOVED.
*
* If the tool that comes into proximity supports x/y coordinates,
* libinput guarantees that both x and y are set in the proximity
* event.
*
* When a tool goes out of proximity, the value of every axis should be
* assumed to have an undefined state and any buttons that are currently held
* down on the stylus are marked as released. Button release events for
* each button that was held down on the stylus are sent before the
* proximity out event.
*/
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY,
/**
* Signals that a tool has come in contact with the surface of a
* device with the @ref LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
*
* On devices without distance proximity detection, the @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP is sent immediately after @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY for the tip down event, and
* immediately before for the tip up event.
*
* The decision when a tip touches the surface is device-dependent
* and may be derived from pressure data or other means. If the tip
* state is changed by axes changing state, the
* @ref LIBINPUT_EVENT_TABLET_TOOL_TIP event includes the changed
* axes and no additional axis event is sent for this state change.
* In other words, a caller must look at both @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS and @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP events to know the current state
* of the axes.
*
* If a button state change occurs at the same time as a tip state
* change, the order of events is device-dependent.
*/
LIBINPUT_EVENT_TABLET_TOOL_TIP,
/**
* Signals that a tool has changed a logical button state on a
* device with the @ref LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
*
* Button state changes occur on their own and do not include axis
* state changes. If button and axis state changes occur within the
* same logical hardware event, the order of the @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON and @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS event is device-specific.
*/
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
LIBINPUT_EVENT_GESTURE_SWIPE_END,
@ -273,6 +433,16 @@ struct libinput_event_pointer;
*/
struct libinput_event_touch;
/**
* @ingroup event_tablet
* @struct libinput_event_tablet_tool
*
* Tablet event representing an axis update, button press, or tool update. Valid
* event types for this event are @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY and @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*/
struct libinput_event_tablet_tool;
/**
* @defgroup event Accessing and destruction of events
*/
@ -369,8 +539,6 @@ struct libinput_event_touch *
libinput_event_get_touch_event(struct libinput_event *event);
/**
* @ingroup event
*
* Return the gesture event that is this input event. If the event type does
* not match the gesture event types, this function returns NULL.
*
@ -381,6 +549,19 @@ libinput_event_get_touch_event(struct libinput_event *event);
struct libinput_event_gesture *
libinput_event_get_gesture_event(struct libinput_event *event);
/**
* @ingroup event
*
* Return the tablet event that is this input event. If the event type does not
* match the tablet event types, this function returns NULL.
*
* The inverse of this function is libinput_event_tablet_tool_get_base_event().
*
* @return A tablet event, or NULL for other events
*/
struct libinput_event_tablet_tool *
libinput_event_get_tablet_tool_event(struct libinput_event *event);
/**
* @ingroup event
*
@ -1169,6 +1350,737 @@ libinput_event_gesture_get_scale(struct libinput_event_gesture *event);
double
libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event);
/**
* @defgroup event_tablet Tablet events
*
* Events that come from tools on tablet devices.
*/
/**
* @ingroup event_tablet
*
* @return The generic libinput_event of this event
*/
struct libinput_event *
libinput_event_tablet_tool_get_base_event(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the x axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_x_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the y axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_y_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the pressure axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_pressure_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the distance axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
* For tablet events of type @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this
* function always returns 1.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_distance_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the tilt x axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_tilt_x_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the tilt y axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_tilt_y_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the z-rotation axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_rotation_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the slider axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_slider_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Check if the wheel axis was updated in this event.
* For tablet events that are not of type @ref
* LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or
* @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0.
*
* @note It is an application bug to call this function for events other
* than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref
* LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return 1 if the axis was updated or 0 otherwise
*/
int
libinput_event_tablet_tool_wheel_has_changed(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the X coordinate of the tablet tool, in mm from the top left
* corner of the tablet in its current logical orientation. Use
* libinput_event_tablet_tool_get_x_transformed() for transforming the axis
* value into a different coordinate space.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the Y coordinate of the tablet tool, in mm from the top left
* corner of the tablet in its current logical orientation. Use
* libinput_event_tablet_tool_get_y_transformed() for transforming the axis
* value into a different coordinate space.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_y(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the delta between the last event and the current event.
* If the tool employs pointer acceleration, the delta returned by this
* function is the accelerated delta.
*
* This value is in screen coordinate space, the delta is to be interpreted
* like the return value of libinput_event_pointer_get_dx().
* See @ref tablet-relative-motion for more details.
*
* @param event The libinput tablet event
* @return The relative x movement since the last event
*/
double
libinput_event_tablet_tool_get_dx(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the delta between the last event and the current event.
* If the tool employs pointer acceleration, the delta returned by this
* function is the accelerated delta.
*
* This value is in screen coordinate space, the delta is to be interpreted
* like the return value of libinput_event_pointer_get_dx().
* See @ref tablet-relative-motion for more details.
*
* @param event The libinput tablet event
* @return The relative y movement since the last event
*/
double
libinput_event_tablet_tool_get_dy(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the current pressure being applied on the tool in use, normalized
* to the range [0, 1].
*
* If this axis does not exist on the current tool, this function returns 0.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_pressure(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the current distance from the tablet's sensor, normalized to the
* range [0, 1].
*
* If this axis does not exist on the current tool, this function returns 0.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_distance(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the current tilt along the X axis of the tablet's current logical
* orientation, normalized to the range [-1, 1].
*
* If this axis does not exist on the current tool, this function returns 0.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_tilt_x(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the current tilt along the Y axis of the tablet's current logical
* orientation, normalized to the range [-1, 1].
*
* If this axis does not exist on the current tool, this function returns 0.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_tilt_y(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the current z rotation of the tool in degrees, clockwise from the
* tool's logical neutral position.
*
* For tools of type @ref LIBINPUT_TABLET_TOOL_TYPE_MOUSE and @ref
* LIBINPUT_TABLET_TOOL_TYPE_LENS the logical neutral position is
* pointing to the current logical north of the tablet. For tools of type @ref
* LIBINPUT_TABLET_TOOL_TYPE_BRUSH, the logical neutral position is with the
* buttons pointing up.
*
* If this axis does not exist on the current tool, this function returns 0.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_rotation(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the current position of the slider on the tool, normalized to the
* range [-1, 1]. The logical zero is the neutral position of the slider, or
* the logical center of the axis. This axis is available on e.g. the Wacom
* Airbrush.
*
* If this axis does not exist on the current tool, this function returns 0.
*
* @param event The libinput tablet event
* @return The current value of the the axis
*/
double
libinput_event_tablet_tool_get_slider_position(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the delta for the wheel in degrees.
*
* @param event The libinput tablet event
* @return The delta of the wheel, in degrees, compared to the last event
*
* @see libinput_event_tablet_tool_get_wheel_delta_discrete
*/
double
libinput_event_tablet_tool_get_wheel_delta(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the delta for the wheel in discrete steps (e.g. wheel clicks).
* @param event The libinput tablet event
* @return The delta of the wheel, in discrete steps, compared to the last event
*
* @see libinput_event_tablet_tool_get_wheel_delta_discrete
*/
int
libinput_event_tablet_tool_get_wheel_delta_discrete(
struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the current absolute x coordinate of the tablet event, transformed to
* screen coordinates.
*
* @note This function may be called for a specific axis even if
* libinput_event_tablet_tool_*_has_changed() returns 0 for that axis.
* libinput always includes all device axes in the event.
*
* @param event The libinput tablet event
* @param width The current output screen width
* @return the current absolute x coordinate transformed to a screen coordinate
*/
double
libinput_event_tablet_tool_get_x_transformed(struct libinput_event_tablet_tool *event,
uint32_t width);
/**
* @ingroup event_tablet
*
* Return the current absolute y coordinate of the tablet event, transformed to
* screen coordinates.
*
* @note This function may be called for a specific axis even if
* libinput_event_tablet_tool_*_has_changed() returns 0 for that axis.
* libinput always includes all device axes in the event.
*
* @param event The libinput tablet event
* @param height The current output screen height
* @return the current absolute y coordinate transformed to a screen coordinate
*/
double
libinput_event_tablet_tool_get_y_transformed(struct libinput_event_tablet_tool *event,
uint32_t height);
/**
* @ingroup event_tablet
*
* Returns the tool that was in use during this event.
*
* If the caller holds at least one reference (see
* libinput_tablet_tool_ref()), this struct is used whenever the
* tools enters proximity. Otherwise, if no references remain when the tool
* leaves proximity, the tool may be destroyed.
*
* @note Physical tool tracking requires hardware support. If unavailable,
* libinput creates one tool per type per tablet. See @ref
* tablet-serial-numbers for more details.
*
* @param event The libinput tablet event
* @return The new tool triggering this event
*/
struct libinput_tablet_tool *
libinput_event_tablet_tool_get_tool(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the new proximity state of a tool from a proximity event.
* Used to check whether or not a tool came in or out of proximity during an
* event of type @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY.
*
* See @ref tablet-fake-proximity for recommendations on proximity handling.
*
* @param event The libinput tablet event
* @return The new proximity state of the tool from the event.
*/
enum libinput_tablet_tool_proximity_state
libinput_event_tablet_tool_get_proximity_state(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Returns the new tip state of a tool from a tip event.
* Used to check whether or not a tool came in contact with the tablet
* surface or left contact with the tablet surface during an
* event of type @ref LIBINPUT_EVENT_TABLET_TOOL_TIP.
*
* @param event The libinput tablet event
* @return The new tip state of the tool from the event.
*/
enum libinput_tablet_tool_tip_state
libinput_event_tablet_tool_get_tip_state(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the button that triggered this event.
* For tablet events that are not of type @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON, this
* function returns 0.
*
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return the button triggering this event
*/
uint32_t
libinput_event_tablet_tool_get_button(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the button state of the event.
*
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
*
* @param event The libinput tablet event
* @return the button state triggering this event
*/
enum libinput_button_state
libinput_event_tablet_tool_get_button_state(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* For the button of a @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON event, return the total
* number of buttons pressed on all devices on the associated seat after the
* the event was triggered.
*
" @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON. For other events, this function returns 0.
*
* @return the seat wide pressed button count for the key of this event
*/
uint32_t
libinput_event_tablet_tool_get_seat_button_count(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* @param event The libinput tablet event
* @return The event time for this event
*/
uint32_t
libinput_event_tablet_tool_get_time(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* @param event The libinput tablet event
* @return The event time for this event in microseconds
*/
uint64_t
libinput_event_tablet_tool_get_time_usec(struct libinput_event_tablet_tool *event);
/**
* @ingroup event_tablet
*
* Return the type of tool type for a tool object, see @ref
* tablet-tool-types for details.
*
* @param tool The libinput tool
* @return The tool type for this tool object
*
* @see libinput_tablet_tool_get_tool_id
*/
enum libinput_tablet_tool_type
libinput_tablet_tool_get_type(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return the tool ID for a tool object. If nonzero, this number identifies
* the specific type of the tool with more precision than the type returned in
* libinput_tablet_tool_get_type(), see @ref tablet-tool-types. Not all
* tablets support a tool ID.
*
* Tablets known to support tool IDs include the Wacom Intuos 3, 4, 5, Wacom
* Cintiq and Wacom Intuos Pro series.
*
* @param tool The libinput tool
* @return The tool ID for this tool object or 0 if none is provided
*
* @see libinput_tablet_tool_get_type
*/
uint64_t
libinput_tablet_tool_get_tool_id(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Increment the reference count of the tool by one. A tool is destroyed
* whenever the reference count reaches 0. See libinput_tablet_tool_unref().
*
* @param tool The tool to increment the ref count of
* @return The passed tool
*
* @see libinput_tablet_tool_unref
*/
struct libinput_tablet_tool *
libinput_tablet_tool_ref(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Decrement the reference count of the tool by one. When the reference
* count of tool reaches 0, the memory allocated for tool will be freed.
*
* @param tool The tool to decrement the ref count of
* @return NULL if the tool was destroyed otherwise the passed tool
*
* @see libinput_tablet_tool_ref
*/
struct libinput_tablet_tool *
libinput_tablet_tool_unref(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return whether the tablet tool supports pressure.
*
* @param tool The tool to check the axis capabilities of
* @return Nonzero if the axis is available, zero otherwise.
*/
int
libinput_tablet_tool_has_pressure(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return whether the tablet tool supports distance.
*
* @param tool The tool to check the axis capabilities of
* @return Nonzero if the axis is available, zero otherwise.
*/
int
libinput_tablet_tool_has_distance(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return whether the tablet tool supports tilt.
*
* @param tool The tool to check the axis capabilities of
* @return Nonzero if the axis is available, zero otherwise.
*/
int
libinput_tablet_tool_has_tilt(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return whether the tablet tool supports z-rotation.
*
* @param tool The tool to check the axis capabilities of
* @return Nonzero if the axis is available, zero otherwise.
*/
int
libinput_tablet_tool_has_rotation(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return whether the tablet tool has a slider axis.
*
* @param tool The tool to check the axis capabilities of
* @return Nonzero if the axis is available, zero otherwise.
*/
int
libinput_tablet_tool_has_slider(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return whether the tablet tool has a relative wheel.
*
* @param tool The tool to check the axis capabilities of
* @return Nonzero if the axis is available, zero otherwise.
*/
int
libinput_tablet_tool_has_wheel(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Check if a tablet tool has a button with the
* passed-in code (see linux/input.h).
*
* @param tool A tablet tool
* @param code button code to check for
*
* @return 1 if the tool supports this button code, 0 if it does not
*/
int
libinput_tablet_tool_has_button(struct libinput_tablet_tool *tool,
uint32_t code);
/**
* @ingroup event_tablet
*
* Return nonzero if the physical tool can be uniquely identified by
* libinput, or nonzero otherwise. If a tool can be uniquely identified,
* keeping a reference to the tool allows tracking the tool across
* proximity out sequences and across compatible tablets.
* See @ref tablet-serial-numbers for more details.
*
* @param tool A tablet tool
* @return 1 if the tool can be uniquely identified, 0 otherwise.
*
* @see libinput_tablet_tool_get_serial
*/
int
libinput_tablet_tool_is_unique(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return the serial number of a tool. If the tool does not report a serial
* number, this function returns zero. See @ref tablet-serial-numbers for
* details.
*
* @param tool The libinput tool
* @return The tool serial number
*
* @see libinput_tablet_tool_is_unique
*/
uint64_t
libinput_tablet_tool_get_serial(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Return the user data associated with a tool object. libinput does
* not manage, look at, or modify this data. The caller must ensure the
* data is valid.
*
* @param tool The libinput tool
* @return The user data associated with the tool object
*/
void *
libinput_tablet_tool_get_user_data(struct libinput_tablet_tool *tool);
/**
* @ingroup event_tablet
*
* Set the user data associated with a tool object, if any.
*
* @param tool The libinput tool
* @param user_data The user data to associate with the tool object
*/
void
libinput_tablet_tool_set_user_data(struct libinput_tablet_tool *tool,
void *user_data);
/**
* @defgroup base Initialization and manipulation of libinput contexts
*/

View file

@ -124,6 +124,7 @@ global:
libinput_udev_assign_seat;
libinput_udev_create_context;
libinput_unref;
local:
*;
};
@ -184,4 +185,52 @@ LIBINPUT_1.2 {
libinput_device_config_tap_get_drag_enabled;
libinput_device_config_tap_get_default_drag_enabled;
libinput_device_config_tap_set_drag_enabled;
libinput_event_get_tablet_tool_event;
libinput_event_tablet_tool_x_has_changed;
libinput_event_tablet_tool_y_has_changed;
libinput_event_tablet_tool_pressure_has_changed;
libinput_event_tablet_tool_distance_has_changed;
libinput_event_tablet_tool_rotation_has_changed;
libinput_event_tablet_tool_tilt_x_has_changed;
libinput_event_tablet_tool_tilt_y_has_changed;
libinput_event_tablet_tool_wheel_has_changed;
libinput_event_tablet_tool_slider_has_changed;
libinput_event_tablet_tool_get_dx;
libinput_event_tablet_tool_get_dy;
libinput_event_tablet_tool_get_x;
libinput_event_tablet_tool_get_y;
libinput_event_tablet_tool_get_pressure;
libinput_event_tablet_tool_get_distance;
libinput_event_tablet_tool_get_tilt_x;
libinput_event_tablet_tool_get_tilt_y;
libinput_event_tablet_tool_get_rotation;
libinput_event_tablet_tool_get_slider_position;
libinput_event_tablet_tool_get_wheel_delta;
libinput_event_tablet_tool_get_wheel_delta_discrete;
libinput_event_tablet_tool_get_base_event;
libinput_event_tablet_tool_get_button;
libinput_event_tablet_tool_get_button_state;
libinput_event_tablet_tool_get_proximity_state;
libinput_event_tablet_tool_get_seat_button_count;
libinput_event_tablet_tool_get_time;
libinput_event_tablet_tool_get_tip_state;
libinput_event_tablet_tool_get_tool;
libinput_event_tablet_tool_get_x_transformed;
libinput_event_tablet_tool_get_y_transformed;
libinput_event_tablet_tool_get_time_usec;
libinput_tablet_tool_get_serial;
libinput_tablet_tool_get_tool_id;
libinput_tablet_tool_get_type;
libinput_tablet_tool_get_user_data;
libinput_tablet_tool_has_pressure;
libinput_tablet_tool_has_distance;
libinput_tablet_tool_has_rotation;
libinput_tablet_tool_has_tilt;
libinput_tablet_tool_has_wheel;
libinput_tablet_tool_has_slider;
libinput_tablet_tool_has_button;
libinput_tablet_tool_is_unique;
libinput_tablet_tool_ref;
libinput_tablet_tool_set_user_data;
libinput_tablet_tool_unref;
} LIBINPUT_1.1;

View file

@ -22,6 +22,7 @@ liblitest_la_SOURCES = \
litest-device-bcm5974.c \
litest-device-elantech-touchpad.c \
litest-device-generic-singletouch.c \
litest-device-huion-pentablet.c \
litest-device-keyboard.c \
litest-device-keyboard-razer-blackwidow.c \
litest-device-logitech-trackball.c \
@ -41,8 +42,13 @@ liblitest_la_SOURCES = \
litest-device-synaptics-x1-carbon-3rd.c \
litest-device-trackpoint.c \
litest-device-touch-screen.c \
litest-device-wacom-bamboo-tablet.c \
litest-device-wacom-cintiq-tablet.c \
litest-device-wacom-intuos-tablet.c \
litest-device-wacom-isdv4-tablet.c \
litest-device-wacom-touch.c \
litest-device-wacom-intuos-finger.c \
litest-device-waltop-tablet.c \
litest-device-wheel-only.c \
litest-device-xen-virtual-pointer.c \
litest-device-vmware-virtual-usb-mouse.c \
@ -61,6 +67,7 @@ run_tests = \
test-touchpad \
test-touchpad-tap \
test-touchpad-buttons \
test-tablet \
test-device \
test-gestures \
test-pointer \
@ -105,6 +112,10 @@ test_log_SOURCES = log.c
test_log_LDADD = $(TEST_LIBS)
test_log_LDFLAGS = -no-install
test_tablet_SOURCES = tablet.c
test_tablet_LDADD = $(TEST_LIBS)
test_tablet_LDFLAGS = -static
test_touchpad_SOURCES = touchpad.c
test_touchpad_LDADD = $(TEST_LIBS)
test_touchpad_LDFLAGS = -no-install

View file

@ -1104,6 +1104,22 @@ START_TEST(device_udev_tag_synaptics_serial)
}
END_TEST
START_TEST(device_udev_tag_wacom_tablet)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
struct udev_device *d;
const char *prop;
d = libinput_device_get_udev_device(device);
prop = udev_device_get_property_value(d,
"ID_INPUT_TABLET");
ck_assert_notnull(prop);
udev_device_unref(d);
}
END_TEST
START_TEST(device_nonpointer_rel)
{
struct libevdev_uinput *uinput;
@ -1289,16 +1305,16 @@ litest_setup_tests(void)
struct range abs_range = { 0, ABS_MISC };
struct range abs_mt_range = { ABS_MT_SLOT + 1, ABS_CNT };
litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD);
litest_add("device:sendevents", device_sendevents_config_invalid, LITEST_ANY, LITEST_ANY);
litest_add("device:sendevents", device_sendevents_config_touchpad, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_sendevents_config_touchpad_superset, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_sendevents_config_default, LITEST_ANY, LITEST_ANY);
litest_add("device:sendevents", device_disable, LITEST_RELATIVE, LITEST_ANY);
litest_add("device:sendevents", device_disable_touchpad, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_disable_events_pending, LITEST_RELATIVE, LITEST_TOUCHPAD);
litest_add("device:sendevents", device_double_disable, LITEST_ANY, LITEST_ANY);
litest_add("device:sendevents", device_double_enable, LITEST_ANY, LITEST_ANY);
litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_invalid, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_touchpad, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_touchpad_superset, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_default, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_disable, LITEST_RELATIVE, LITEST_TABLET);
litest_add("device:sendevents", device_disable_touchpad, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_disable_events_pending, LITEST_RELATIVE, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_double_disable, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_double_enable, LITEST_ANY, LITEST_TABLET);
litest_add_no_device("device:sendevents", device_reenable_syspath_changed);
litest_add_no_device("device:sendevents", device_reenable_device_removed);
litest_add_for_device("device:sendevents", device_disable_release_buttons, LITEST_MOUSE);
@ -1325,13 +1341,14 @@ litest_setup_tests(void)
litest_add_no_device("device:invalid devices", abs_device_missing_res);
litest_add_no_device("device:invalid devices", abs_mt_device_missing_res);
litest_add("device:wheel", device_wheel_only, LITEST_WHEEL, LITEST_RELATIVE|LITEST_ABSOLUTE);
litest_add("device:wheel", device_wheel_only, LITEST_WHEEL, LITEST_RELATIVE|LITEST_ABSOLUTE|LITEST_TABLET);
litest_add_no_device("device:accelerometer", device_accelerometer);
litest_add("device:udev tags", device_udev_tag_alps, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_wacom, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_apple, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_wacom_tablet, LITEST_TABLET, LITEST_ANY);
litest_add_no_device("device:invalid rel events", device_nonpointer_rel);
litest_add_no_device("device:invalid rel events", device_touchpad_rel);

View file

@ -0,0 +1,113 @@
/*
* Copyright © 2015 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_huion_tablet_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_HUION_TABLET);
litest_set_current_device(d);
}
static struct input_event proximity_in[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event proximity_out[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_Y, .value = 0 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event motion[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static int
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
{
switch (evcode) {
case ABS_PRESSURE:
*value = 100;
return 0;
}
return 1;
}
static struct litest_device_interface interface = {
.tablet_proximity_in_events = proximity_in,
.tablet_proximity_out_events = proximity_out,
.tablet_motion_events = motion,
.get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 40000, 0, 0, 157 },
{ ABS_Y, 0, 25000, 0, 0, 157 },
{ ABS_PRESSURE, 0, 2047, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x3,
.vendor = 0x256c,
.product = 0x6e,
};
static int events[] = {
EV_KEY, BTN_TOOL_PEN,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_STYLUS,
EV_KEY, BTN_STYLUS2,
EV_MSC, MSC_SCAN,
-1, -1,
};
struct litest_test_device litest_huion_tablet_device = {
.type = LITEST_HUION_TABLET,
.features = LITEST_TABLET,
.shortname = "huion-tablet",
.setup = litest_huion_tablet_setup,
.interface = &interface,
.name = "HUION PenTablet Pen",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,119 @@
/*
* Copyright © 2014 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_bamboo_tablet_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_WACOM_BAMBOO);
litest_set_current_device(d);
}
static struct input_event proximity_in[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event proximity_out[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_Y, .value = 0 },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = 0 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event motion[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static int
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
{
switch (evcode) {
case ABS_PRESSURE:
*value = 100;
return 0;
}
return 1;
}
static struct litest_device_interface interface = {
.tablet_proximity_in_events = proximity_in,
.tablet_proximity_out_events = proximity_out,
.tablet_motion_events = motion,
.get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 14720, 4, 0, 100 },
{ ABS_Y, 0, 9200, 4, 0, 100 },
{ ABS_PRESSURE, 0, 1023, 0, 0, 0 },
{ ABS_DISTANCE, 0, 31, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x3,
.vendor = 0x56a,
.product = 0xde,
.version = 0x100,
};
static int events[] = {
EV_KEY, BTN_TOOL_PEN,
EV_KEY, BTN_TOOL_RUBBER,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_STYLUS,
EV_KEY, BTN_STYLUS2,
INPUT_PROP_MAX, INPUT_PROP_POINTER,
-1, -1,
};
struct litest_test_device litest_wacom_bamboo_tablet_device = {
.type = LITEST_WACOM_BAMBOO,
.features = LITEST_TABLET | LITEST_DISTANCE,
.shortname = "wacom-bamboo-tablet",
.setup = litest_wacom_bamboo_tablet_setup,
.interface = &interface,
.name = "Wacom Bamboo 16FG 4x5 Pen",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,158 @@
/*
* Copyright © 2014 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_cintiq_tablet_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_WACOM_CINTIQ);
litest_set_current_device(d);
}
static struct input_event proximity_in[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MISC, .value = 2083 },
{ .type = EV_MSC, .code = MSC_SERIAL, .value = 297797542 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event proximity_out[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_Y, .value = 0 },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = 0 },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = 0 },
{ .type = EV_ABS, .code = ABS_MISC, .value = 0 },
{ .type = EV_MSC, .code = MSC_SERIAL, .value = 297797542 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event motion[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_MSC, .code = MSC_SERIAL, .value = 297797542 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static int
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
{
switch (evcode) {
case ABS_TILT_X:
case ABS_TILT_Y:
*value = 0;
return 0;
case ABS_PRESSURE:
*value = 100;
return 0;
case ABS_DISTANCE:
*value = 0;
return 0;
}
return 1;
}
static struct litest_device_interface interface = {
.tablet_proximity_in_events = proximity_in,
.tablet_proximity_out_events = proximity_out,
.tablet_motion_events = motion,
.get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 53020, 4, 0, 200 },
{ ABS_Y, 0, 33440, 4, 0, 200 },
{ ABS_Z, -900, 899, 0, 0, 0 },
{ ABS_RX, 0, 4096, 0, 0, 0 },
{ ABS_RY, 0, 4096, 0, 0, 0 },
{ ABS_WHEEL, 0, 1023, 0, 0, 0 },
{ ABS_PRESSURE, 0, 1023, 0, 0, 0 },
{ ABS_DISTANCE, 0, 63, 0, 0, 0 },
{ ABS_TILT_X, 0, 127, 0, 0, 0 },
{ ABS_TILT_Y, 0, 127, 0, 0, 0 },
{ ABS_MISC, 0, 0, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x3,
.vendor = 0x56a,
.product = 0xc6,
.version = 0x113,
};
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_9,
EV_KEY, BTN_TOOL_PEN,
EV_KEY, BTN_TOOL_RUBBER,
EV_KEY, BTN_TOOL_BRUSH,
EV_KEY, BTN_TOOL_PENCIL,
EV_KEY, BTN_TOOL_AIRBRUSH,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_STYLUS,
EV_KEY, BTN_STYLUS2,
EV_MSC, MSC_SERIAL,
INPUT_PROP_MAX, INPUT_PROP_DIRECT,
-1, -1,
};
struct litest_test_device litest_wacom_cintiq_tablet_device = {
.type = LITEST_WACOM_CINTIQ,
.features = LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_SERIAL | LITEST_TILT,
.shortname = "wacom-cintiq-tablet",
.setup = litest_wacom_cintiq_tablet_setup,
.interface = &interface,
.name = "Wacom Cintiq 12WX",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,163 @@
/*
* Copyright © 2014 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_intuos_tablet_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_WACOM_INTUOS);
litest_set_current_device(d);
}
static struct input_event proximity_in[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MISC, .value = 1050626 },
{ .type = EV_MSC, .code = MSC_SERIAL, .value = 578837976 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event proximity_out[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_Y, .value = 0 },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = 0 },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = 0 },
{ .type = EV_ABS, .code = ABS_MISC, .value = 0 },
{ .type = EV_MSC, .code = MSC_SERIAL, .value = 578837976 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event motion[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_MSC, .code = MSC_SERIAL, .value = 578837976 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static int
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
{
switch (evcode) {
case ABS_TILT_X:
case ABS_TILT_Y:
*value = 0;
return 0;
case ABS_PRESSURE:
*value = 100;
return 0;
case ABS_DISTANCE:
*value = 0;
return 0;
}
return 1;
}
static struct litest_device_interface interface = {
.tablet_proximity_in_events = proximity_in,
.tablet_proximity_out_events = proximity_out,
.tablet_motion_events = motion,
.get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 44704, 4, 0, 200 },
{ ABS_Y, 0, 27940, 4, 0, 200 },
{ ABS_Z, -900, 899, 0, 0, 0 },
{ ABS_THROTTLE, -1023, 1023, 0, 0, 0 },
{ ABS_WHEEL, 0, 1023, 0, 0, 0 },
{ ABS_PRESSURE, 0, 2047, 0, 0, 0 },
{ ABS_DISTANCE, 0, 63, 0, 0, 0 },
{ ABS_TILT_X, 0, 127, 0, 0, 0 },
{ ABS_TILT_Y, 0, 127, 0, 0, 0 },
{ ABS_MISC, 0, 0, 0, 0, 0 },
{ .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_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_KEY, BTN_SIDE,
EV_KEY, BTN_EXTRA,
EV_KEY, BTN_TOOL_PEN,
EV_KEY, BTN_TOOL_RUBBER,
EV_KEY, BTN_TOOL_BRUSH,
EV_KEY, BTN_TOOL_PENCIL,
EV_KEY, BTN_TOOL_AIRBRUSH,
EV_KEY, BTN_TOOL_MOUSE,
EV_KEY, BTN_TOOL_LENS,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_STYLUS,
EV_KEY, BTN_STYLUS2,
EV_REL, REL_WHEEL,
EV_MSC, MSC_SERIAL,
INPUT_PROP_MAX, INPUT_PROP_POINTER,
-1, -1,
};
struct litest_test_device litest_wacom_intuos_tablet_device = {
.type = LITEST_WACOM_INTUOS,
.features = LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_SERIAL | LITEST_TILT,
.shortname = "wacom-intuos-tablet",
.setup = litest_wacom_intuos_tablet_setup,
.interface = &interface,
.name = "Wacom Intuos5 touch M Pen",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,112 @@
/*
* Copyright © 2014 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_isdv4_tablet_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_WACOM_ISDV4);
litest_set_current_device(d);
}
static struct input_event proximity_in[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event proximity_out[] = {
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event motion[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static int
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
{
switch (evcode) {
case ABS_PRESSURE:
*value = 100;
return 0;
}
return 1;
}
static struct litest_device_interface interface = {
.tablet_proximity_in_events = proximity_in,
.tablet_proximity_out_events = proximity_out,
.tablet_motion_events = motion,
.get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 27760, 4, 0, 100 },
{ ABS_Y, 0, 15694, 4, 0, 100 },
{ ABS_PRESSURE, 0, 255, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x3,
.vendor = 0x56a,
.product = 0xe6,
};
static int events[] = {
EV_KEY, BTN_TOOL_PEN,
EV_KEY, BTN_TOOL_RUBBER,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_STYLUS,
EV_KEY, BTN_STYLUS2,
INPUT_PROP_MAX, INPUT_PROP_DIRECT,
-1, -1,
};
struct litest_test_device litest_wacom_isdv4_tablet_device = {
.type = LITEST_WACOM_ISDV4,
.features = LITEST_TABLET,
.shortname = "wacom-isdv4-tablet",
.setup = litest_wacom_isdv4_tablet_setup,
.interface = &interface,
.name = "Wacom ISDv4 E6 Pen",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,241 @@
/*
* Copyright © 2014 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_waltop_tablet_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_WALTOP);
litest_set_current_device(d);
}
static struct input_event proximity_in[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event proximity_out[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_Y, .value = 0 },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = 0 },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = 0 },
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event motion[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static int
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
{
switch (evcode) {
case ABS_TILT_X:
case ABS_TILT_Y:
*value = 0;
return 0;
case ABS_PRESSURE:
*value = 100;
return 0;
}
return 1;
}
static struct litest_device_interface interface = {
.tablet_proximity_in_events = proximity_in,
.tablet_proximity_out_events = proximity_out,
.tablet_motion_events = motion,
.get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 32000, 0, 0, 0 },
{ ABS_Y, 0, 32000, 0, 0, 0 },
{ ABS_PRESSURE, 0, 2047, 0, 0, 0 },
{ ABS_TILT_X, -127, 127, 0, 0, 0 },
{ ABS_TILT_Y, -127, 127, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x3,
.vendor = 0x172f,
.product = 0x509,
};
static int events[] = {
EV_KEY, KEY_ESC,
EV_KEY, KEY_1,
EV_KEY, KEY_2,
EV_KEY, KEY_3,
EV_KEY, KEY_4,
EV_KEY, KEY_5,
EV_KEY, KEY_6,
EV_KEY, KEY_7,
EV_KEY, KEY_8,
EV_KEY, KEY_9,
EV_KEY, KEY_0,
EV_KEY, KEY_MINUS,
EV_KEY, KEY_EQUAL,
EV_KEY, KEY_BACKSPACE,
EV_KEY, KEY_TAB,
EV_KEY, KEY_Q,
EV_KEY, KEY_W,
EV_KEY, KEY_E,
EV_KEY, KEY_R,
EV_KEY, KEY_T,
EV_KEY, KEY_Y,
EV_KEY, KEY_U,
EV_KEY, KEY_I,
EV_KEY, KEY_O,
EV_KEY, KEY_P,
EV_KEY, KEY_LEFTBRACE,
EV_KEY, KEY_RIGHTBRACE,
EV_KEY, KEY_ENTER,
EV_KEY, KEY_LEFTCTRL,
EV_KEY, KEY_A,
EV_KEY, KEY_S,
EV_KEY, KEY_D,
EV_KEY, KEY_F,
EV_KEY, KEY_G,
EV_KEY, KEY_H,
EV_KEY, KEY_J,
EV_KEY, KEY_K,
EV_KEY, KEY_L,
EV_KEY, KEY_SEMICOLON,
EV_KEY, KEY_APOSTROPHE,
EV_KEY, KEY_GRAVE,
EV_KEY, KEY_LEFTSHIFT,
EV_KEY, KEY_BACKSLASH,
EV_KEY, KEY_Z,
EV_KEY, KEY_X,
EV_KEY, KEY_C,
EV_KEY, KEY_V,
EV_KEY, KEY_B,
EV_KEY, KEY_N,
EV_KEY, KEY_M,
EV_KEY, KEY_COMMA,
EV_KEY, KEY_DOT,
EV_KEY, KEY_SLASH,
EV_KEY, KEY_RIGHTSHIFT,
EV_KEY, KEY_KPASTERISK,
EV_KEY, KEY_LEFTALT,
EV_KEY, KEY_SPACE,
EV_KEY, KEY_CAPSLOCK,
EV_KEY, KEY_F1,
EV_KEY, KEY_F2,
EV_KEY, KEY_F3,
EV_KEY, KEY_F4,
EV_KEY, KEY_F5,
EV_KEY, KEY_F6,
EV_KEY, KEY_F7,
EV_KEY, KEY_F8,
EV_KEY, KEY_F9,
EV_KEY, KEY_F10,
EV_KEY, KEY_NUMLOCK,
EV_KEY, KEY_SCROLLLOCK,
EV_KEY, KEY_KP7,
EV_KEY, KEY_KP8,
EV_KEY, KEY_KP9,
EV_KEY, KEY_KPMINUS,
EV_KEY, KEY_KP4,
EV_KEY, KEY_KP5,
EV_KEY, KEY_KP6,
EV_KEY, KEY_KPPLUS,
EV_KEY, KEY_KP1,
EV_KEY, KEY_KP2,
EV_KEY, KEY_KP3,
EV_KEY, KEY_KP0,
EV_KEY, KEY_KPDOT,
EV_KEY, KEY_102ND,
EV_KEY, KEY_F11,
EV_KEY, KEY_F12,
EV_KEY, KEY_KPENTER,
EV_KEY, KEY_RIGHTCTRL,
EV_KEY, KEY_KPSLASH,
EV_KEY, KEY_SYSRQ,
EV_KEY, KEY_RIGHTALT,
EV_KEY, KEY_HOME,
EV_KEY, KEY_UP,
EV_KEY, KEY_PAGEUP,
EV_KEY, KEY_LEFT,
EV_KEY, KEY_RIGHT,
EV_KEY, KEY_END,
EV_KEY, KEY_DOWN,
EV_KEY, KEY_PAGEDOWN,
EV_KEY, KEY_INSERT,
EV_KEY, KEY_DELETE,
EV_KEY, KEY_MUTE,
EV_KEY, KEY_VOLUMEDOWN,
EV_KEY, KEY_VOLUMEUP,
EV_KEY, KEY_PAUSE,
EV_KEY, KEY_LEFTMETA,
EV_KEY, KEY_RIGHTMETA,
EV_KEY, KEY_COMPOSE,
EV_KEY, BTN_0,
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_KEY, BTN_SIDE,
EV_KEY, BTN_EXTRA,
EV_KEY, BTN_TOOL_PEN,
EV_KEY, BTN_TOOL_RUBBER,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_STYLUS,
EV_REL, REL_HWHEEL,
EV_REL, REL_WHEEL,
EV_MSC, MSC_SERIAL,
-1, -1,
};
struct litest_test_device litest_waltop_tablet_device = {
.type = LITEST_WALTOP,
.features = LITEST_TABLET | LITEST_WHEEL | LITEST_TILT,
.shortname = "waltop-tablet",
.setup = litest_waltop_tablet_setup,
.interface = &interface,
.name = " WALTOP Batteryless Tablet ", /* sic */
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -97,6 +97,14 @@ struct litest_device_interface {
struct input_event *touch_move_events;
struct input_event *touch_up_events;
/**
* Tablet events, LITEST_AUTO_ASSIGN is allowed on event values for
* ABS_X, ABS_Y, ABS_DISTANCE and ABS_PRESSURE.
*/
struct input_event *tablet_proximity_in_events;
struct input_event *tablet_proximity_out_events;
struct input_event *tablet_motion_events;
int min[2]; /* x/y axis minimum */
int max[2]; /* x/y axis maximum */
};

View file

@ -344,6 +344,10 @@ extern struct litest_test_device litest_trackpoint_device;
extern struct litest_test_device litest_bcm5974_device;
extern struct litest_test_device litest_mouse_device;
extern struct litest_test_device litest_wacom_touch_device;
extern struct litest_test_device litest_wacom_bamboo_tablet_device;
extern struct litest_test_device litest_wacom_cintiq_tablet_device;
extern struct litest_test_device litest_wacom_intuos_tablet_device;
extern struct litest_test_device litest_wacom_isdv4_tablet_device;
extern struct litest_test_device litest_alps_device;
extern struct litest_test_device litest_generic_singletouch_device;
extern struct litest_test_device litest_qemu_tablet_device;
@ -369,6 +373,8 @@ extern struct litest_test_device litest_mouse_gladius_device;
extern struct litest_test_device litest_mouse_wheel_click_angle_device;
extern struct litest_test_device litest_apple_keyboard_device;
extern struct litest_test_device litest_anker_mouse_kbd_device;
extern struct litest_test_device litest_waltop_tablet_device;
extern struct litest_test_device litest_huion_tablet_device;
struct litest_test_device* devices[] = {
&litest_synaptics_clickpad_device,
@ -379,6 +385,10 @@ struct litest_test_device* devices[] = {
&litest_bcm5974_device,
&litest_mouse_device,
&litest_wacom_touch_device,
&litest_wacom_bamboo_tablet_device,
&litest_wacom_cintiq_tablet_device,
&litest_wacom_intuos_tablet_device,
&litest_wacom_isdv4_tablet_device,
&litest_alps_device,
&litest_generic_singletouch_device,
&litest_qemu_tablet_device,
@ -404,6 +414,8 @@ struct litest_test_device* devices[] = {
&litest_mouse_wheel_click_angle_device,
&litest_apple_keyboard_device,
&litest_anker_mouse_kbd_device,
&litest_waltop_tablet_device,
&litest_huion_tablet_device,
NULL,
};
@ -1492,6 +1504,82 @@ litest_touch_move_to(struct litest_device *d,
litest_touch_move(d, slot, x_to, y_to);
}
static int
auto_assign_tablet_value(struct litest_device *d,
const struct input_event *ev,
int x, int y,
struct axis_replacement *axes)
{
int value = ev->value;
if (value != LITEST_AUTO_ASSIGN || ev->type != EV_ABS)
return value;
switch (ev->code) {
case ABS_X:
value = litest_scale(d, ABS_X, x);
break;
case ABS_Y:
value = litest_scale(d, ABS_Y, y);
break;
default:
if (!axis_replacement_value(d, axes, ev->code, &value) &&
d->interface->get_axis_default)
d->interface->get_axis_default(d, ev->code, &value);
break;
}
return value;
}
static int
tablet_ignore_event(const struct input_event *ev, int value)
{
return value == -1 && (ev->code == ABS_PRESSURE || ev->code == ABS_DISTANCE);
}
void
litest_tablet_proximity_in(struct litest_device *d, int x, int y, struct axis_replacement *axes)
{
struct input_event *ev;
ev = d->interface->tablet_proximity_in_events;
while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
int value = auto_assign_tablet_value(d, ev, x, y, axes);
if (!tablet_ignore_event(ev, value))
litest_event(d, ev->type, ev->code, value);
ev++;
}
}
void
litest_tablet_proximity_out(struct litest_device *d)
{
struct input_event *ev;
ev = d->interface->tablet_proximity_out_events;
while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
int value = auto_assign_tablet_value(d, ev, -1, -1, NULL);
if (!tablet_ignore_event(ev, value))
litest_event(d, ev->type, ev->code, value);
ev++;
}
}
void
litest_tablet_motion(struct litest_device *d, int x, int y, struct axis_replacement *axes)
{
struct input_event *ev;
ev = d->interface->tablet_motion_events;
while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
int value = auto_assign_tablet_value(d, ev, x, y, axes);
if (!tablet_ignore_event(ev, value))
litest_event(d, ev->type, ev->code, value);
ev++;
}
}
void
litest_touch_move_two_touches(struct litest_device *d,
double x0, double y0,
@ -1838,6 +1926,18 @@ litest_event_type_str(struct libinput_event *event)
case LIBINPUT_EVENT_GESTURE_PINCH_END:
str = "GESTURE PINCH END";
break;
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
str = "TABLET AXIS";
break;
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
str = "TABLET PROX";
break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
str = "TABLET TIP";
break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
str = "TABLET BUTTON";
break;
}
return str;
}
@ -1846,6 +1946,7 @@ static void
litest_print_event(struct libinput_event *event)
{
struct libinput_event_pointer *p;
struct libinput_event_tablet_tool *t;
struct libinput_device *dev;
enum libinput_event_type type;
double x, y;
@ -1891,6 +1992,22 @@ litest_print_event(struct libinput_event *event)
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
fprintf(stderr, "vert %.f horiz %.2f", y, x);
break;
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
t = libinput_event_get_tablet_tool_event(event);
fprintf(stderr, "proximity %d\n",
libinput_event_tablet_tool_get_proximity_state(t));
break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
t = libinput_event_get_tablet_tool_event(event);
fprintf(stderr, "tip %d\n",
libinput_event_tablet_tool_get_tip_state(t));
break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
t = libinput_event_get_tablet_tool_event(event);
fprintf(stderr, "button %d state %d\n",
libinput_event_tablet_tool_get_button(t),
libinput_event_tablet_tool_get_button_state(t));
break;
default:
break;
}
@ -2258,6 +2375,60 @@ litest_is_gesture_event(struct libinput_event *event,
return gevent;
}
struct libinput_event_tablet_tool * litest_is_tablet_event(
struct libinput_event *event,
enum libinput_event_type type)
{
struct libinput_event_tablet_tool *tevent;
litest_assert(event != NULL);
litest_assert_int_eq(libinput_event_get_type(event), type);
tevent = libinput_event_get_tablet_tool_event(event);
litest_assert(tevent != NULL);
return tevent;
}
void
litest_assert_tablet_button_event(struct libinput *li, unsigned int button,
enum libinput_button_state state)
{
struct libinput_event *event;
struct libinput_event_tablet_tool *tev;
enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_BUTTON;
litest_wait_for_event(li);
event = libinput_get_event(li);
litest_assert_notnull(event);
litest_assert_int_eq(libinput_event_get_type(event), type);
tev = libinput_event_get_tablet_tool_event(event);
litest_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
button);
litest_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
state);
libinput_event_destroy(event);
}
void litest_assert_tablet_proximity_event(struct libinput *li,
enum libinput_tablet_tool_proximity_state state)
{
struct libinput_event *event;
struct libinput_event_tablet_tool *tev;
enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY;
litest_wait_for_event(li);
event = libinput_get_event(li);
litest_assert_notnull(event);
litest_assert_int_eq(libinput_event_get_type(event), type);
tev = libinput_event_get_tablet_tool_event(event);
litest_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
state);
libinput_event_destroy(event);
}
void
litest_assert_scroll(struct libinput *li,
enum libinput_pointer_axis axis,

View file

@ -35,6 +35,28 @@
#include <libinput.h>
#include <math.h>
void
litest_fail_condition(const char *file,
int line,
const char *func,
const char *condition,
const char *message,
...);
void
litest_fail_comparison_int(const char *file,
int line,
const char *func,
const char *operator,
int a,
int b,
const char *astr,
const char *bstr);
void
litest_fail_comparison_ptr(const char *file,
int line,
const char *func,
const char *comparison);
#define litest_assert(cond) \
do { \
if (!(cond)) \
@ -111,6 +133,24 @@
#define litest_assert_ptr_notnull(a_) \
litest_assert_comparison_ptr_(a_, !=, NULL)
#define litest_assert_double_eq(a_, b_)\
ck_assert_int_eq((int)((a_) * 256), (int)((b_) * 256))
#define litest_assert_double_ne(a_, b_)\
ck_assert_int_ne((int)((a_) * 256), (int)((b_) * 256))
#define litest_assert_double_lt(a_, b_)\
ck_assert_int_lt((int)((a_) * 256), (int)((b_) * 256))
#define litest_assert_double_le(a_, b_)\
ck_assert_int_le((int)((a_) * 256), (int)((b_) * 256))
#define litest_assert_double_gt(a_, b_)\
ck_assert_int_gt((int)((a_) * 256), (int)((b_) * 256))
#define litest_assert_double_ge(a_, b_)\
ck_assert_int_ge((int)((a_) * 256), (int)((b_) * 256))
enum litest_device_type {
LITEST_NO_DEVICE = -1,
LITEST_SYNAPTICS_CLICKPAD = -2,
@ -146,6 +186,12 @@ enum litest_device_type {
LITEST_MOUSE_WHEEL_CLICK_ANGLE = -32,
LITEST_APPLE_KEYBOARD = -33,
LITEST_ANKER_MOUSE_KBD = -34,
LITEST_WACOM_BAMBOO = -35,
LITEST_WACOM_CINTIQ = -36,
LITEST_WACOM_INTUOS = -37,
LITEST_WACOM_ISDV4 = -38,
LITEST_WALTOP = -39,
LITEST_HUION_TABLET = -40,
};
enum litest_device_feature {
@ -168,6 +214,10 @@ enum litest_device_feature {
LITEST_PROTOCOL_A = 1 << 14,
LITEST_HOVER = 1 << 15,
LITEST_ELLIPSE = 1 << 16,
LITEST_TABLET = 1 << 17,
LITEST_DISTANCE = 1 << 18,
LITEST_TOOL_SERIAL = 1 << 19,
LITEST_TILT = 1 << 20,
};
struct litest_device {
@ -188,9 +238,27 @@ struct litest_device {
struct axis_replacement {
int32_t evcode;
int32_t value;
double value;
};
static inline void litest_axis_set_value(struct axis_replacement *axes,
int code,
double value)
{
litest_assert_double_ge(value, 0.0);
litest_assert_double_le(value, 100.0);
while (axes->evcode != -1) {
if (axes->evcode == code) {
axes->value = value;
return;
}
axes++;
}
litest_abort_msg("Missing axis code %d\n", code);
}
/* A loop range, resolves to:
for (i = lower; i < upper; i++)
*/
@ -203,28 +271,6 @@ struct libinput *litest_create_context(void);
void litest_disable_log_handler(struct libinput *libinput);
void litest_restore_log_handler(struct libinput *libinput);
void
litest_fail_condition(const char *file,
int line,
const char *func,
const char *condition,
const char *message,
...);
void
litest_fail_comparison_int(const char *file,
int line,
const char *func,
const char *operator,
int a,
int b,
const char *astr,
const char *bstr);
void
litest_fail_comparison_ptr(const char *file,
int line,
const char *func,
const char *comparison);
#define litest_add(name_, func_, ...) \
_litest_add(name_, #func_, func_, __VA_ARGS__)
#define litest_add_ranged(name_, func_, ...) \
@ -336,6 +382,15 @@ void litest_touch_move_three_touches(struct litest_device *d,
double x2, double y2,
double dx, double dy,
int steps, int sleep_ms);
void litest_tablet_proximity_in(struct litest_device *d,
int x, int y,
struct axis_replacement *axes);
void litest_tablet_proximity_out(struct litest_device *d);
void litest_tablet_motion(struct litest_device *d,
int x, int y,
struct axis_replacement *axes);
void litest_hover_start(struct litest_device *d,
unsigned int slot,
double x,
@ -389,6 +444,9 @@ struct libinput_event_gesture * litest_is_gesture_event(
struct libinput_event *event,
enum libinput_event_type type,
int nfingers);
struct libinput_event_tablet_tool * litest_is_tablet_event(
struct libinput_event *event,
enum libinput_event_type type);
void litest_assert_button_event(struct libinput *li,
unsigned int button,
@ -398,7 +456,11 @@ void litest_assert_scroll(struct libinput *li,
int minimum_movement);
void litest_assert_only_typed_events(struct libinput *li,
enum libinput_event_type type);
void litest_assert_tablet_button_event(struct libinput *li,
unsigned int button,
enum libinput_button_state state);
void litest_assert_tablet_proximity_event(struct libinput *li,
enum libinput_tablet_tool_proximity_state state);
struct libevdev_uinput * litest_create_uinput_device(const char *name,
struct input_id *id,
...);
@ -406,24 +468,6 @@ struct libevdev_uinput * litest_create_uinput_abs_device(const char *name,
struct input_id *id,
const struct input_absinfo *abs,
...);
#define litest_assert_double_eq(a_, b_)\
ck_assert_int_eq((int)(a_ * 256), (int)(b_ * 256))
#define litest_assert_double_ne(a_, b_)\
ck_assert_int_ne((int)(a_ * 256), (int)(b_ * 256))
#define litest_assert_double_lt(a_, b_)\
ck_assert_int_lt((int)(a_ * 256), (int)(b_ * 256))
#define litest_assert_double_le(a_, b_)\
ck_assert_int_le((int)(a_ * 256), (int)(b_ * 256))
#define litest_assert_double_gt(a_, b_)\
ck_assert_int_gt((int)(a_ * 256), (int)(b_ * 256))
#define litest_assert_double_ge(a_, b_)\
ck_assert_int_ge((int)(a_ * 256), (int)(b_ * 256))
void litest_timeout_tap(void);
void litest_timeout_tapndrag(void);
void litest_timeout_softbuttons(void);

View file

@ -31,6 +31,7 @@
#include <unistd.h>
#include "litest.h"
#include "libinput-util.h"
static int open_restricted(const char *path, int flags, void *data)
{
@ -132,6 +133,7 @@ START_TEST(event_conversion_device_notify)
ck_assert(libinput_event_get_keyboard_event(event) == NULL);
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);
litest_restore_log_handler(li);
}
@ -187,6 +189,7 @@ START_TEST(event_conversion_pointer)
ck_assert(libinput_event_get_keyboard_event(event) == NULL);
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);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@ -236,6 +239,7 @@ START_TEST(event_conversion_pointer_abs)
ck_assert(libinput_event_get_keyboard_event(event) == NULL);
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);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@ -278,6 +282,7 @@ START_TEST(event_conversion_key)
ck_assert(libinput_event_get_pointer_event(event) == NULL);
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);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@ -327,6 +332,7 @@ START_TEST(event_conversion_touch)
ck_assert(libinput_event_get_pointer_event(event) == NULL);
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);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@ -384,6 +390,89 @@ START_TEST(event_conversion_gesture)
}
END_TEST
START_TEST(event_conversion_tablet)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
int events = 0;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
litest_tablet_proximity_in(dev, 50, 50, axes);
litest_tablet_motion(dev, 60, 50, axes);
litest_button_click(dev, BTN_STYLUS, true);
litest_button_click(dev, BTN_STYLUS, false);
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_TOOL_AXIS &&
type <= LIBINPUT_EVENT_TABLET_TOOL_BUTTON) {
struct libinput_event_tablet_tool *t;
struct libinput_event *base;
t = libinput_event_get_tablet_tool_event(event);
base = libinput_event_tablet_tool_get_base_event(t);
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);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
}
ck_assert_int_gt(events, 0);
}
END_TEST
START_TEST(bitfield_helpers)
{
/* This value has a bit set on all of the word boundaries we want to
* test: 0, 1, 7, 8, 31, 32, and 33
*/
unsigned char read_bitfield[] = { 0x83, 0x1, 0x0, 0x80, 0x3 };
unsigned char write_bitfield[ARRAY_LENGTH(read_bitfield)] = {0};
size_t i;
/* Now check that the bitfield we wrote to came out to be the same as
* the bitfield we were writing from */
for (i = 0; i < ARRAY_LENGTH(read_bitfield) * 8; i++) {
switch (i) {
case 0:
case 1:
case 7:
case 8:
case 31:
case 32:
case 33:
ck_assert(bit_is_set(read_bitfield, i));
set_bit(write_bitfield, i);
break;
default:
ck_assert(!bit_is_set(read_bitfield, i));
clear_bit(write_bitfield, i);
break;
}
}
ck_assert_int_eq(memcmp(read_bitfield,
write_bitfield,
sizeof(read_bitfield)),
0);
}
END_TEST
START_TEST(context_ref_counting)
{
struct libinput *li;
@ -784,6 +873,8 @@ litest_setup_tests(void)
litest_add_for_device("events:conversion", event_conversion_key, LITEST_KEYBOARD);
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_no_device("bitfield_helpers", bitfield_helpers);
litest_add_no_device("context:refcount", context_ref_counting);
litest_add_no_device("config:status string", config_status_string);

View file

@ -1593,14 +1593,14 @@ litest_setup_tests(void)
litest_add("pointer:button", pointer_button, LITEST_BUTTON, LITEST_CLICKPAD);
litest_add_no_device("pointer:button", pointer_button_auto_release);
litest_add_no_device("pointer:button", pointer_seat_button_count);
litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_TABLET);
litest_add("pointer:scroll", pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_nowheel_defaults, LITEST_RELATIVE|LITEST_BUTTON, LITEST_WHEEL);
litest_add("pointer:scroll", pointer_scroll_natural_defaults, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_natural_enable_config, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_natural_wheel, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_natural_defaults, LITEST_WHEEL, LITEST_TABLET);
litest_add("pointer:scroll", pointer_scroll_natural_enable_config, LITEST_WHEEL, LITEST_TABLET);
litest_add("pointer:scroll", pointer_scroll_natural_wheel, LITEST_WHEEL, LITEST_TABLET);
litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE|LITEST_PROTOCOL_A);
litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE|LITEST_PROTOCOL_A|LITEST_TABLET);
/* tests touchpads too */
litest_add("pointer:left-handed", pointer_left_handed_defaults, LITEST_BUTTON, LITEST_ANY);

3479
test/tablet.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,24 @@
...
fun:mtdev_put_event
}
{
<g_type_register_static>
Memcheck:Leak
...
fun:g_type_register_static
}
{
<g_type_register_static>
Memcheck:Leak
...
fun:g_type_register_fundamental
}
{
<g_type_register_static>
Memcheck:Leak
...
fun:g_malloc0
}
{
libunwind:msync_uninitialized_bytes
Memcheck:Param

View file

@ -23,6 +23,7 @@
#define _GNU_SOURCE
#include <errno.h>
#include <inttypes.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
@ -108,9 +109,21 @@ print_event_header(struct libinput_event *ev)
case LIBINPUT_EVENT_GESTURE_PINCH_END:
type = "GESTURE_PINCH_END";
break;
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
type = "TABLET_AXIS";
break;
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
type = "TABLET_PROXIMITY";
break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
type = "TABLET_TIP";
break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
type = "TABLET_BUTTON";
break;
}
printf("%-7s %s ", libinput_device_get_sysname(dev), type);
printf("%-7s %-16s ", libinput_device_get_sysname(dev), type);
}
static void
@ -156,6 +169,9 @@ print_device_notify(struct libinput_event *ev)
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_GESTURE))
printf("g");
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_TABLET_TOOL))
printf("T");
if (libinput_device_get_size(dev, &w, &h) == 0)
printf("\tsize %.2f/%.2fmm", w, h);
@ -251,7 +267,7 @@ print_absmotion_event(struct libinput_event *ev)
}
static void
print_button_event(struct libinput_event *ev)
print_pointer_button_event(struct libinput_event *ev)
{
struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
enum libinput_button_state state;
@ -272,7 +288,34 @@ print_button_event(struct libinput_event *ev)
}
static void
print_axis_event(struct libinput_event *ev)
print_tablet_tip_event(struct libinput_event *ev)
{
struct libinput_event_tablet_tool *p = libinput_event_get_tablet_tool_event(ev);
enum libinput_tablet_tool_tip_state state;
print_event_time(libinput_event_tablet_tool_get_time(p));
state = libinput_event_tablet_tool_get_tip_state(p);
printf("%s\n", state == LIBINPUT_TABLET_TOOL_TIP_DOWN ? "down" : "up");
}
static void
print_tablet_button_event(struct libinput_event *ev)
{
struct libinput_event_tablet_tool *p = libinput_event_get_tablet_tool_event(ev);
enum libinput_button_state state;
print_event_time(libinput_event_tablet_tool_get_time(p));
state = libinput_event_tablet_tool_get_button_state(p);
printf("%3d %s, seat count: %u\n",
libinput_event_tablet_tool_get_button(p),
state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released",
libinput_event_tablet_tool_get_seat_button_count(p));
}
static void
print_pointer_axis_event(struct libinput_event *ev)
{
struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
double v = 0, h = 0;
@ -295,6 +338,75 @@ print_axis_event(struct libinput_event *ev)
printf("vert %.2f%s horiz %.2f%s\n", v, have_vert, h, have_horiz);
}
static void
print_tablet_axes(struct libinput_event_tablet_tool *t)
{
struct libinput_tablet_tool *tool = libinput_event_tablet_tool_get_tool(t);
double x, y;
double dist, pressure;
double rotation, slider, wheel;
double delta;
#define changed_sym(ev, ax) \
(libinput_event_tablet_tool_##ax##_has_changed(ev) ? "*" : "")
x = libinput_event_tablet_tool_get_x(t);
y = libinput_event_tablet_tool_get_x(t);
printf("\t%.2f%s/%.2f%s",
x, changed_sym(t, x),
y, changed_sym(t, y));
if (libinput_tablet_tool_has_tilt(tool)) {
x = libinput_event_tablet_tool_get_tilt_x(t);
y = libinput_event_tablet_tool_get_tilt_y(t);
printf("\ttilt: %.2f%s/%.2f%s",
x, changed_sym(t, tilt_x),
y, changed_sym(t, tilt_y));
}
if (libinput_tablet_tool_has_distance(tool) ||
libinput_tablet_tool_has_pressure(tool)) {
dist = libinput_event_tablet_tool_get_distance(t);
pressure = libinput_event_tablet_tool_get_pressure(t);
if (dist)
printf("\tdistance: %.2f%s",
dist, changed_sym(t, distance));
else
printf("\tpressure: %.2f%s",
pressure, changed_sym(t, pressure));
}
if (libinput_tablet_tool_has_rotation(tool)) {
rotation = libinput_event_tablet_tool_get_rotation(t);
printf("\trotation: %.2f%s",
rotation, changed_sym(t, rotation));
}
if (libinput_tablet_tool_has_slider(tool)) {
slider = libinput_event_tablet_tool_get_slider_position(t);
printf("\tslider: %.2f%s",
slider, changed_sym(t, slider));
}
if (libinput_tablet_tool_has_wheel(tool)) {
wheel = libinput_event_tablet_tool_get_wheel_delta(t);
delta = libinput_event_tablet_tool_get_wheel_delta_discrete(t);
printf("\twheel: %.2f%s (%d)",
wheel, changed_sym(t, wheel),
(int)delta);
}
}
static void
print_tablet_axis_event(struct libinput_event *ev)
{
struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev);
print_event_time(libinput_event_tablet_tool_get_time(t));
print_tablet_axes(t);
printf("\n");
}
static void
print_touch_event_without_coords(struct libinput_event *ev)
{
@ -304,6 +416,96 @@ print_touch_event_without_coords(struct libinput_event *ev)
printf("\n");
}
static void
print_proximity_event(struct libinput_event *ev)
{
struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev);
struct libinput_tablet_tool *tool = libinput_event_tablet_tool_get_tool(t);
enum libinput_tablet_tool_proximity_state state;
const char *tool_str,
*state_str;
switch (libinput_tablet_tool_get_type(tool)) {
case LIBINPUT_TABLET_TOOL_TYPE_PEN:
tool_str = "pen";
break;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
tool_str = "eraser";
break;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
tool_str = "brush";
break;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
tool_str = "pencil";
break;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
tool_str = "airbrush";
break;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
tool_str = "mouse";
break;
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
tool_str = "lens";
break;
default:
abort();
}
state = libinput_event_tablet_tool_get_proximity_state(t);
print_event_time(libinput_event_tablet_tool_get_time(t));
if (state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) {
print_tablet_axes(t);
state_str = "proximity-in";
} else if (state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
state_str = "proximity-out";
printf("\t");
} else {
abort();
}
printf("\t%s (%#" PRIx64 ", id %#" PRIx64 ") %s",
tool_str,
libinput_tablet_tool_get_serial(tool),
libinput_tablet_tool_get_tool_id(tool),
state_str);
printf("\taxes:");
if (libinput_tablet_tool_has_distance(tool))
printf("d");
if (libinput_tablet_tool_has_pressure(tool))
printf("p");
if (libinput_tablet_tool_has_tilt(tool))
printf("t");
if (libinput_tablet_tool_has_rotation(tool))
printf("r");
if (libinput_tablet_tool_has_slider(tool))
printf("s");
if (libinput_tablet_tool_has_wheel(tool))
printf("w");
printf("\tbtn:");
if (libinput_tablet_tool_has_button(tool, BTN_TOUCH))
printf("T");
if (libinput_tablet_tool_has_button(tool, BTN_STYLUS))
printf("S");
if (libinput_tablet_tool_has_button(tool, BTN_STYLUS2))
printf("S2");
if (libinput_tablet_tool_has_button(tool, BTN_LEFT))
printf("L");
if (libinput_tablet_tool_has_button(tool, BTN_MIDDLE))
printf("M");
if (libinput_tablet_tool_has_button(tool, BTN_RIGHT))
printf("R");
if (libinput_tablet_tool_has_button(tool, BTN_SIDE))
printf("Sd");
if (libinput_tablet_tool_has_button(tool, BTN_EXTRA))
printf("Ex");
printf("\n");
}
static void
print_touch_event_with_coords(struct libinput_event *ev)
{
@ -395,10 +597,10 @@ handle_and_print_events(struct libinput *li)
print_absmotion_event(ev);
break;
case LIBINPUT_EVENT_POINTER_BUTTON:
print_button_event(ev);
print_pointer_button_event(ev);
break;
case LIBINPUT_EVENT_POINTER_AXIS:
print_axis_event(ev);
print_pointer_axis_event(ev);
break;
case LIBINPUT_EVENT_TOUCH_DOWN:
print_touch_event_with_coords(ev);
@ -433,6 +635,18 @@ handle_and_print_events(struct libinput *li)
case LIBINPUT_EVENT_GESTURE_PINCH_END:
print_gesture_event_without_coords(ev);
break;
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
print_tablet_axis_event(ev);
break;
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
print_proximity_event(ev);
break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
print_tablet_tip_event(ev);
break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
print_tablet_button_event(ev);
break;
}
libinput_event_destroy(ev);

View file

@ -51,6 +51,10 @@ struct touch {
int x, y;
};
struct point {
double x, y;
};
struct window {
GtkWidget *win;
GtkWidget *area;
@ -85,6 +89,22 @@ struct window {
double x, y;
} pinch;
struct {
double x, y;
double x_in, y_in;
double x_down, y_down;
double x_up, y_up;
double pressure;
double distance;
double tilt_x, tilt_y;
/* these are for the delta coordinates, but they're not
* deltas, theyconverted into
* abs positions */
size_t ndeltas;
struct point deltas[64];
} tool;
struct libinput_device *devices[50];
};
@ -118,6 +138,8 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data)
struct window *w = data;
struct touch *t;
int i, offset;
int first, last, mask;
double x, y;
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_rectangle(cr, 0, 0, w->width, w->height);
@ -216,6 +238,61 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data)
cairo_stroke(cr);
cairo_restore(cr);
/* tablet tool, square for prox-in location */
cairo_save(cr);
cairo_set_source_rgb(cr, .8, .8, .8);
if (w->tool.x_in && w->tool.y_in) {
cairo_rectangle(cr, w->tool.x_in - 15, w->tool.y_in - 15, 30, 30);
cairo_stroke(cr);
cairo_restore(cr);
cairo_save(cr);
}
if (w->tool.x_down && w->tool.y_down) {
cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20);
cairo_stroke(cr);
cairo_restore(cr);
cairo_save(cr);
}
if (w->tool.x_up && w->tool.y_up) {
cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20);
cairo_stroke(cr);
cairo_restore(cr);
cairo_save(cr);
}
if (w->tool.pressure)
cairo_set_source_rgb(cr, .8, .8, .2);
cairo_translate(cr, w->tool.x, w->tool.y);
cairo_scale(cr, 1.0 + w->tool.tilt_x, 1.0 + w->tool.tilt_y);
cairo_arc(cr, 0, 0,
1 + 10 * max(w->tool.pressure, w->tool.distance),
0, 2 * M_PI);
cairo_fill(cr);
cairo_restore(cr);
/* tablet deltas */
mask = ARRAY_LENGTH(w->tool.deltas);
first = max(w->tool.ndeltas + 1, mask) - mask;
last = w->tool.ndeltas;
cairo_save(cr);
cairo_set_source_rgb(cr, .8, .8, .2);
x = w->tool.deltas[first % mask].x;
y = w->tool.deltas[first % mask].y;
cairo_move_to(cr, x, y);
for (i = first + 1; i < last; i++) {
x = w->tool.deltas[i % mask].x;
y = w->tool.deltas[i % mask].y;
cairo_line_to(cr, x, y);
}
cairo_stroke(cr);
return TRUE;
}
@ -551,6 +628,76 @@ handle_event_pinch(struct libinput_event *ev, struct window *w)
}
}
static void
handle_event_tablet(struct libinput_event *ev, struct window *w)
{
struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev);
double x, y;
struct point point;
int idx;
const int mask = ARRAY_LENGTH(w->tool.deltas);
x = libinput_event_tablet_tool_get_x_transformed(t, w->width);
y = libinput_event_tablet_tool_get_y_transformed(t, w->height);
switch (libinput_event_get_type(ev)) {
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
if (libinput_event_tablet_tool_get_proximity_state(t) ==
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
w->tool.x_in = 0;
w->tool.y_in = 0;
w->tool.x_down = 0;
w->tool.y_down = 0;
w->tool.x_up = 0;
w->tool.y_up = 0;
} else {
w->tool.x_in = x;
w->tool.y_in = y;
w->tool.ndeltas = 0;
w->tool.deltas[0].x = w->width/2;
w->tool.deltas[0].y = w->height/2;
}
break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
w->tool.pressure = libinput_event_tablet_tool_get_pressure(t);
w->tool.distance = libinput_event_tablet_tool_get_distance(t);
w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t);
w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t);
if (libinput_event_tablet_tool_get_tip_state(t) ==
LIBINPUT_TABLET_TOOL_TIP_DOWN) {
w->tool.x_down = x;
w->tool.y_down = y;
} else {
w->tool.x_up = x;
w->tool.y_up = y;
}
/* fallthrough */
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
w->tool.x = x;
w->tool.y = y;
w->tool.pressure = libinput_event_tablet_tool_get_pressure(t);
w->tool.distance = libinput_event_tablet_tool_get_distance(t);
w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t);
w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t);
/* Add the delta to the last position and store them as abs
* coordinates */
idx = w->tool.ndeltas % mask;
point = w->tool.deltas[idx];
idx = (w->tool.ndeltas + 1) % mask;
point.x += libinput_event_tablet_tool_get_dx(t);
point.y += libinput_event_tablet_tool_get_dy(t);
w->tool.deltas[idx] = point;
w->tool.ndeltas++;
break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
break;
default:
abort();
}
}
static gboolean
handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
{
@ -606,6 +753,12 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
case LIBINPUT_EVENT_GESTURE_PINCH_END:
handle_event_pinch(ev, w);
break;
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
handle_event_tablet(ev, w);
break;
}
libinput_event_destroy(ev);

View file

@ -269,6 +269,9 @@ print_device_notify(struct libinput_event *ev)
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_TOUCH))
printf("touch");
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_TABLET_TOOL))
printf("tablet");
printf("\n");
printf("Tap-to-click: %s\n", tap_default(dev));