<div dir="ltr"><div><div>hi, <br>Oh I must have missed those. Just added them. Also found some more typos. <br>v9 is comming..<br><br></div>regards<br></div>Andreas<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Nov 13, 2015 at 5:58 AM, Peter Hutterer <span dir="ltr"><<a href="mailto:peter.hutterer@who-t.net" target="_blank">peter.hutterer@who-t.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Mon, Nov 02, 2015 at 04:56:13PM +0100, Andreas Pokorny wrote:<br>
> This change adds four new properties to touch events:<br>
> * major: diameter of the touch ellipse along the major axis<br>
> * minor: diameter perpendicular to major axis<br>
> * pressure: a pressure value mapped into the range [0, 1]<br>
> * orientation: the angle between major and the x axis [0, 360]<br>
><br>
> Those values are optionally supported by multi-touch drivers, so default values<br>
> are used if the information is missing. The existance of each of the properties<br>
> can be queried at the event using another set of libinput_event_touch_has_*<br>
> functions.<br>
><br>
> Explanation of those values was added to the touch screen page.<br>
><br>
> Signed-off-by: Andreas Pokorny <<a href="mailto:andreas.pokorny@canonical.com">andreas.pokorny@canonical.com</a>><br>
<br>
</span>did you get my patch to squash in with the documentation updates?<br>
none of those appear to be in here.<br>
<br>
Cheers,<br>
Peter<br>
<div class="HOEnZb"><div class="h5"><br>
> ---<br>
> doc/Makefile.am | 2 +<br>
> doc/page-hierarchy.dox | 1 +<br>
> doc/svg/touchscreen-touch-event-properties.svg | 347 +++++++++++++++++++++++++<br>
> doc/touch-event-properties.dox | 42 +++<br>
> src/evdev.c | 224 ++++++++++++++--<br>
> src/evdev.h | 24 ++<br>
> src/libinput-private.h | 13 +-<br>
> src/libinput-util.h | 6 +<br>
> src/libinput.c | 212 ++++++++++++++-<br>
> src/libinput.h | 222 ++++++++++++++++<br>
> src/libinput.sym | 13 +<br>
> test/touch.c | 241 +++++++++++++++++<br>
> 12 files changed, 1315 insertions(+), 32 deletions(-)<br>
> create mode 100644 doc/svg/touchscreen-touch-event-properties.svg<br>
> create mode 100644 doc/touch-event-properties.dox<br>
><br>
> diff --git a/doc/Makefile.am b/doc/Makefile.am<br>
> index fe70f6a..c0b4f73 100644<br>
> --- a/doc/Makefile.am<br>
> +++ b/doc/Makefile.am<br>
> @@ -26,6 +26,7 @@ header_files = \<br>
> $(srcdir)/tapping.dox \<br>
> $(srcdir)/test-suite.dox \<br>
> $(srcdir)/tools.dox \<br>
> + $(srcdir)/touch-event-properties.dox \<br>
> $(srcdir)/touchpads.dox<br>
><br>
> diagram_files = \<br>
> @@ -50,6 +51,7 @@ diagram_files = \<br>
> $(srcdir)/svg/thumb-detection.svg \<br>
> $(srcdir)/svg/top-software-buttons.svg \<br>
> $(srcdir)/svg/touchscreen-gestures.svg \<br>
> + $(srcdir)/svg/touchscreen-touch-event-properties.svg \<br>
> $(srcdir)/svg/twofinger-scrolling.svg<br>
><br>
> style_files = \<br>
> diff --git a/doc/page-hierarchy.dox b/doc/page-hierarchy.dox<br>
> index 3fdb1f7..aadc87f 100644<br>
> --- a/doc/page-hierarchy.dox<br>
> +++ b/doc/page-hierarchy.dox<br>
> @@ -11,6 +11,7 @@<br>
> @page touchscreens Touchscreens<br>
><br>
> - @subpage absolute_axes<br>
> +- @subpage touch_event_properties<br>
><br>
> @page pointers Mice, Trackballs, etc.<br>
><br>
> diff --git a/doc/svg/touchscreen-touch-event-properties.svg b/doc/svg/touchscreen-touch-event-properties.svg<br>
> new file mode 100644<br>
> index 0000000..b728f40<br>
> --- /dev/null<br>
> +++ b/doc/svg/touchscreen-touch-event-properties.svg<br>
> @@ -0,0 +1,347 @@<br>
> +<?xml version="1.0" encoding="UTF-8" standalone="no"?><br>
> +<!-- Created with Inkscape (<a href="http://www.inkscape.org/" rel="noreferrer" target="_blank">http://www.inkscape.org/</a>) --><br>
> +<br>
> +<svg<br>
> + xmlns:dc="<a href="http://purl.org/dc/elements/1.1/" rel="noreferrer" target="_blank">http://purl.org/dc/elements/1.1/</a>"<br>
> + xmlns:cc="<a href="http://creativecommons.org/ns#" rel="noreferrer" target="_blank">http://creativecommons.org/ns#</a>"<br>
> + xmlns:rdf="<a href="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rel="noreferrer" target="_blank">http://www.w3.org/1999/02/22-rdf-syntax-ns#</a>"<br>
> + xmlns:svg="<a href="http://www.w3.org/2000/svg" rel="noreferrer" target="_blank">http://www.w3.org/2000/svg</a>"<br>
> + xmlns="<a href="http://www.w3.org/2000/svg" rel="noreferrer" target="_blank">http://www.w3.org/2000/svg</a>"<br>
> + xmlns:sodipodi="<a href="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" rel="noreferrer" target="_blank">http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd</a>"<br>
> + xmlns:inkscape="<a href="http://www.inkscape.org/namespaces/inkscape" rel="noreferrer" target="_blank">http://www.inkscape.org/namespaces/inkscape</a>"<br>
> + width="81.778557mm"<br>
> + height="107.62305mm"<br>
> + viewBox="0 0 289.76655 381.34154"<br>
> + id="svg2"<br>
> + version="1.1"<br>
> + inkscape:version="0.91 r13725"<br>
> + sodipodi:docname="touchscreen-touch-event-properties.svg"><br>
> + <defs<br>
> + id="defs4"><br>
> + <marker<br>
> + inkscape:stockid="DotL"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="DotL"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4259"<br>
> + 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"<br>
> + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"<br>
> + transform="matrix(0.8,0,0,0.8,5.92,0.8)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="CurveOut"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="CurveOut"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4385"<br>
> + d="m -5.4129913,-5.0456926 c 2.76,0 4.99999999,2.24 4.99999999,5.00000002 0,2.75999998 -2.23999999,4.99999998 -4.99999999,4.99999998"<br>
> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"<br>
> + transform="scale(0.6,0.6)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="StopL"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="StopL"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4367"<br>
> + d="M 0,5.65 0,-5.65"<br>
> + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"<br>
> + transform="scale(0.8,0.8)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <marker<br>
> + style="overflow:visible"<br>
> + id="DistanceStart"<br>
> + refX="0"<br>
> + refY="0"<br>
> + orient="auto"<br>
> + inkscape:stockid="DistanceStart"<br>
> + inkscape:isstock="true"><br>
> + <g<br>
> + id="g2300"<br>
> + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1"><br>
> + <path<br>
> + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.14999998;stroke-linecap:square;stroke-opacity:1"<br>
> + d="M 0,0 2,0"<br>
> + id="path2306"<br>
> + inkscape:connector-curvature="0" /><br>
> + <path<br>
> + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-opacity:1"<br>
> + d="M 0,0 13,4 9,0 13,-4 0,0 Z"<br>
> + id="path2302"<br>
> + inkscape:connector-curvature="0" /><br>
> + <path<br>
> + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-opacity:1"<br>
> + d="M 0,-4 0,40"<br>
> + id="path2304"<br>
> + inkscape:connector-curvature="0" /><br>
> + </g><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="Arrow2Mend"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="Arrow2Mend"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4225"<br>
> + style="fill:#cb004e;fill-opacity:1;fill-rule:evenodd;stroke:#cb004e;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"<br>
> + 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"<br>
> + transform="scale(-0.6,-0.6)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="Arrow2Lend"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="Arrow2Lend"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4219"<br>
> + style="fill:#cb004e;fill-opacity:1;fill-rule:evenodd;stroke:#cb004e;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"<br>
> + 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"<br>
> + transform="matrix(-1.1,0,0,-1.1,-1.1,0)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="TriangleInL"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="TriangleInL"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4331"<br>
> + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"<br>
> + style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1pt;stroke-opacity:1"<br>
> + transform="scale(-0.8,-0.8)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="Arrow2Lstart"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="Arrow2Lstart"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + id="path4216"<br>
> + style="fill:#cb004e;fill-opacity:1;fill-rule:evenodd;stroke:#cb004e;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"<br>
> + 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"<br>
> + transform="matrix(1.1,0,0,1.1,1.1,0)"<br>
> + inkscape:connector-curvature="0" /><br>
> + </marker><br>
> + <inkscape:path-effect<br>
> + effect="powerstroke"<br>
> + id="path-effect4140"<br>
> + is_visible="true"<br>
> + offset_points="0,0.5"<br>
> + sort_points="true"<br>
> + interpolator_type="Linear"<br>
> + interpolator_beta="0.2"<br>
> + start_linecap_type="zerowidth"<br>
> + linejoin_type="round"<br>
> + miter_limit="4"<br>
> + end_linecap_type="zerowidth"<br>
> + cusp_linecap_type="round" /><br>
> + <marker<br>
> + inkscape:stockid="TriangleInL"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="TriangleInL-1"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + inkscape:connector-curvature="0"<br>
> + id="path4331-8"<br>
> + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"<br>
> + style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1pt;stroke-opacity:1"<br>
> + transform="scale(-0.8,-0.8)" /><br>
> + </marker><br>
> + <marker<br>
> + inkscape:stockid="TriangleInL"<br>
> + orient="auto"<br>
> + refY="0"<br>
> + refX="0"<br>
> + id="TriangleInL-1-3"<br>
> + style="overflow:visible"<br>
> + inkscape:isstock="true"><br>
> + <path<br>
> + inkscape:connector-curvature="0"<br>
> + id="path4331-8-7"<br>
> + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"<br>
> + style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1pt;stroke-opacity:1"<br>
> + transform="scale(-0.8,-0.8)" /><br>
> + </marker><br>
> + </defs><br>
> + <sodipodi:namedview<br>
> + id="base"<br>
> + pagecolor="#ffffff"<br>
> + bordercolor="#666666"<br>
> + borderopacity="1.0"<br>
> + inkscape:pageopacity="0.0"<br>
> + inkscape:pageshadow="2"<br>
> + inkscape:zoom="0.99999999"<br>
> + inkscape:cx="123.83444"<br>
> + inkscape:cy="279.21547"<br>
> + inkscape:document-units="px"<br>
> + inkscape:current-layer="layer1"<br>
> + showgrid="false"<br>
> + showguides="false"<br>
> + inkscape:window-width="2560"<br>
> + inkscape:window-height="1056"<br>
> + inkscape:window-x="0"<br>
> + inkscape:window-y="24"<br>
> + inkscape:window-maximized="1"<br>
> + fit-margin-top="0"<br>
> + fit-margin-left="0"<br>
> + fit-margin-right="0"<br>
> + fit-margin-bottom="0" /><br>
> + <metadata<br>
> + id="metadata7"><br>
> + <rdf:RDF><br>
> + <cc:Work<br>
> + rdf:about=""><br>
> + <dc:format>image/svg+xml</dc:format><br>
> + <dc:type<br>
> + rdf:resource="<a href="http://purl.org/dc/dcmitype/StillImage" rel="noreferrer" target="_blank">http://purl.org/dc/dcmitype/StillImage</a>" /><br>
> + <dc:title></dc:title><br>
> + </cc:Work><br>
> + </rdf:RDF><br>
> + </metadata><br>
> + <g<br>
> + inkscape:label="Layer 1"<br>
> + inkscape:groupmode="layer"<br>
> + id="layer1"<br>
> + transform="translate(-99.549825,-70.836892)"><br>
> + <path<br>
> + style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1.79780054px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#TriangleInL-1-3)"<br>
> + d="m 231.28087,80.931744 -0.008,371.246666"<br>
> + id="path4144-1-8-1"<br>
> + inkscape:connector-curvature="0"<br>
> + sodipodi:nodetypes="cc" /><br>
> + <g<br>
> + id="g6309"<br>
> + inkscape:transform-center-x="-9.527809"<br>
> + inkscape:transform-center-y="-8.1612127"<br>
> + transform="matrix(1.171972,1.3632932,-1.3632932,1.171972,275.33248,-179.00364)"><br>
> + <path<br>
> + sodipodi:nodetypes="cc"<br>
> + inkscape:connector-curvature="0"<br>
> + id="path4144-1-8"<br>
> + d="m 172.88767,70.631028 -0.004,206.500482"<br>
> + style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#TriangleInL-1)" /><br>
> + <ellipse<br>
> + ry="77.321434"<br>
> + rx="45.89286"<br>
> + cy="180.93364"<br>
> + cx="172.85715"<br>
> + id="path4136"<br>
> + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><br>
> + <path<br>
> + sodipodi:nodetypes="cc"<br>
> + inkscape:connector-curvature="0"<br>
> + id="path4142"<br>
> + d="m 126.9449,180.93396 91.84596,0.007"<br>
> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><br>
> + <path<br>
> + sodipodi:nodetypes="cc"<br>
> + inkscape:connector-curvature="0"<br>
> + id="path4144"<br>
> + d="m 172.84766,103.6564 -0.004,154.59727"<br>
> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><br>
> + <text<br>
> + sodipodi:linespacing="125%"<br>
> + id="text4146"<br>
> + y="188.01213"<br>
> + x="128.08986"<br>
> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;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"<br>
> + xml:space="preserve"><tspan<br>
> + y="188.01213"<br>
> + x="128.08986"<br>
> + id="tspan4148"<br>
> + sodipodi:role="line">minor axis</tspan></text><br>
> + <text<br>
> + transform="matrix(0,-1,1,0,0,0)"<br>
> + sodipodi:linespacing="125%"<br>
> + id="text4150"<br>
> + y="169.33234"<br>
> + x="-256.35562"<br>
> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;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"<br>
> + xml:space="preserve"><tspan<br>
> + y="169.33234"<br>
> + x="-256.35562"<br>
> + id="tspan4152"<br>
> + sodipodi:role="line">major axis</tspan></text><br>
> + </g><br>
> + <text<br>
> + xml:space="preserve"<br>
> + style="font-style:normal;font-weight:normal;font-size:71.91202545px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"<br>
> + x="44.285629"<br>
> + y="369.12045"<br>
> + id="text6877"<br>
> + sodipodi:linespacing="125%"<br>
> + transform="matrix(0.76306478,-0.64632201,0.64632201,0.76306478,0,0)"><tspan<br>
> + sodipodi:role="line"<br>
> + id="tspan6879"<br>
> + x="44.285629"<br>
> + y="369.12045"<br>
> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.4835043px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#b3b3b3;fill-opacity:1">pointing direction</tspan></text><br>
> + <text<br>
> + xml:space="preserve"<br>
> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.4835043px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"<br>
> + x="237.00804"<br>
> + y="99.788658"<br>
> + id="text6887"<br>
> + sodipodi:linespacing="125%"><tspan<br>
> + sodipodi:role="line"<br>
> + id="tspan6889"<br>
> + x="237.00804"<br>
> + y="99.788658">y axis</tspan></text><br>
> + <path<br>
> + style="fill:none;fill-opacity:1;stroke:#cb004e;stroke-width:1.79780054;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"<br>
> + id="path7011"<br>
> + sodipodi:type="arc"<br>
> + sodipodi:cx="231.14914"<br>
> + sodipodi:cy="268.54077"<br>
> + sodipodi:rx="79.092262"<br>
> + sodipodi:ry="79.092262"<br>
> + sodipodi:start="4.7157629"<br>
> + sodipodi:end="5.5461565"<br>
> + d="m 231.41599,189.44896 a 79.092262,79.092262 0 0 1 58.2985,25.93463"<br>
> + sodipodi:open="true" /><br>
> + <text<br>
> + xml:space="preserve"<br>
> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.98900318px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cb004e;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"<br>
> + x="232.66777"<br>
> + y="184.40468"<br>
> + id="text7119"<br>
> + sodipodi:linespacing="125%"><tspan<br>
> + sodipodi:role="line"<br>
> + id="tspan7121"<br>
> + x="232.66777"<br>
> + y="184.40468"<br>
> + style="font-size:13.4835043px;fill:#cb004e;fill-opacity:1">orientation</tspan></text><br>
> + </g><br>
> +</svg><br>
> diff --git a/doc/touch-event-properties.dox b/doc/touch-event-properties.dox<br>
> new file mode 100644<br>
> index 0000000..bf326f7<br>
> --- /dev/null<br>
> +++ b/doc/touch-event-properties.dox<br>
> @@ -0,0 +1,42 @@<br>
> +/**<br>
> +@page touch_event_properties Properties of a touch event<br>
> +<br>
> +This page gives some overview on touchscreen events. With libinput touchscreens<br>
> +provide the event types @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref LIBINPUT_EVENT_TOUCH_UP,<br>
> +@ref LIBINPUT_EVENT_TOUCH_MOTION and @ref LIBINPUT_EVENT_TOUCH_CANCEL. The<br>
> +touchscreen events @ref LIBINPUT_EVENT_TOUCH_DOWN and<br>
> +@ref LIBINPUT_EVENT_TOUCH_MOTION provide alongside the actual state change and<br>
> +the absolute coordinates (@ref absolute_axes_handling) additional information<br>
> +about the touch contact.<br>
> +<br>
> +@image html touchscreen-touch-event-properties.svg "Properties of a touch screen contact"<br>
> +<br>
> +Assuming the interaction of fingers with a touch screen, touch contacts are<br>
> +approximated with an ellipse. The major axis of the ellipse describes the<br>
> +pointing direction of the finger. The minor axis is the perpendicular<br>
> +extent of the touching shape. The orientation angle is the clockwise rotation of<br>
> +the pointing direction against the y-axis of the touchscreen.<br>
> +<br>
> +Additionally to the values shown in the drawing above, most touchscreens also<br>
> +provide a pressure value to indicate the force applied with the contact point.<br>
> +<br>
> +The support for those contact properties varies between the different<br>
> +available touchscreens. In the case of pressure libinput will return the<br>
> +maximum pressure value, which is 1.0. If only the major axis but no minor axis<br>
> +is present, libinput will assume a circular shape and return the major axis<br>
> +value for convenience. If also no major axis value is known 0.0 is returned.<br>
> +If the orientation is not available libinput will return 0.0 degrees.<br>
> +<br>
> +For querying the touch properties see:<br>
> +- libinput_event_touch_get_major_transformed()<br>
> +- libinput_event_touch_get_minor_transformed()<br>
> +- libinput_event_touch_get_orientation()<br>
> +- libinput_event_touch_get_pressure()<br>
> +<br>
> +For testing which of the touch properties are available see:<br>
> +- libinput_event_touch_has_major()<br>
> +- libinput_event_touch_has_minor()<br>
> +- libinput_event_touch_has_orientation()<br>
> +- libinput_event_touch_has_pressure()<br>
> +<br>
> +*/<br>
> diff --git a/src/evdev.c b/src/evdev.c<br>
> index ec3abc6..ea6be05 100644<br>
> --- a/src/evdev.c<br>
> +++ b/src/evdev.c<br>
> @@ -45,6 +45,10 @@<br>
><br>
> #define DEFAULT_WHEEL_CLICK_ANGLE 15<br>
> #define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT ms2us(200)<br>
> +#define DEFAULT_TOUCH_PRESSURE 1.0<br>
> +#define DEFAULT_TOUCH_ORIENTATION 0.0<br>
> +#define DEFAULT_TOUCH_MAJOR 0.0<br>
> +#define DEFAULT_TOUCH_MINOR 0.0<br>
><br>
> enum evdev_key_type {<br>
> EVDEV_KEY_TYPE_NONE,<br>
> @@ -245,6 +249,100 @@ evdev_device_transform_y(struct evdev_device *device,<br>
> return scale_axis(device->abs.absinfo_y, y, height);<br>
> }<br>
><br>
> +double<br>
> +evdev_device_transform_ellipse_diameter_to_mm(struct evdev_device *device,<br>
> + int diameter,<br>
> + double axis_angle)<br>
> +{<br>
> + double x_res = device->abs.absinfo_x->resolution;<br>
> + double y_res = device->abs.absinfo_y->resolution;<br>
> +<br>
> + if (x_res == y_res)<br>
> + return diameter / x_res;<br>
> +<br>
> + /* resolution differs but no orientation available<br>
> + * -> estimate resolution using the average */<br>
> + if (device->abs.absinfo_orientation == NULL) {<br>
> + return diameter * 2.0 / (x_res + y_res);<br>
> + } else {<br>
> + /* Why scale x using sine of angle?<br>
> + * axis_angle = 0 indicates that the given diameter<br>
> + * is aligned with the y-axis. */<br>
> + double x_scaling_ratio = fabs(sin(deg2rad(axis_angle)));<br>
> + double y_scaling_ratio = fabs(cos(deg2rad(axis_angle)));<br>
> +<br>
> + return diameter / hypotf(y_res * y_scaling_ratio,<br>
> + x_res * x_scaling_ratio);<br>
> + }<br>
> +}<br>
> +<br>
> +double<br>
> +evdev_device_transform_ellipse_diameter(struct evdev_device *device,<br>
> + int diameter,<br>
> + double axis_angle,<br>
> + uint32_t width,<br>
> + uint32_t height)<br>
> +{<br>
> + double x_res = device->abs.absinfo_x->resolution;<br>
> + double y_res = device->abs.absinfo_y->resolution;<br>
> + double x_scale = width / (device->abs.dimensions.x + 1.0);<br>
> + double y_scale = height / (device->abs.dimensions.y + 1.0);<br>
> +<br>
> + if (x_res == y_res)<br>
> + return diameter * x_scale;<br>
> +<br>
> + /* no orientation available -> estimate resolution using the<br>
> + * average */<br>
> + if (device->abs.absinfo_orientation == NULL) {<br>
> + return diameter * (x_scale + y_scale) / 2.0;<br>
> + } else {<br>
> + /* Why scale x using sine of angle?<br>
> + * axis_angle = 0 indicates that the given diameter<br>
> + * is aligned with the y-axis. */<br>
> + double x_scaling_ratio = fabs(sin(deg2rad(axis_angle)));<br>
> + double y_scaling_ratio = fabs(cos(deg2rad(axis_angle)));<br>
> +<br>
> + return diameter * (y_scale * y_scaling_ratio +<br>
> + x_scale * x_scaling_ratio);<br>
> + }<br>
> +}<br>
> +<br>
> +double<br>
> +evdev_device_transform_orientation(struct evdev_device *device,<br>
> + int32_t orientation)<br>
> +{<br>
> + const struct input_absinfo *orientation_info =<br>
> + device->abs.absinfo_orientation;<br>
> +<br>
> + double angle = DEFAULT_TOUCH_ORIENTATION;<br>
> +<br>
> + /* ABS_MT_ORIENTATION is defined as a clockwise rotation - zero<br>
> + * (instead of minimum) is mapped to the y-axis, and maximum is<br>
> + * mapped to the x-axis. So minimum is likely to be negative but<br>
> + * plays no role in scaling the value to degrees.*/<br>
> + if (orientation_info)<br>
> + angle = (90.0 * orientation) / orientation_info->maximum;<br>
> +<br>
> + return fmod(360.0 + angle, 360.0);<br>
> +}<br>
> +<br>
> +double<br>
> +evdev_device_transform_pressure(struct evdev_device *device,<br>
> + int32_t pressure)<br>
> +{<br>
> + const struct input_absinfo *pressure_info =<br>
> + device->abs.absinfo_pressure;<br>
> +<br>
> + if (pressure_info) {<br>
> + double max_pressure = pressure_info->maximum;<br>
> + double min_pressure = pressure_info->minimum;<br>
> + return (pressure - min_pressure) /<br>
> + (max_pressure - min_pressure);<br>
> + } else {<br>
> + return DEFAULT_TOUCH_PRESSURE;<br>
> + }<br>
> +}<br>
> +<br>
> static inline void<br>
> normalize_delta(struct evdev_device *device,<br>
> const struct device_coords *delta,<br>
> @@ -282,8 +380,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)<br>
> struct normalized_coords accel, unaccel;<br>
> struct device_coords point;<br>
> struct device_float_coords raw;<br>
> + struct mt_slot *slot_data;<br>
> + struct ellipse default_touch = {<br>
> + .major = DEFAULT_TOUCH_MAJOR,<br>
> + .minor = DEFAULT_TOUCH_MINOR,<br>
> + .orientation = DEFAULT_TOUCH_ORIENTATION<br>
> + };<br>
><br>
> slot = device->mt.slot;<br>
> + slot_data = &device->mt.slots[slot];<br>
><br>
> switch (device->pending_event) {<br>
> case EVDEV_NONE:<br>
> @@ -324,7 +429,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)<br>
> if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))<br>
> break;<br>
><br>
> - if (device->mt.slots[slot].seat_slot != -1) {<br>
> + if (slot_data->seat_slot != -1) {<br>
> log_bug_kernel(libinput,<br>
> "%s: Driver sent multiple touch down for the "<br>
> "same slot",<br>
> @@ -333,38 +438,50 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)<br>
> }<br>
><br>
> seat_slot = ffs(~seat->slot_map) - 1;<br>
> - device->mt.slots[slot].seat_slot = seat_slot;<br>
> + slot_data->seat_slot = seat_slot;<br>
><br>
> if (seat_slot == -1)<br>
> break;<br>
><br>
> seat->slot_map |= 1 << seat_slot;<br>
> - point = device->mt.slots[slot].point;<br>
> + point = slot_data->point;<br>
> transform_absolute(device, &point);<br>
><br>
> - touch_notify_touch_down(base, time, slot, seat_slot,<br>
> - &point);<br>
> + touch_notify_touch_down(base,<br>
> + time,<br>
> + slot,<br>
> + seat_slot,<br>
> + &point,<br>
> + &slot_data->area,<br>
> + slot_data->pressure);<br>
> break;<br>
> case EVDEV_ABSOLUTE_MT_MOTION:<br>
> if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))<br>
> break;<br>
><br>
> - seat_slot = device->mt.slots[slot].seat_slot;<br>
> - point = device->mt.slots[slot].point;<br>
> + seat_slot = slot_data->seat_slot;<br>
> +<br>
> + point = slot_data->point;<br>
><br>
> if (seat_slot == -1)<br>
> break;<br>
><br>
> transform_absolute(device, &point);<br>
> - touch_notify_touch_motion(base, time, slot, seat_slot,<br>
> - &point);<br>
> +<br>
> + touch_notify_touch_motion(base,<br>
> + time,<br>
> + slot,<br>
> + seat_slot,<br>
> + &point,<br>
> + &slot_data->area,<br>
> + slot_data->pressure);<br>
> break;<br>
> case EVDEV_ABSOLUTE_MT_UP:<br>
> if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))<br>
> break;<br>
><br>
> - seat_slot = device->mt.slots[slot].seat_slot;<br>
> - device->mt.slots[slot].seat_slot = -1;<br>
> + seat_slot = slot_data->seat_slot;<br>
> + slot_data->seat_slot = -1;<br>
><br>
> if (seat_slot == -1)<br>
> break;<br>
> @@ -396,7 +513,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)<br>
> point = device->abs.point;<br>
> transform_absolute(device, &point);<br>
><br>
> - touch_notify_touch_down(base, time, -1, seat_slot, &point);<br>
> + touch_notify_touch_down(base,<br>
> + time,<br>
> + -1,<br>
> + seat_slot,<br>
> + &point,<br>
> + &default_touch,<br>
> + DEFAULT_TOUCH_PRESSURE);<br>
> break;<br>
> case EVDEV_ABSOLUTE_MOTION:<br>
> point = device->abs.point;<br>
> @@ -408,8 +531,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)<br>
> if (seat_slot == -1)<br>
> break;<br>
><br>
> - touch_notify_touch_motion(base, time, -1, seat_slot,<br>
> - &point);<br>
> + touch_notify_touch_motion(base,<br>
> + time,<br>
> + -1,<br>
> + seat_slot,<br>
> + &point,<br>
> + &default_touch,<br>
> + DEFAULT_TOUCH_PRESSURE);<br>
> } else if (device->seat_caps & EVDEV_DEVICE_POINTER) {<br>
> pointer_notify_motion_absolute(base, time, &point);<br>
> }<br>
> @@ -569,8 +697,9 @@ evdev_process_touch(struct evdev_device *device,<br>
> struct input_event *e,<br>
> uint64_t time)<br>
> {<br>
> - switch (e->code) {<br>
> - case ABS_MT_SLOT:<br>
> + struct mt_slot *current_slot = &device->mt.slots[device->mt.slot];<br>
> +<br>
> + if (e->code == ABS_MT_SLOT) {<br>
> if ((size_t)e->value >= device->mt.slots_len) {<br>
> log_bug_libinput(device->base.seat->libinput,<br>
> "%s exceeds slots (%d of %zd)\n",<br>
> @@ -581,8 +710,7 @@ evdev_process_touch(struct evdev_device *device,<br>
> }<br>
> evdev_flush_pending_event(device, time);<br>
> device->mt.slot = e->value;<br>
> - break;<br>
> - case ABS_MT_TRACKING_ID:<br>
> + } else if(e->code == ABS_MT_TRACKING_ID) {<br>
> if (device->pending_event != EVDEV_NONE &&<br>
> device->pending_event != EVDEV_ABSOLUTE_MT_MOTION)<br>
> evdev_flush_pending_event(device, time);<br>
> @@ -590,17 +718,34 @@ evdev_process_touch(struct evdev_device *device,<br>
> device->pending_event = EVDEV_ABSOLUTE_MT_DOWN;<br>
> else<br>
> device->pending_event = EVDEV_ABSOLUTE_MT_UP;<br>
> - break;<br>
> - case ABS_MT_POSITION_X:<br>
> - device->mt.slots[device->mt.slot].point.x = e->value;<br>
> - if (device->pending_event == EVDEV_NONE)<br>
> - device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;<br>
> - break;<br>
> - case ABS_MT_POSITION_Y:<br>
> - device->mt.slots[device->mt.slot].point.y = e->value;<br>
> - if (device->pending_event == EVDEV_NONE)<br>
> + } else {<br>
> + bool needs_wake = true;<br>
> +<br>
> + switch(e->code) {<br>
> + case ABS_MT_POSITION_X:<br>
> + current_slot->point.x = e->value;<br>
> + break;<br>
> + case ABS_MT_POSITION_Y:<br>
> + current_slot->point.y = e->value;<br>
> + break;<br>
> + case ABS_MT_TOUCH_MAJOR:<br>
> + current_slot->area.major = e->value;<br>
> + break;<br>
> + case ABS_MT_TOUCH_MINOR:<br>
> + current_slot->area.minor = e->value;<br>
> + break;<br>
> + case ABS_MT_ORIENTATION:<br>
> + current_slot->area.orientation = e->value;<br>
> + break;<br>
> + case ABS_MT_PRESSURE:<br>
> + current_slot->pressure = e->value;<br>
> + break;<br>
> + default:<br>
> + needs_wake = false;<br>
> + break;<br>
> + }<br>
> + if (needs_wake && device->pending_event == EVDEV_NONE)<br>
> device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;<br>
> - break;<br>
> }<br>
> }<br>
><br>
> @@ -1954,6 +2099,20 @@ evdev_configure_mt_device(struct evdev_device *device)<br>
> slots[slot].point.y = libevdev_get_slot_value(evdev,<br>
> slot,<br>
> ABS_MT_POSITION_Y);<br>
> + slots[slot].area.major =<br>
> + libevdev_get_slot_value(evdev,<br>
> + slot,<br>
> + ABS_MT_TOUCH_MAJOR);<br>
> + slots[slot].area.minor =<br>
> + libevdev_get_slot_value(evdev,<br>
> + slot,<br>
> + ABS_MT_TOUCH_MINOR);<br>
> + slots[slot].area.orientation =<br>
> + libevdev_get_slot_value(evdev,<br>
> + slot,<br>
> + ABS_MT_ORIENTATION);<br>
> + slots[slot].pressure =<br>
> + libevdev_get_slot_value(evdev, slot, ABS_MT_PRESSURE);<br>
> }<br>
> device->mt.slots = slots;<br>
> device->mt.slots_len = num_slots;<br>
> @@ -2024,6 +2183,15 @@ evdev_configure_device(struct evdev_device *device)<br>
> return -1;<br>
> }<br>
><br>
> + device->abs.absinfo_orientation =<br>
> + libevdev_get_abs_info(evdev, ABS_MT_ORIENTATION);<br>
> + device->abs.absinfo_pressure =<br>
> + libevdev_get_abs_info(evdev, ABS_MT_PRESSURE);<br>
> + device->abs.absinfo_major =<br>
> + libevdev_get_abs_info(evdev, ABS_MT_TOUCH_MAJOR);<br>
> + device->abs.absinfo_minor =<br>
> + libevdev_get_abs_info(evdev, ABS_MT_TOUCH_MINOR);<br>
> +<br>
> if (!evdev_is_fake_mt_device(device))<br>
> evdev_fix_android_mt(device);<br>
><br>
> diff --git a/src/evdev.h b/src/evdev.h<br>
> index e44a65d..7b8d0e6 100644<br>
> --- a/src/evdev.h<br>
> +++ b/src/evdev.h<br>
> @@ -112,6 +112,8 @@ enum evdev_device_model {<br>
> struct mt_slot {<br>
> int32_t seat_slot;<br>
> struct device_coords point;<br>
> + struct ellipse area;<br>
> + int32_t pressure;<br>
> };<br>
><br>
> struct evdev_device {<br>
> @@ -128,6 +130,8 @@ struct evdev_device {<br>
> int fd;<br>
> struct {<br>
> const struct input_absinfo *absinfo_x, *absinfo_y;<br>
> + const struct input_absinfo *absinfo_major, *absinfo_minor,<br>
> + *absinfo_pressure, *absinfo_orientation;<br>
> int fake_resolution;<br>
><br>
> struct device_coords point;<br>
> @@ -349,6 +353,26 @@ double<br>
> evdev_device_transform_y(struct evdev_device *device,<br>
> double y,<br>
> uint32_t height);<br>
> +double<br>
> +evdev_device_transform_ellipse_diameter_to_mm(struct evdev_device *device,<br>
> + int32_t diameter,<br>
> + double axis_angle);<br>
> +<br>
> +double<br>
> +evdev_device_transform_ellipse_diameter(struct evdev_device *device,<br>
> + int32_t diameter,<br>
> + double axis_angle,<br>
> + uint32_t width,<br>
> + uint32_t height);<br>
> +<br>
> +double<br>
> +evdev_device_transform_orientation(struct evdev_device *device,<br>
> + int32_t orientation);<br>
> +<br>
> +double<br>
> +evdev_device_transform_pressure(struct evdev_device *device,<br>
> + int32_t pressure);<br>
> +<br>
> int<br>
> evdev_device_suspend(struct evdev_device *device);<br>
><br>
> diff --git a/src/libinput-private.h b/src/libinput-private.h<br>
> index e146c26..b90c21d 100644<br>
> --- a/src/libinput-private.h<br>
> +++ b/src/libinput-private.h<br>
> @@ -40,6 +40,11 @@ struct device_coords {<br>
> int x, y;<br>
> };<br>
><br>
> +/* Ellipse parameters in device coordinates */<br>
> +struct ellipse {<br>
> + int major, minor, orientation;<br>
> +};<br>
> +<br>
> /*<br>
> * A coordinate pair in device coordinates, capable of holding non discrete<br>
> * values, this is necessary e.g. when device coordinates get averaged.<br>
> @@ -396,14 +401,18 @@ touch_notify_touch_down(struct libinput_device *device,<br>
> uint64_t time,<br>
> int32_t slot,<br>
> int32_t seat_slot,<br>
> - const struct device_coords *point);<br>
> + const struct device_coords *point,<br>
> + const struct ellipse *area,<br>
> + int32_t pressure);<br>
><br>
> void<br>
> touch_notify_touch_motion(struct libinput_device *device,<br>
> uint64_t time,<br>
> int32_t slot,<br>
> int32_t seat_slot,<br>
> - const struct device_coords *point);<br>
> + const struct device_coords *point,<br>
> + const struct ellipse *area,<br>
> + int32_t pressure);<br>
><br>
> void<br>
> touch_notify_touch_up(struct libinput_device *device,<br>
> diff --git a/src/libinput-util.h b/src/libinput-util.h<br>
> index ba253b5..9495fa6 100644<br>
> --- a/src/libinput-util.h<br>
> +++ b/src/libinput-util.h<br>
> @@ -118,6 +118,12 @@ msleep(unsigned int ms)<br>
> usleep(ms * 1000);<br>
> }<br>
><br>
> +static inline double<br>
> +deg2rad(double angle)<br>
> +{<br>
> + return angle * M_PI/180.0;<br>
> +}<br>
> +<br>
> static inline int<br>
> long_bit_is_set(const unsigned long *array, int bit)<br>
> {<br>
> diff --git a/src/libinput.c b/src/libinput.c<br>
> index 24f2b69..bdd3d41 100644<br>
> --- a/src/libinput.c<br>
> +++ b/src/libinput.c<br>
> @@ -112,6 +112,8 @@ struct libinput_event_touch {<br>
> int32_t slot;<br>
> int32_t seat_slot;<br>
> struct device_coords point;<br>
> + struct ellipse area;<br>
> + int32_t pressure;<br>
> };<br>
><br>
> struct libinput_event_gesture {<br>
> @@ -732,6 +734,204 @@ libinput_event_touch_get_y(struct libinput_event_touch *event)<br>
> return evdev_convert_to_mm(device->abs.absinfo_y, event->point.y);<br>
> }<br>
><br>
> +LIBINPUT_EXPORT double<br>
> +libinput_event_touch_get_major(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> + double angle;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + angle = evdev_device_transform_orientation(device,<br>
> + event->area.orientation);<br>
> +<br>
> + return evdev_device_transform_ellipse_diameter_to_mm(device,<br>
> + event->area.major,<br>
> + angle);<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT double<br>
> +libinput_event_touch_get_major_transformed(struct libinput_event_touch *event,<br>
> + uint32_t width,<br>
> + uint32_t height)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> + double angle;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + angle = evdev_device_transform_orientation(device,<br>
> + event->area.orientation);<br>
> +<br>
> + return evdev_device_transform_ellipse_diameter(device,<br>
> + event->area.major,<br>
> + angle,<br>
> + width,<br>
> + height);<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT int<br>
> +libinput_event_touch_has_major(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + return device->abs.absinfo_major != 0;<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT double<br>
> +libinput_event_touch_get_minor(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> + double angle;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + angle = evdev_device_transform_orientation(device,<br>
> + event->area.orientation);<br>
> +<br>
> + /* angle + 90 since the minor diameter is perpendicular to the<br>
> + * major axis */<br>
> + return evdev_device_transform_ellipse_diameter_to_mm(device,<br>
> + event->area.minor,<br>
> + angle + 90.0);<br>
> +<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT double<br>
> +libinput_event_touch_get_minor_transformed(struct libinput_event_touch *event,<br>
> + uint32_t width,<br>
> + uint32_t height)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> + double angle;<br>
> + int diameter;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + angle = evdev_device_transform_orientation(device,<br>
> + event->area.orientation);<br>
> +<br>
> + /* use major diameter if minor is not available, but if it is<br>
> + * add 90 since the minor diameter is perpendicular to the<br>
> + * major axis */<br>
> + if (device->abs.absinfo_minor) {<br>
> + diameter = event->area.minor,<br>
> + angle += 90.0;<br>
> + } else {<br>
> + diameter = event->area.major;<br>
> + }<br>
> +<br>
> + return evdev_device_transform_ellipse_diameter(device,<br>
> + diameter,<br>
> + angle,<br>
> + width,<br>
> + height);<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT int<br>
> +libinput_event_touch_has_minor(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + return device->abs.absinfo_minor != 0;<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT double<br>
> +libinput_event_touch_get_orientation(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + return evdev_device_transform_orientation(device,<br>
> + event->area.orientation);<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT int<br>
> +libinput_event_touch_has_orientation(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + return device->abs.absinfo_orientation != 0;<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT double<br>
> +libinput_event_touch_get_pressure(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + return evdev_device_transform_pressure(device,<br>
> + event->pressure);<br>
> +}<br>
> +<br>
> +LIBINPUT_EXPORT int<br>
> +libinput_event_touch_has_pressure(struct libinput_event_touch *event)<br>
> +{<br>
> + struct evdev_device *device =<br>
> + (struct evdev_device *) event->base.device;<br>
> +<br>
> + require_event_type(libinput_event_get_context(&event->base),<br>
> + event->base.type,<br>
> + 0,<br>
> + LIBINPUT_EVENT_TOUCH_DOWN,<br>
> + LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + return device->abs.absinfo_pressure != 0;<br>
> +}<br>
> +<br>
> LIBINPUT_EXPORT uint32_t<br>
> libinput_event_gesture_get_time(struct libinput_event_gesture *event)<br>
> {<br>
> @@ -1512,7 +1712,9 @@ touch_notify_touch_down(struct libinput_device *device,<br>
> uint64_t time,<br>
> int32_t slot,<br>
> int32_t seat_slot,<br>
> - const struct device_coords *point)<br>
> + const struct device_coords *point,<br>
> + const struct ellipse *area,<br>
> + int32_t pressure)<br>
> {<br>
> struct libinput_event_touch *touch_event;<br>
><br>
> @@ -1528,6 +1730,8 @@ touch_notify_touch_down(struct libinput_device *device,<br>
> .slot = slot,<br>
> .seat_slot = seat_slot,<br>
> .point = *point,<br>
> + .area = *area,<br>
> + .pressure = pressure,<br>
> };<br>
><br>
> post_device_event(device, time,<br>
> @@ -1540,7 +1744,9 @@ touch_notify_touch_motion(struct libinput_device *device,<br>
> uint64_t time,<br>
> int32_t slot,<br>
> int32_t seat_slot,<br>
> - const struct device_coords *point)<br>
> + const struct device_coords *point,<br>
> + const struct ellipse *area,<br>
> + int32_t pressure)<br>
> {<br>
> struct libinput_event_touch *touch_event;<br>
><br>
> @@ -1556,6 +1762,8 @@ touch_notify_touch_motion(struct libinput_device *device,<br>
> .slot = slot,<br>
> .seat_slot = seat_slot,<br>
> .point = *point,<br>
> + .area = *area,<br>
> + .pressure = pressure,<br>
> };<br>
><br>
> post_device_event(device, time,<br>
> diff --git a/src/libinput.h b/src/libinput.h<br>
> index 9057446..1c50c58 100644<br>
> --- a/src/libinput.h<br>
> +++ b/src/libinput.h<br>
> @@ -968,6 +968,228 @@ libinput_event_touch_get_y_transformed(struct libinput_event_touch *event,<br>
> /**<br>
> * @ingroup event_touch<br>
> *<br>
> + * Return the diameter of the major axis of the touch ellipse in mm.<br>
> + * This value might not be provided by the device, in that case the value<br>
> + * 0.0 is returned.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return The current major axis diameter<br>
> + */<br>
> +double<br>
> +libinput_event_touch_get_major(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return the diameter of the major axis of the touch ellipse in screen<br>
> + * space. This value might not be provided by the device, in that case the<br>
> + * value 0.0 is returned.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @param width The current output screen width<br>
> + * @param height The current output screen height<br>
> + * @return The current major axis diameter<br>
> + */<br>
> +double<br>
> +libinput_event_touch_get_major_transformed(struct libinput_event_touch *event,<br>
> + uint32_t width,<br>
> + uint32_t height);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return if the event contains a major axis value of the touch ellipse.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return Non-zero when a major diameter is available<br>
> + */<br>
> +int<br>
> +libinput_event_touch_has_major(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return the diameter of the minor axis of the touch ellipse in mm.<br>
> + * This value might not be provided by the device, in this case the value<br>
> + * 0.0 is returned.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return The current minor diameter<br>
> + */<br>
> +double<br>
> +libinput_event_touch_get_minor(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return the diameter of the minor axis of the touch ellipse in screen<br>
> + * space. This value might not be provided by the device, in this case<br>
> + * the value 0.0 is returned.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @param width The current output screen width<br>
> + * @param height The current output screen height<br>
> + * @return The current minor diameter<br>
> + */<br>
> +double<br>
> +libinput_event_touch_get_minor_transformed(struct libinput_event_touch *event,<br>
> + uint32_t width,<br>
> + uint32_t height);<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return if the event contains a minor axis value of the touch ellipse.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return Non-zero when a minor diameter is available<br>
> + */<br>
> +int<br>
> +libinput_event_touch_has_minor(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return the pressure value applied to the touch contact normalized to the<br>
> + * range [0, 1]. If this value is not available the function returns the maximum<br>
> + * value 1.0.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return The current pressure value<br>
> + */<br>
> +double<br>
> +libinput_event_touch_get_pressure(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return if the event contains a pressure value for the touch contact.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return Non-zero when a pressure value is available<br>
> + */<br>
> +int<br>
> +libinput_event_touch_has_pressure(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return the major axis rotation in degrees, clockwise from the logical north<br>
> + * of the touch screen.<br>
> + *<br>
> + * @note Even when the orientation is measured by the device, it might be only<br>
> + * available in coarse steps (e.g only indicating alignment with either of the<br>
> + * axes).<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return The current orientation value<br>
> + */<br>
> +double<br>
> +libinput_event_touch_get_orientation(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> + * Return if the event contains a orientation value for the touch contact.<br>
> + *<br>
> + * A more detailed explanation can be found in @ref touch_event_properties.<br>
> + *<br>
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.<br>
> + *<br>
> + * @note It is an application bug to call this function for events of type<br>
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref<br>
> + * LIBINPUT_EVENT_TOUCH_MOTION.<br>
> + *<br>
> + * @param event The libinput touch event<br>
> + * @return Non-zero when an orientation value is available<br>
> + */<br>
> +int<br>
> +libinput_event_touch_has_orientation(struct libinput_event_touch *event);<br>
> +<br>
> +/**<br>
> + * @ingroup event_touch<br>
> + *<br>
> * @return The generic libinput_event of this event<br>
> */<br>
> struct libinput_event *<br>
> diff --git a/src/libinput.sym b/src/libinput.sym<br>
> index 15203c8..23d7975 100644<br>
> --- a/src/libinput.sym<br>
> +++ b/src/libinput.sym<br>
> @@ -179,3 +179,16 @@ LIBINPUT_1.1 {<br>
> libinput_device_config_accel_get_default_profile;<br>
> libinput_device_config_accel_set_profile;<br>
> } LIBINPUT_0.21.0;<br>
> +<br>
> +LIBINPUT_1.1_unreleased {<br>
> + libinput_event_touch_get_major;<br>
> + libinput_event_touch_get_major_transformed;<br>
> + libinput_event_touch_get_minor;<br>
> + libinput_event_touch_get_minor_transformed;<br>
> + libinput_event_touch_get_orientation;<br>
> + libinput_event_touch_get_pressure;<br>
> + libinput_event_touch_has_major;<br>
> + libinput_event_touch_has_minor;<br>
> + libinput_event_touch_has_orientation;<br>
> + libinput_event_touch_has_pressure;<br>
> +} LIBINPUT_1.1;<br>
> diff --git a/test/touch.c b/test/touch.c<br>
> index eae8007..ab30914 100644<br>
> --- a/test/touch.c<br>
> +++ b/test/touch.c<br>
> @@ -673,6 +673,245 @@ START_TEST(touch_time_usec)<br>
> }<br>
> END_TEST<br>
><br>
> +static inline double calc_diameter_scale(double x_res,<br>
> + double y_res,<br>
> + double orientation)<br>
> +{<br>
> + double orientation_rad = deg2rad(orientation);<br>
> + if (x_res == y_res)<br>
> + return x_res;<br>
> +<br>
> + return hypotf(y_res * fabs(cos(orientation_rad)),<br>
> + x_res * fabs(sin(orientation_rad)));<br>
> +}<br>
> +<br>
> +static inline bool exceeds_range(const struct input_absinfo *info,<br>
> + int value)<br>
> +{<br>
> + return !info || (info->minimum > value) || (info->maximum < value);<br>
> +}<br>
> +<br>
> +START_TEST(touch_point_properties)<br>
> +{<br>
> + struct litest_device *dev = litest_current_device();<br>
> + struct libinput *li = dev->libinput;<br>
> + struct libinput_event *ev;<br>
> + struct libinput_event_touch *tev;<br>
> +<br>
> + const int touch_x = 50;<br>
> + const int touch_y = 90;<br>
> + const int input_orientation = 64;<br>
> + const int input_pressure = 128;<br>
> + const int input_major = 14;<br>
> + const int input_minor= 8;<br>
> +<br>
> + const int input_orientation_2 = 128;<br>
> + const int input_major_2 = 30;<br>
> +<br>
> + struct axis_replacement down_values[] = {<br>
> + {ABS_MT_PRESSURE, input_pressure},<br>
> + {ABS_MT_ORIENTATION, input_orientation},<br>
> + {ABS_MT_TOUCH_MAJOR, input_major},<br>
> + {ABS_MT_TOUCH_MINOR, input_minor},<br>
> + {-1, -1}};<br>
> + struct axis_replacement move_values[] = {<br>
> + {ABS_MT_ORIENTATION, input_orientation_2},<br>
> + {ABS_MT_TOUCH_MAJOR, input_major_2},<br>
> + {-1, -1}};<br>
> + const struct input_absinfo *orientation_info;<br>
> + const struct input_absinfo *pressure_info;<br>
> + const struct input_absinfo *major_info;<br>
> + const struct input_absinfo *minor_info;<br>
> + const struct input_absinfo *x_info, *y_info;<br>
> +<br>
> + double x_res, y_res, touch_minor_scale, touch_major_scale;<br>
> +<br>
> + double expected_major;<br>
> + double expected_minor;<br>
> + double expected_orientation;<br>
> + double expected_pressure;<br>
> +<br>
> + pressure_info = libevdev_get_abs_info(dev->evdev, ABS_MT_PRESSURE);<br>
> + orientation_info = libevdev_get_abs_info(dev->evdev, ABS_MT_ORIENTATION);<br>
> + major_info = libevdev_get_abs_info(dev->evdev, ABS_MT_TOUCH_MAJOR);<br>
> + minor_info = libevdev_get_abs_info(dev->evdev, ABS_MT_TOUCH_MINOR);<br>
> + x_info = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X);<br>
> + y_info = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_Y);<br>
> +<br>
> + if (!orientation_info || !pressure_info || !major_info || !minor_info)<br>
> + return;<br>
> +<br>
> + if (exceeds_range(pressure_info, input_pressure) ||<br>
> + exceeds_range(major_info, input_major) ||<br>
> + exceeds_range(major_info, input_major_2) ||<br>
> + exceeds_range(minor_info, input_minor) ||<br>
> + exceeds_range(orientation_info, input_orientation) ||<br>
> + exceeds_range(orientation_info, input_orientation_2)) {<br>
> + fprintf(stderr,<br>
> + "%s does not support the required value ranges\n",<br>
> + libinput_device_get_name(dev->libinput_device));<br>
> + return;<br>
> + }<br>
> +<br>
> + x_res = x_info->resolution ? x_info->resolution : 1;<br>
> + y_res = y_info->resolution ? y_info->resolution : 1;<br>
> +<br>
> + expected_orientation = 90.0 * input_orientation /<br>
> + orientation_info->maximum;<br>
> + touch_major_scale = calc_diameter_scale(x_res,<br>
> + y_res,<br>
> + expected_orientation);<br>
> + touch_minor_scale = calc_diameter_scale(x_res,<br>
> + y_res,<br>
> + expected_orientation + 90.0);<br>
> + expected_major = input_major / touch_major_scale;<br>
> + expected_minor = input_minor / touch_minor_scale;<br>
> + expected_pressure = (double)input_pressure / (pressure_info->maximum -<br>
> + pressure_info->minimum);<br>
> +<br>
> + litest_drain_events(li);<br>
> +<br>
> + litest_touch_down_extended(dev, 0, touch_x, touch_y, down_values);<br>
> +<br>
> + litest_wait_for_event(li);<br>
> + ev = libinput_get_event(li);<br>
> + tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_DOWN);<br>
> +<br>
> + ck_assert_double_eq(libinput_event_touch_get_pressure(tev),<br>
> + expected_pressure);<br>
> + ck_assert_double_eq(libinput_event_touch_get_orientation(tev),<br>
> + expected_orientation);<br>
> + ck_assert_double_eq(libinput_event_touch_get_major(tev),<br>
> + expected_major);<br>
> + ck_assert_double_eq(libinput_event_touch_get_minor(tev),<br>
> + expected_minor);<br>
> +<br>
> + litest_touch_move_extended(dev, 0, touch_x, touch_y, move_values);<br>
> +<br>
> + do {<br>
> + libinput_event_destroy(ev);<br>
> + litest_wait_for_event(li);<br>
> + ev = libinput_get_event(li);<br>
> + } while (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_FRAME);<br>
> +<br>
> + tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + expected_orientation = 90.0 * input_orientation_2 /<br>
> + orientation_info->maximum;<br>
> + touch_major_scale = calc_diameter_scale(x_res,<br>
> + y_res,<br>
> + expected_orientation);<br>
> + expected_major = input_major_2 / touch_major_scale;<br>
> +<br>
> + ck_assert_double_eq(libinput_event_touch_get_pressure(tev),<br>
> + expected_pressure);<br>
> + ck_assert_double_eq(libinput_event_touch_get_orientation(tev),<br>
> + expected_orientation);<br>
> + ck_assert_double_eq(libinput_event_touch_get_major(tev),<br>
> + expected_major);<br>
> + ck_assert_double_eq(libinput_event_touch_get_minor(tev),<br>
> + expected_minor);<br>
> +<br>
> + libinput_event_destroy(ev);<br>
> +}<br>
> +END_TEST<br>
> +<br>
> +START_TEST(touch_point_no_minor_or_orientation)<br>
> +{<br>
> + struct litest_device *dev = litest_current_device();<br>
> + struct libinput *li = dev->libinput;<br>
> + struct libinput_event *ev;<br>
> + struct libinput_event_touch *tev;<br>
> + const int touch_x = 50;<br>
> + const int touch_y = 90;<br>
> + const int input_pressure = 43;<br>
> + const int input_major = 23;<br>
> + const int input_major_2 = 30;<br>
> +<br>
> + struct axis_replacement down_values[] = {<br>
> + {ABS_MT_PRESSURE, input_pressure},<br>
> + {ABS_MT_TOUCH_MAJOR, input_major},<br>
> + {-1, -1}};<br>
> + struct axis_replacement move_values[] = {<br>
> + {ABS_MT_TOUCH_MAJOR, input_major_2},<br>
> + {-1, -1}};<br>
> +<br>
> + const struct input_absinfo *orientation_info;<br>
> + const struct input_absinfo *pressure_info;<br>
> + const struct input_absinfo *x_info;<br>
> + const struct input_absinfo *major_info;<br>
> + double touch_major_scale;<br>
> +<br>
> + double expected_major;<br>
> + double expected_minor;<br>
> + double expected_orientation = 0.0;<br>
> + double expected_pressure;<br>
> +<br>
> + x_info = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X);<br>
> + pressure_info = libevdev_get_abs_info(dev->evdev, ABS_MT_PRESSURE);<br>
> + major_info = libevdev_get_abs_info(dev->evdev, ABS_MT_TOUCH_MAJOR);<br>
> + orientation_info = libevdev_get_abs_info(dev->evdev,<br>
> + ABS_MT_ORIENTATION);<br>
> +<br>
> + if (orientation_info || !pressure_info || !x_info || !major_info ||<br>
> + !libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_TOUCH_MAJOR) ||<br>
> + libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_TOUCH_MINOR))<br>
> + return;<br>
> +<br>
> + if (exceeds_range(pressure_info, input_pressure) ||<br>
> + exceeds_range(major_info, input_major) ||<br>
> + exceeds_range(major_info, input_major_2)) {<br>
> + fprintf(stderr,<br>
> + "%s does not support the required value ranges\n",<br>
> + libinput_device_get_name(dev->libinput_device));<br>
> + return;<br>
> + }<br>
> +<br>
> + expected_pressure = (double) input_pressure /<br>
> + (pressure_info->maximum - pressure_info->minimum);<br>
> + touch_major_scale = x_info->resolution ? x_info->resolution : 1;<br>
> + expected_major = input_major / touch_major_scale;<br>
> + expected_minor = expected_major;<br>
> +<br>
> + litest_drain_events(li);<br>
> +<br>
> + litest_touch_down_extended(dev, 0, touch_x, touch_y, down_values);<br>
> +<br>
> + litest_wait_for_event(li);<br>
> + ev = libinput_get_event(li);<br>
> + tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_DOWN);<br>
> +<br>
> + ck_assert_double_eq(libinput_event_touch_get_orientation(tev),<br>
> + expected_orientation);<br>
> + ck_assert_double_eq(libinput_event_touch_get_pressure(tev),<br>
> + expected_pressure);<br>
> + ck_assert_double_eq(libinput_event_touch_get_major(tev),<br>
> + expected_major);<br>
> + ck_assert_double_eq(libinput_event_touch_get_minor(tev),<br>
> + expected_minor);<br>
> +<br>
> + expected_major = input_major_2 / touch_major_scale;<br>
> + expected_minor = expected_major;<br>
> +<br>
> + litest_touch_move_extended(dev, 0, touch_x, touch_y, move_values);<br>
> +<br>
> + do {<br>
> + libinput_event_destroy(ev);<br>
> + litest_wait_for_event(li);<br>
> + ev = libinput_get_event(li);<br>
> + } while (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_FRAME);<br>
> +<br>
> + tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_MOTION);<br>
> +<br>
> + ck_assert_double_eq(libinput_event_touch_get_major(tev),<br>
> + expected_major);<br>
> + ck_assert_double_eq(libinput_event_touch_get_minor(tev),<br>
> + expected_minor);<br>
> +<br>
> + libinput_event_destroy(ev);<br>
> +}<br>
> +END_TEST<br>
> +<br>
> void<br>
> litest_setup_tests(void)<br>
> {<br>
> @@ -697,6 +936,8 @@ litest_setup_tests(void)<br>
> litest_add("touch:protocol a", touch_protocol_a_init, LITEST_PROTOCOL_A, LITEST_ANY);<br>
> litest_add("touch:protocol a", touch_protocol_a_touch, LITEST_PROTOCOL_A, LITEST_ANY);<br>
> litest_add("touch:protocol a", touch_protocol_a_2fg_touch, LITEST_PROTOCOL_A, LITEST_ANY);<br>
> + litest_add("touch:properties", touch_point_properties, LITEST_TOUCH|LITEST_ELLIPSE, LITEST_ANY);<br>
> + litest_add("touch:properties", touch_point_no_minor_or_orientation, LITEST_TOUCH|LITEST_ELLIPSE, LITEST_ANY);<br>
><br>
> litest_add_ranged("touch:state", touch_initial_state, LITEST_TOUCH, LITEST_PROTOCOL_A, &axes);<br>
><br>
> --<br>
> 2.5.0<br>
><br>
</div></div></blockquote></div><br></div>