debian/changelog | 10 debian/libinput10.symbols | 11 debian/patches/fix-litest.patch | 44 debian/patches/series | 2 debian/patches/touch-point-orientation-size.patch | 1675 ++++++++++++++++++++++ 5 files changed, 1742 insertions(+)
New commits: commit 28c3fd8ff064ee5ec7f2f2644e5a493c7d91add4 Author: Robert Ancell <robert.anc...@canonical.com> Date: Mon Aug 24 15:56:17 2015 +0100 * debian/patches/touch-point-orientation-size.patch: * debian/patches/fix-litest.patch: - Add support for touchscreen contact properties (LP: #1488064) * debian/libinput10.symbols: - Updated diff --git a/debian/changelog b/debian/changelog index 6f96377..8159edb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +libinput (0.21.0-1ubuntu1) wily; urgency=medium + + * debian/patches/touch-point-orientation-size.patch: + * debian/patches/fix-litest.patch: + - Add support for touchscreen contact properties (LP: #1488064) + * debian/libinput10.symbols: + - Updated + + -- Robert Ancell <robert.anc...@canonical.com> Mon, 24 Aug 2015 13:13:32 +0100 + libinput (0.21.0-1) unstable; urgency=medium * New upstream release. diff --git a/debian/libinput10.symbols b/debian/libinput10.symbols index 406f01e..eb427b6 100644 --- a/debian/libinput10.symbols +++ b/debian/libinput10.symbols @@ -6,6 +6,7 @@ libinput.so.10 libinput10 #MINVER# LIBINPUT_0.19.0@LIBINPUT_0.19.0 0.21.0 LIBINPUT_0.20.0@LIBINPUT_0.20.0 0.21.0 LIBINPUT_0.21.0@LIBINPUT_0.21.0 0.21.0 + LIBINPUT_0.22.0@LIBINPUT_0.22.0 0.21.0-1ubuntu1 libinput_config_status_to_str@LIBINPUT_0.12.0 0.15.0 libinput_device_config_accel_get_default_speed@LIBINPUT_0.12.0 0.15.0 libinput_device_config_accel_get_speed@LIBINPUT_0.12.0 0.15.0 @@ -123,6 +124,12 @@ libinput.so.10 libinput10 #MINVER# libinput_event_pointer_get_time_usec@LIBINPUT_0.21.0 0.21.0 libinput_event_pointer_has_axis@LIBINPUT_0.12.0 0.15.0 libinput_event_touch_get_base_event@LIBINPUT_0.12.0 0.15.0 + libinput_event_touch_get_major@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_get_major_transformed@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_get_minor@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_get_minor_transformed@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_get_orientation@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_get_pressure@LIBINPUT_0.22.0 0.21.0-1ubuntu1 libinput_event_touch_get_seat_slot@LIBINPUT_0.12.0 0.15.0 libinput_event_touch_get_slot@LIBINPUT_0.12.0 0.15.0 libinput_event_touch_get_time@LIBINPUT_0.12.0 0.15.0 @@ -131,6 +138,10 @@ libinput.so.10 libinput10 #MINVER# libinput_event_touch_get_x_transformed@LIBINPUT_0.12.0 0.15.0 libinput_event_touch_get_y@LIBINPUT_0.12.0 0.15.0 libinput_event_touch_get_y_transformed@LIBINPUT_0.12.0 0.15.0 + libinput_event_touch_has_major@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_has_minor@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_has_orientation@LIBINPUT_0.22.0 0.21.0-1ubuntu1 + libinput_event_touch_has_pressure@LIBINPUT_0.22.0 0.21.0-1ubuntu1 libinput_get_event@LIBINPUT_0.12.0 0.15.0 libinput_get_fd@LIBINPUT_0.12.0 0.15.0 libinput_get_user_data@LIBINPUT_0.12.0 0.15.0 diff --git a/debian/patches/fix-litest.patch b/debian/patches/fix-litest.patch new file mode 100644 index 0000000..e476d8d --- /dev/null +++ b/debian/patches/fix-litest.patch @@ -0,0 +1,44 @@ +With this change auto assign events will be skipped if no replacement value +is provided. This behavior is practical when emitting mt events, as those +only contain the axis values that changed. + +Signed-off-by: Andreas Pokorny <andreas.pokorny at canonical.com> +--- + test/litest.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/test/litest.c b/test/litest.c +index 26c5e43..8fc7bca 100644 +--- a/test/litest.c ++++ b/test/litest.c +@@ -1292,7 +1292,6 @@ litest_auto_assign_value(struct litest_device *d, + value = touching ? 0 : 1; + break; + default: +- value = -1; + if (!axis_replacement_value(axes, ev->code, &value) && + d->interface->get_axis_default) + d->interface->get_axis_default(d, ev->code, &value); +@@ -1342,8 +1341,8 @@ litest_slot_start(struct litest_device *d, + y, + axes, + touching); +- +- litest_event(d, ev->type, ev->code, value); ++ if (value != LITEST_AUTO_ASSIGN) ++ litest_event(d, ev->type, ev->code, value); + ev++; + } + } +@@ -1428,7 +1427,8 @@ litest_slot_move(struct litest_device *d, + y, + axes, + touching); +- litest_event(d, ev->type, ev->code, value); ++ if (value != LITEST_AUTO_ASSIGN) ++ litest_event(d, ev->type, ev->code, value); + ev++; + } + } +-- +2.1.4 diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..cc360d0 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,2 @@ +fix-litest.patch +touch-point-orientation-size.patch diff --git a/debian/patches/touch-point-orientation-size.patch b/debian/patches/touch-point-orientation-size.patch new file mode 100644 index 0000000..24505a6 --- /dev/null +++ b/debian/patches/touch-point-orientation-size.patch @@ -0,0 +1,1675 @@ +This change adds four new properties to touch events: +* major: diameter of the touch ellipse along the major axis +* minor: diameter perpendicular to major axis +* pressure: a pressure value mapped into the range [0, 1] +* orientation: the angle between major and the x axis [0, 360] + +Those values are optionally supported by multi-touch drivers, so default values +are used if the information is missing. The existance of each of the properties +can be querried at the event using another set of libinput_event_touch_has_* +functions. + +Explanation of those values was added to the touch screen page. + +Signed-off-by: Andreas Pokorny <andreas.pokorny at canonical.com> +--- + doc/Makefile.am | 2 + + doc/page-hierarchy.dox | 1 + + doc/svg/touchscreen-touch-event-properties.svg | 347 +++++++++++++++++++++++++ + doc/touch-event-properties.dox | 42 +++ + src/evdev.c | 218 ++++++++++++++-- + src/evdev.h | 25 ++ + src/libinput-private.h | 25 +- + src/libinput-util.h | 6 + + src/libinput.c | 205 ++++++++++++++- + src/libinput.h | 222 ++++++++++++++++ + src/libinput.sym | 13 + + test/touch.c | 239 +++++++++++++++++ + 12 files changed, 1313 insertions(+), 32 deletions(-) + create mode 100644 doc/svg/touchscreen-touch-event-properties.svg + create mode 100644 doc/touch-event-properties.dox + +diff --git a/doc/Makefile.am b/doc/Makefile.am +index a8d4182..da21283 100644 +--- a/doc/Makefile.am ++++ b/doc/Makefile.am +@@ -26,6 +26,7 @@ header_files = \ + $(srcdir)/tapping.dox \ + $(srcdir)/test-suite.dox \ + $(srcdir)/tools.dox \ ++ $(srcdir)/touch-event-properties.dox \ + $(srcdir)/touchpads.dox + + diagram_files = \ +@@ -49,6 +50,7 @@ diagram_files = \ + $(srcdir)/svg/thumb-detection.svg \ + $(srcdir)/svg/top-software-buttons.svg \ + $(srcdir)/svg/touchscreen-gestures.svg \ ++ $(srcdir)/svg/touchscreen-touch-event-properties.svg \ + $(srcdir)/svg/twofinger-scrolling.svg + + style_files = \ +diff --git a/doc/page-hierarchy.dox b/doc/page-hierarchy.dox +index 3fdb1f7..72765e2 100644 +--- a/doc/page-hierarchy.dox ++++ b/doc/page-hierarchy.dox +@@ -11,6 +11,7 @@ + @page touchscreens Touchscreens + + - @subpage absolute_axes ++- @subpage touch_event_properties + + @page pointers Mice, Trackballs, etc. + +diff --git a/doc/svg/touchscreen-touch-event-properties.svg b/doc/svg/touchscreen-touch-event-properties.svg +new file mode 100644 +index 0000000..b728f40 +--- /dev/null ++++ b/doc/svg/touchscreen-touch-event-properties.svg +@@ -0,0 +1,347 @@ ++<?xml version="1.0" encoding="UTF-8" standalone="no"?> ++<!-- Created with Inkscape (http://www.inkscape.org/) --> ++ ++<svg ++ xmlns:dc="http://purl.org/dc/elements/1.1/" ++ xmlns:cc="http://creativecommons.org/ns#" ++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ++ xmlns:svg="http://www.w3.org/2000/svg" ++ xmlns="http://www.w3.org/2000/svg" ++ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" ++ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" ++ width="81.778557mm" ++ height="107.62305mm" ++ viewBox="0 0 289.76655 381.34154" ++ id="svg2" ++ version="1.1" ++ inkscape:version="0.91 r13725" ++ sodipodi:docname="touchscreen-touch-event-properties.svg"> ++ <defs ++ id="defs4"> ++ <marker ++ inkscape:stockid="DotL" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="DotL" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4259" ++ d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" ++ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" ++ transform="matrix(0.8,0,0,0.8,5.92,0.8)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <marker ++ inkscape:stockid="CurveOut" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="CurveOut" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4385" ++ 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" ++ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" ++ transform="scale(0.6,0.6)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <marker ++ inkscape:stockid="StopL" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="StopL" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4367" ++ d="M 0,5.65 0,-5.65" ++ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" ++ transform="scale(0.8,0.8)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <marker ++ style="overflow:visible" ++ id="DistanceStart" ++ refX="0" ++ refY="0" ++ orient="auto" ++ inkscape:stockid="DistanceStart" ++ inkscape:isstock="true"> ++ <g ++ id="g2300" ++ style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1"> ++ <path ++ style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.14999998;stroke-linecap:square;stroke-opacity:1" ++ d="M 0,0 2,0" ++ id="path2306" ++ inkscape:connector-curvature="0" /> ++ <path ++ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-opacity:1" ++ d="M 0,0 13,4 9,0 13,-4 0,0 Z" ++ id="path2302" ++ inkscape:connector-curvature="0" /> ++ <path ++ style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-opacity:1" ++ d="M 0,-4 0,40" ++ id="path2304" ++ inkscape:connector-curvature="0" /> ++ </g> ++ </marker> ++ <marker ++ inkscape:stockid="Arrow2Mend" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="Arrow2Mend" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4225" ++ style="fill:#cb004e;fill-opacity:1;fill-rule:evenodd;stroke:#cb004e;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" ++ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" ++ transform="scale(-0.6,-0.6)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <marker ++ inkscape:stockid="Arrow2Lend" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="Arrow2Lend" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4219" ++ style="fill:#cb004e;fill-opacity:1;fill-rule:evenodd;stroke:#cb004e;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" ++ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" ++ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <marker ++ inkscape:stockid="TriangleInL" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="TriangleInL" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4331" ++ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" ++ style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1pt;stroke-opacity:1" ++ transform="scale(-0.8,-0.8)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <marker ++ inkscape:stockid="Arrow2Lstart" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="Arrow2Lstart" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ id="path4216" ++ style="fill:#cb004e;fill-opacity:1;fill-rule:evenodd;stroke:#cb004e;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" ++ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" ++ transform="matrix(1.1,0,0,1.1,1.1,0)" ++ inkscape:connector-curvature="0" /> ++ </marker> ++ <inkscape:path-effect ++ effect="powerstroke" ++ id="path-effect4140" ++ is_visible="true" ++ offset_points="0,0.5" ++ sort_points="true" ++ interpolator_type="Linear" ++ interpolator_beta="0.2" ++ start_linecap_type="zerowidth" ++ linejoin_type="round" ++ miter_limit="4" ++ end_linecap_type="zerowidth" ++ cusp_linecap_type="round" /> ++ <marker ++ inkscape:stockid="TriangleInL" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="TriangleInL-1" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ inkscape:connector-curvature="0" ++ id="path4331-8" ++ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" ++ style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1pt;stroke-opacity:1" ++ transform="scale(-0.8,-0.8)" /> ++ </marker> ++ <marker ++ inkscape:stockid="TriangleInL" ++ orient="auto" ++ refY="0" ++ refX="0" ++ id="TriangleInL-1-3" ++ style="overflow:visible" ++ inkscape:isstock="true"> ++ <path ++ inkscape:connector-curvature="0" ++ id="path4331-8-7" ++ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" ++ style="fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:1pt;stroke-opacity:1" ++ transform="scale(-0.8,-0.8)" /> ++ </marker> ++ </defs> ++ <sodipodi:namedview ++ id="base" ++ pagecolor="#ffffff" ++ bordercolor="#666666" ++ borderopacity="1.0" ++ inkscape:pageopacity="0.0" ++ inkscape:pageshadow="2" ++ inkscape:zoom="0.99999999" ++ inkscape:cx="123.83444" ++ inkscape:cy="279.21547" ++ inkscape:document-units="px" ++ inkscape:current-layer="layer1" ++ showgrid="false" ++ showguides="false" ++ inkscape:window-width="2560" ++ inkscape:window-height="1056" ++ inkscape:window-x="0" ++ inkscape:window-y="24" ++ inkscape:window-maximized="1" ++ fit-margin-top="0" ++ fit-margin-left="0" ++ fit-margin-right="0" ++ fit-margin-bottom="0" /> ++ <metadata ++ id="metadata7"> ++ <rdf:RDF> ++ <cc:Work ++ rdf:about=""> ++ <dc:format>image/svg+xml</dc:format> ++ <dc:type ++ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> ++ <dc:title></dc:title> ++ </cc:Work> ++ </rdf:RDF> ++ </metadata> ++ <g ++ inkscape:label="Layer 1" ++ inkscape:groupmode="layer" ++ id="layer1" ++ transform="translate(-99.549825,-70.836892)"> ++ <path ++ 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)" ++ d="m 231.28087,80.931744 -0.008,371.246666" ++ id="path4144-1-8-1" ++ inkscape:connector-curvature="0" ++ sodipodi:nodetypes="cc" /> ++ <g ++ id="g6309" ++ inkscape:transform-center-x="-9.527809" ++ inkscape:transform-center-y="-8.1612127" ++ transform="matrix(1.171972,1.3632932,-1.3632932,1.171972,275.33248,-179.00364)"> ++ <path ++ sodipodi:nodetypes="cc" ++ inkscape:connector-curvature="0" ++ id="path4144-1-8" ++ d="m 172.88767,70.631028 -0.004,206.500482" ++ 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)" /> ++ <ellipse ++ ry="77.321434" ++ rx="45.89286" ++ cy="180.93364" ++ cx="172.85715" ++ id="path4136" ++ 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" /> ++ <path ++ sodipodi:nodetypes="cc" ++ inkscape:connector-curvature="0" ++ id="path4142" ++ d="m 126.9449,180.93396 91.84596,0.007" ++ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> ++ <path ++ sodipodi:nodetypes="cc" ++ inkscape:connector-curvature="0" ++ id="path4144" ++ d="m 172.84766,103.6564 -0.004,154.59727" ++ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> ++ <text ++ sodipodi:linespacing="125%" ++ id="text4146" ++ y="188.01213" ++ x="128.08986" ++ 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" ++ xml:space="preserve"><tspan ++ y="188.01213" ++ x="128.08986" ++ id="tspan4148" ++ sodipodi:role="line">minor axis</tspan></text> ++ <text ++ transform="matrix(0,-1,1,0,0,0)" ++ sodipodi:linespacing="125%" ++ id="text4150" ++ y="169.33234" ++ x="-256.35562" ++ 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" ++ xml:space="preserve"><tspan ++ y="169.33234" ++ x="-256.35562" ++ id="tspan4152" ++ sodipodi:role="line">major axis</tspan></text> ++ </g> ++ <text ++ xml:space="preserve" ++ 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" ++ x="44.285629" ++ y="369.12045" ++ id="text6877" ++ sodipodi:linespacing="125%" ++ transform="matrix(0.76306478,-0.64632201,0.64632201,0.76306478,0,0)"><tspan ++ sodipodi:role="line" ++ id="tspan6879" ++ x="44.285629" ++ y="369.12045" ++ 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> ++ <text ++ xml:space="preserve" ++ 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" ++ x="237.00804" ++ y="99.788658" ++ id="text6887" ++ sodipodi:linespacing="125%"><tspan ++ sodipodi:role="line" ++ id="tspan6889" ++ x="237.00804" ++ y="99.788658">y axis</tspan></text> ++ <path ++ 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)" ++ id="path7011" ++ sodipodi:type="arc" ++ sodipodi:cx="231.14914" ++ sodipodi:cy="268.54077" ++ sodipodi:rx="79.092262" ++ sodipodi:ry="79.092262" ++ sodipodi:start="4.7157629" ++ sodipodi:end="5.5461565" ++ d="m 231.41599,189.44896 a 79.092262,79.092262 0 0 1 58.2985,25.93463" ++ sodipodi:open="true" /> ++ <text ++ xml:space="preserve" ++ 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" ++ x="232.66777" ++ y="184.40468" ++ id="text7119" ++ sodipodi:linespacing="125%"><tspan ++ sodipodi:role="line" ++ id="tspan7121" ++ x="232.66777" ++ y="184.40468" ++ style="font-size:13.4835043px;fill:#cb004e;fill-opacity:1">orientation</tspan></text> ++ </g> ++</svg> +diff --git a/doc/touch-event-properties.dox b/doc/touch-event-properties.dox +new file mode 100644 +index 0000000..75fc072 +--- /dev/null ++++ b/doc/touch-event-properties.dox +@@ -0,0 +1,42 @@ ++/** ++ at page touch_event_properties Properties of a touch event ++ ++This page gives some overview on touchscreen events. With libinput touchscreens ++provide the event types @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref LIBINPUT_EVENT_TOUCH_UP, ++ at ref LIBINPUT_EVENT_TOUCH_MOTION and @ref LIBINPUT_EVENT_TOUCH_CANCEL. The ++touchscreen events @ref LIBINPUT_EVENT_TOUCH_DOWN and ++ at ref LIBINPUT_EVENT_TOUCH_MOTION provide alongside the actual state change and ++the absolute coordinates (@ref absolute_axes_handling) additional information ++about the touch contact. ++ ++ at image html touchscreen-touch-event-properties.svg "Properties of a touch screen contact" ++ ++Assuming the interaction of fingers with a touch screen, touch contacts are ++approximated with an ellipse. The major axis of the ellipse describes the ++pointing direction of the finger. The minor axis is the perpendicular ++extent of the touching shape. The orientation angle is the clockwise rotation of ++the pointing direction against the y-axis of the touchscreen. ++ ++Additionally to the values shown in the drawing above, most touchscreens also ++provide a pressure value to indicate the force applied with the contact point. ++ ++The support for those contact properties varies between the different ++available touchscreens. In the case of pressure libinput will return the ++maximum pressure value, which is 1.0. If only the major axis but no minor axis ++is present, libinput will assume a circular shape and return the major axis ++value for convenience. If also no major axis value is known 0.0 is returned. ++If the orientation is not available libinput will return 0.0 degrees. ++ ++For querying the touch properties see: ++- @ref libinput_event_touch_get_major_transformed ++- @ref libinput_event_touch_get_minor_transformed ++- @ref libinput_event_touch_get_orientation ++- @ref libinput_event_touch_get_pressure ++ ++For testing which of the touch properties are available see: ++- @ref libinput_event_touch_has_major ++- @ref libinput_event_touch_has_minor ++- @ref libinput_event_touch_has_orientation ++- @ref libinput_event_touch_has_pressure ++ ++*/ +diff --git a/src/evdev.c b/src/evdev.c +index 303e447..29303f8 100644 +--- a/src/evdev.c ++++ b/src/evdev.c +@@ -45,6 +45,10 @@ + + #define DEFAULT_WHEEL_CLICK_ANGLE 15 + #define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT ms2us(200) ++#define DEFAULT_TOUCH_PRESSURE 1 ++#define DEFAULT_TOUCH_ORIENTATION 0 ++#define DEFAULT_TOUCH_MAJOR 0 ++#define DEFAULT_TOUCH_MINOR 0 + + enum evdev_key_type { + EVDEV_KEY_TYPE_NONE, +@@ -245,6 +249,100 @@ evdev_device_transform_y(struct evdev_device *device, + return scale_axis(device->abs.absinfo_y, y, height); + } + ++double ++evdev_device_transform_ellipse_diameter_to_mm(struct evdev_device *device, ++ int diameter, ++ double axis_angle) ++{ ++ double x_res = device->abs.absinfo_x->resolution; ++ double y_res = device->abs.absinfo_y->resolution; ++ ++ if (x_res == y_res) ++ return diameter / x_res; ++ ++ /* resolution differs but no orientation available ++ * -> estimate resolution using the average */ ++ if (device->abs.absinfo_orientation == NULL) { ++ return diameter * 2.0 / (x_res + y_res); ++ } else { ++ /* Why scale x using sine of angle? ++ * axis_angle = 0 indicates that the given diameter ++ * is aligned with the y-axis. */ ++ double x_scaling_ratio = fabs(sin(deg2rad(axis_angle))); ++ double y_scaling_ratio = fabs(cos(deg2rad(axis_angle))); ++ ++ return diameter / (y_res * y_scaling_ratio + ++ x_res * x_scaling_ratio); ++ } ++} ++ ++double ++evdev_device_transform_ellipse_diameter(struct evdev_device *device, ++ int diameter, ++ double axis_angle, ++ uint32_t width, ++ uint32_t height) ++{ ++ double x_res = device->abs.absinfo_x->resolution; ++ double y_res = device->abs.absinfo_y->resolution; ++ double x_scale = width / (device->abs.dimensions.x + 1.0); ++ double y_scale = height / (device->abs.dimensions.y + 1.0); ++ ++ if (x_res == y_res) ++ return diameter * x_scale; ++ ++ /* no orientation available -> estimate resolution using the ++ * average */ ++ if (device->abs.absinfo_orientation == NULL) { ++ return diameter * (x_scale + y_scale) / 2.0; ++ } else { ++ /* Why scale x using sine of angle? ++ * axis_angle = 0 indicates that the given diameter ++ * is aligned with the y-axis. */ ++ double x_scaling_ratio = fabs(sin(deg2rad(axis_angle))); ++ double y_scaling_ratio = fabs(cos(deg2rad(axis_angle))); ++ ++ return diameter * (y_scale * y_scaling_ratio + ++ x_scale * x_scaling_ratio); ++ } ++} ++ ++double ++evdev_device_transform_orientation(struct evdev_device *device, ++ int32_t orientation) ++{ ++ const struct input_absinfo *orientation_info = ++ device->abs.absinfo_orientation; ++ ++ double angle = DEFAULT_TOUCH_ORIENTATION; ++ ++ /* ABS_MT_ORIENTATION is defined as a clockwise rotation - zero ++ * (instead of minimum) is mapped to the y-axis, and maximum is ++ * mapped to the x-axis. So minimum is likely to be negative but ++ * plays no role in scaling the value to degrees.*/ ++ if (orientation_info) ++ angle = (90.0 * orientation) / orientation_info->maximum; ++ ++ return fmod(360.0 + angle, 360.0); ++} ++ ++double ++evdev_device_transform_pressure(struct evdev_device *device, ++ int32_t pressure) ++{ ++ const struct input_absinfo *pressure_info = ++ device->abs.absinfo_pressure; ++ ++ if (pressure_info) { ++ double max_pressure = pressure_info->maximum; ++ double min_pressure = pressure_info->minimum; ++ return (pressure - min_pressure) / ++ (max_pressure - min_pressure); ++ } else { ++ return DEFAULT_TOUCH_PRESSURE; ++ } ++} ++ + static inline void + normalize_delta(struct evdev_device *device, + const struct device_coords *delta, +@@ -282,8 +380,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) + struct normalized_coords accel, unaccel; + struct device_coords point; + struct device_float_coords raw; ++ struct mt_slot *slot_data; ++ struct ellipse default_touch = { ++ .major = DEFAULT_TOUCH_MAJOR, ++ .minor = DEFAULT_TOUCH_MINOR, ++ .orientation = DEFAULT_TOUCH_ORIENTATION ++ }; + + slot = device->mt.slot; ++ slot_data = &device->mt.slots[slot]; + + switch (device->pending_event) { + case EVDEV_NONE: +@@ -314,7 +419,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + +- if (device->mt.slots[slot].seat_slot != -1) { ++ if (slot_data->seat_slot != -1) { + log_bug_kernel(libinput, + "%s: Driver sent multiple touch down for the " + "same slot", +@@ -323,38 +428,52 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) + } + + seat_slot = ffs(~seat->slot_map) - 1; +- device->mt.slots[slot].seat_slot = seat_slot; ++ slot_data->seat_slot = seat_slot; + + if (seat_slot == -1) + break; + + seat->slot_map |= 1 << seat_slot; +- point = device->mt.slots[slot].point; ++ point = slot_data->point; + transform_absolute(device, &point); + +- touch_notify_touch_down(base, time, slot, seat_slot, +- &point); ++ touch_notify_touch_down(base, ++ time, ++ slot, ++ seat_slot, ++ &point, ++ slot_data->available_data, ++ &slot_data->area, ++ slot_data->pressure); + break; + case EVDEV_ABSOLUTE_MT_MOTION: + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + +- seat_slot = device->mt.slots[slot].seat_slot; +- point = device->mt.slots[slot].point; ++ seat_slot = slot_data->seat_slot; ++ ++ point = slot_data->point; + + if (seat_slot == -1) + break; + + transform_absolute(device, &point); +- touch_notify_touch_motion(base, time, slot, seat_slot, +- &point); ++ ++ touch_notify_touch_motion(base, ++ time, ++ slot, ++ seat_slot, ++ &point, ++ slot_data->available_data, ++ &slot_data->area, ++ slot_data->pressure); + break; + case EVDEV_ABSOLUTE_MT_UP: + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + +- seat_slot = device->mt.slots[slot].seat_slot; +- device->mt.slots[slot].seat_slot = -1; ++ seat_slot = slot_data->seat_slot; ++ slot_data->seat_slot = -1; + + if (seat_slot == -1) + break; +@@ -386,7 +505,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) + point = device->abs.point; + transform_absolute(device, &point); + +- touch_notify_touch_down(base, time, -1, seat_slot, &point); ++ touch_notify_touch_down(base, ++ time, ++ -1, ++ seat_slot, ++ &point, ++ TOUCH_SLOT_DATA_NONE, ++ &default_touch, ++ DEFAULT_TOUCH_PRESSURE); + break; + case EVDEV_ABSOLUTE_MOTION: + point = device->abs.point; +@@ -398,8 +524,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) + if (seat_slot == -1) + break; + +- touch_notify_touch_motion(base, time, -1, seat_slot, +- &point); ++ touch_notify_touch_motion(base, ++ time, ++ -1, ++ seat_slot, ++ &point, ++ TOUCH_SLOT_DATA_NONE, ++ &default_touch, ++ DEFAULT_TOUCH_PRESSURE); + } else if (device->seat_caps & EVDEV_DEVICE_POINTER) { + pointer_notify_motion_absolute(base, time, &point); + } +@@ -559,8 +691,9 @@ evdev_process_touch(struct evdev_device *device, + struct input_event *e, + uint64_t time) + { +- switch (e->code) { +- case ABS_MT_SLOT: ++ struct mt_slot *current_slot = &device->mt.slots[device->mt.slot]; ++ ++ if (e->code == ABS_MT_SLOT) { + if ((size_t)e->value >= device->mt.slots_len) { + log_bug_libinput(device->base.seat->libinput, + "%s exceeds slots (%d of %zd)\n", +@@ -571,8 +704,7 @@ evdev_process_touch(struct evdev_device *device, + } + evdev_flush_pending_event(device, time); + device->mt.slot = e->value; +- break; +- case ABS_MT_TRACKING_ID: ++ } else if(e->code == ABS_MT_TRACKING_ID) { + if (device->pending_event != EVDEV_NONE && + device->pending_event != EVDEV_ABSOLUTE_MT_MOTION) + evdev_flush_pending_event(device, time); +@@ -580,17 +712,40 @@ evdev_process_touch(struct evdev_device *device, + device->pending_event = EVDEV_ABSOLUTE_MT_DOWN; + else + device->pending_event = EVDEV_ABSOLUTE_MT_UP; +- break; +- case ABS_MT_POSITION_X: +- device->mt.slots[device->mt.slot].point.x = e->value; +- if (device->pending_event == EVDEV_NONE) +- device->pending_event = EVDEV_ABSOLUTE_MT_MOTION; +- break; +- case ABS_MT_POSITION_Y: +- device->mt.slots[device->mt.slot].point.y = e->value; +- if (device->pending_event == EVDEV_NONE) ++ } else { ++ bool needs_wake = true; ++ ++ switch(e->code) { ++ case ABS_MT_POSITION_X: ++ current_slot->point.x = e->value; ++ break; ++ case ABS_MT_POSITION_Y: ++ current_slot->point.y = e->value; ++ break; ++ case ABS_MT_TOUCH_MAJOR: ++ current_slot->available_data |= TOUCH_SLOT_DATA_MAJOR; ++ current_slot->area.major = e->value; ++ break; ++ case ABS_MT_TOUCH_MINOR: ++ current_slot->available_data |= TOUCH_SLOT_DATA_MINOR; ++ current_slot->area.minor = e->value; ++ break; ++ case ABS_MT_ORIENTATION: ++ current_slot->available_data |= ++ TOUCH_SLOT_DATA_ORIENTATION; ++ current_slot->area.orientation = e->value; ++ break; ++ case ABS_MT_PRESSURE: ++ current_slot->available_data |= ++ TOUCH_SLOT_DATA_PRESSURE; ++ current_slot->pressure = e->value; ++ break; ++ default: ++ needs_wake = false; ++ break; ++ } ++ if (needs_wake && device->pending_event == EVDEV_NONE) + device->pending_event = EVDEV_ABSOLUTE_MT_MOTION; +- break; + } + } + +@@ -1941,6 +2096,13 @@ evdev_configure_device(struct evdev_device *device) + return -1; + } + ++ device->abs.absinfo_orientation = ++ libevdev_get_abs_info(evdev, ++ ABS_MT_ORIENTATION); ++ device->abs.absinfo_pressure = ++ libevdev_get_abs_info(evdev, ++ ABS_MT_PRESSURE); ++ + if (!evdev_is_fake_mt_device(device)) + evdev_fix_android_mt(device); + +diff --git a/src/evdev.h b/src/evdev.h +index e44a65d..383e682 100644 +--- a/src/evdev.h ++++ b/src/evdev.h +@@ -112,6 +112,9 @@ enum evdev_device_model { + struct mt_slot { + int32_t seat_slot; + struct device_coords point; ++ enum touch_slot_data available_data; ++ struct ellipse area; ++ int32_t pressure; + }; + + struct evdev_device { +@@ -128,6 +131,8 @@ struct evdev_device { + int fd; + struct { + const struct input_absinfo *absinfo_x, *absinfo_y; ++ const struct input_absinfo *absinfo_pressure, ++ *absinfo_orientation; + int fake_resolution; + + struct device_coords point; +@@ -349,6 +354,26 @@ double + evdev_device_transform_y(struct evdev_device *device, + double y, + uint32_t height); ++double ++evdev_device_transform_ellipse_diameter_to_mm(struct evdev_device *device, ++ int32_t diameter, ++ double axis_angle); ++ ++double ++evdev_device_transform_ellipse_diameter(struct evdev_device *device, ++ int32_t diameter, ++ double axis_angle, ++ uint32_t width, ++ uint32_t height); ++ ++double ++evdev_device_transform_orientation(struct evdev_device *device, ++ int32_t orientation); ++ ++double ++evdev_device_transform_pressure(struct evdev_device *device, ++ int32_t pressure); ++ + int + evdev_device_suspend(struct evdev_device *device); + +diff --git a/src/libinput-private.h b/src/libinput-private.h +index 8b161cc..0060030 100644 +--- a/src/libinput-private.h ++++ b/src/libinput-private.h +@@ -40,6 +40,11 @@ struct device_coords { + int x, y; + }; + ++/* Ellipse parameters in device coordinates */ ++struct ellipse { ++ int major, minor, orientation; ++}; ++ + /* + * A coordinate pair in device coordinates, capable of holding non discrete + * values, this is necessary e.g. when device coordinates get averaged. +@@ -58,6 +63,16 @@ struct discrete_coords { + int x, y; + }; + ++enum touch_slot_data { ++ TOUCH_SLOT_DATA_NONE = 0, ++ TOUCH_SLOT_DATA_MAJOR = (1 << 1), ++ TOUCH_SLOT_DATA_MINOR = (1 << 2), ++ TOUCH_SLOT_DATA_ORIENTATION = (1 << 3), ++ TOUCH_SLOT_DATA_PRESSURE = (1 << 4),