<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>