Merge branch 'master' into tablet-support

sendevents config tests currently disabled for LITEST_TABLET until that gains
the matching bits in the dispatch.

Conflicts:
	src/evdev.c
	src/libinput.c
	test/litest.c
	test/litest.h
This commit is contained in:
Peter Hutterer 2014-09-22 15:42:13 +10:00
commit a6f18c9cca
42 changed files with 4871 additions and 1319 deletions

View file

@ -1,7 +1,7 @@
AC_PREREQ([2.64])
m4_define([libinput_major_version], [0])
m4_define([libinput_minor_version], [4])
m4_define([libinput_minor_version], [6])
m4_define([libinput_micro_version], [0])
m4_define([libinput_version],
[libinput_major_version.libinput_minor_version.libinput_micro_version])
@ -30,7 +30,7 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
# - If binary compatibility has been broken (eg removed or changed interfaces)
# change to C+1:0:0
# - If the interface is the same as the previous version, change to C:R+1:A
LIBINPUT_LT_VERSION=3:0:0
LIBINPUT_LT_VERSION=5:0:0
AC_SUBST(LIBINPUT_LT_VERSION)
AM_SILENT_RULES([yes])
@ -96,7 +96,7 @@ AC_ARG_ENABLE(tests,
[build_tests="$enableval"],
[build_tests="auto"])
PKG_CHECK_MODULES(CHECK, [check >= 0.9.9], [HAVE_CHECK="yes"], [HAVE_CHECK="no"])
PKG_CHECK_MODULES(CHECK, [check >= 0.9.10], [HAVE_CHECK="yes"], [HAVE_CHECK="no"])
if test "x$build_tests" = "xauto"; then
build_tests="$HAVE_CHECK"

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="2190px" height="1624px" version="1.1">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="2180px" height="1624px" version="1.1">
<defs/>
<g transform="translate(0.5,0.5)">
<path d="M 862 441 L 894 441" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
@ -68,13 +68,13 @@
<path d="M 712 441 L 668 441 Q 658 441 658 451 L 658 762" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 786 62 L 786 81 Q 786 91 786 101 L 786 114" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 786 120 L 783 113 L 786 114 L 790 113 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="1753" y="472" width="120" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<rect x="1753" y="412" width="120" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="489">Check state of</text>
<text x="1813" y="503">all touches</text>
<text x="1813" y="429">Check state of</text>
<text x="1813" y="443">all touches</text>
</g>
<path d="M 1813 512 L 1813 518 Q 1813 524 1813 529 L 1813 534" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 526 L 1813 535 L 1818 526" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 452 L 1813 458 Q 1813 465 1813 470 L 1813 475" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 467 L 1813 476 L 1818 467" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<ellipse cx="1813" cy="72" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<path d="M 1813 87 L 1813 115 Q 1813 125 1813 135 L 1813 160" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 152 L 1813 161 L 1818 152" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
@ -82,88 +82,89 @@
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="41">tp_post_softbutton_buttons()</text>
</g>
<path d="M 1813 212 L 1908 267 L 1813 322 L 1718 267 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 192 L 1908 247 L 1813 302 L 1718 247 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="264">!buttons.click_pend</text>
<text x="1813" y="278">&amp;&amp; current == old</text>
<text x="1813" y="244">!buttons.click_pend</text>
<text x="1813" y="258">&amp;&amp; current == old</text>
</g>
<path d="M 1908 267 L 1968 267 Q 1978 267 1988 267 L 2056 267" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2048 272 L 2057 267 L 2048 263" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1908 247 L 1968 247 Q 1978 247 1988 247 L 2056 247" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2048 252 L 2057 247 L 2048 243" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1998" y="252" width="18" height="14" stroke-width="0"/>
<text x="1999" y="261">yes</text>
<rect fill="#ffffff" stroke="none" x="1998" y="228" width="24" height="18" stroke-width="0"/>
<text x="1999" y="241">yes</text>
</g>
<path d="M 1813 322 L 1813 332 Q 1813 342 1813 351 L 1813 360" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 352 L 1813 361 L 1818 352" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 302 L 1813 307 Q 1813 313 1813 317 L 1813 321" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 313 L 1813 322 L 1818 313" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1815" y="330" width="15" height="14" stroke-width="0"/>
<text x="1815" y="339">no</text>
<rect fill="#ffffff" stroke="none" x="1830" y="310" width="18" height="18" stroke-width="0"/>
<text x="1830" y="319">no</text>
</g>
<ellipse cx="2073" cy="267" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2073" cy="267" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<rect x="1708" y="112" width="200" height="60" rx="24" ry="24" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2073" cy="247" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2073" cy="247" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<rect x="1713" y="102" width="200" height="70" rx="28" ry="28" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1808" y="132">current = buttons.state &amp; 0x01</text>
<text x="1808" y="146">old = buttons.old_state &amp; 0x01</text>
<text x="1808" y="160">button = 0</text>
<text x="1813" y="120">current = buttons.state &amp; 0x01</text>
<text x="1813" y="134">old = buttons.old_state &amp; 0x01</text>
<text x="1813" y="148">button = 0</text>
<text x="1813" y="162">is_top = 0</text>
</g>
<path d="M 1813 172 L 1813 182 Q 1813 192 1813 201 L 1813 210" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 202 L 1813 211 L 1818 202" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 536 L 1928 607 L 1813 678 L 1698 607 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 172 L 1813 177 Q 1813 182 1813 186 L 1813 190" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 182 L 1813 191 L 1818 182" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 568 L 1918 626 L 1813 684 L 1708 626 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="611">All touches are in state none</text>
<text x="1813" y="630">All touches are in state none</text>
</g>
<path d="M 1813 678 L 1813 684 Q 1813 690 1813 695 L 1813 700" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 692 L 1813 701 L 1818 692" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 684 L 1813 691 Q 1813 697 1813 702 L 1813 708" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 700 L 1813 709 L 1818 700" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1820" y="687" width="15" height="14" stroke-width="0"/>
<text x="1820" y="696">no</text>
<rect fill="#ffffff" stroke="none" x="1820" y="691" width="18" height="18" stroke-width="0"/>
<text x="1820" y="704">no</text>
</g>
<path d="M 1928 607 L 1938 607 Q 1948 607 1957 607 L 1966 607" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1958 612 L 1967 607 L 1958 603" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1918 626 L 1936 626 Q 1946 626 1955 626 L 1971 626" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1963 631 L 1972 626 L 1963 622" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1930" y="615" width="18" height="14" stroke-width="0"/>
<text x="1930" y="624">yes</text>
<rect fill="#ffffff" stroke="none" x="1920" y="634" width="24" height="18" stroke-width="0"/>
<text x="1920" y="643">yes</text>
</g>
<rect x="1968" y="587" width="150" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<rect x="1973" y="606" width="150" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="2043" y="611">buttons.click_pend = 1</text>
<text x="2048" y="630">buttons.click_pend = 1</text>
</g>
<path d="M 2118 607 L 2128 607 Q 2138 607 2147 607 L 2156 607" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2148 612 L 2157 607 L 2148 603" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 702 L 1938 787 L 1813 872 L 1688 787 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2123 626 L 2128 626 Q 2133 626 2137 626 L 2141 626" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2133 631 L 2142 626 L 2133 622" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 710 L 1938 795 L 1813 880 L 1688 795 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="777">(Some touches are in middle) ||</text>
<text x="1813" y="791">((Some touches are in right) &amp;&amp;</text>
<text x="1813" y="805">(Some touches are in left))</text>
<text x="1813" y="785">(Some touches are in middle) ||</text>
<text x="1813" y="799">((Some touches are in right) &amp;&amp;</text>
<text x="1813" y="813">(Some touches are in left))</text>
</g>
<path d="M 1938 787 L 1943 787 Q 1948 787 1957 787 L 1966 787" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1958 792 L 1967 787 L 1958 783" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1938 795 L 1943 795 Q 1948 795 1957 795 L 1966 795" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1958 800 L 1967 795 L 1958 791" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1941" y="795" width="18" height="14" stroke-width="0"/>
<text x="1942" y="804">yes</text>
<rect fill="#ffffff" stroke="none" x="1941" y="803" width="24" height="18" stroke-width="0"/>
<text x="1942" y="812">yes</text>
</g>
<rect x="1968" y="767" width="160" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<rect x="1968" y="775" width="160" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="2048" y="791">button = BTN_MIDDLE</text>
<text x="2048" y="799">button = BTN_MIDDLE</text>
</g>
<path d="M 2128 787 L 2158 787 Q 2168 787 2168 797 L 2168 1207 Q 2168 1217 2158 1217 L 1913 1217" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1921 1213 L 1912 1217 L 1921 1222" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 362 L 1876 396 L 1813 431 L 1751 396 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2128 795 L 2158 795 Q 2168 795 2168 805 L 2168 1197 Q 2168 1207 2158 1207 L 1913 1207" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1921 1203 L 1912 1207 L 1921 1212" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 323 L 1876 357 L 1813 392 L 1751 357 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="400">current</text>
<text x="1813" y="361">current</text>
</g>
<path d="M 1751 396 L 1601 396 Q 1591 396 1591 406 L 1591 1172 Q 1591 1182 1591 1182 L 1592 1182" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1596 1180 L 1591 1182 L 1596 1184" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1751 357 L 1606 357 Q 1596 357 1596 367 L 1596 1160" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1592 1152 L 1596 1161 L 1601 1152" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1688" y="381" width="15" height="14" stroke-width="0"/>
<text x="1688" y="390">no</text>
<rect fill="#ffffff" stroke="none" x="1687" y="338" width="18" height="18" stroke-width="0"/>
<text x="1687" y="351">no</text>
</g>
<path d="M 1813 431 L 1813 441 Q 1813 451 1813 461 L 1813 470" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 462 L 1813 471 L 1818 462" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 392 L 1813 397 Q 1813 402 1813 406 L 1813 410" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 402 L 1813 411 L 1818 402" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1815" y="438" width="18" height="14" stroke-width="0"/>
<text x="1815" y="448">yes</text>
<rect fill="#ffffff" stroke="none" x="1830" y="390" width="24" height="18" stroke-width="0"/>
<text x="1830" y="399">yes</text>
</g>
<path d="M 1813 902 L 1909 967 L 1813 1032 L 1717 967 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
@ -172,13 +173,13 @@
<path d="M 1909 967 L 1928 967 Q 1938 967 1948 967 L 1966 967" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1958 972 L 1967 967 L 1958 963" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1930" y="975" width="18" height="14" stroke-width="0"/>
<rect fill="#ffffff" stroke="none" x="1930" y="975" width="24" height="18" stroke-width="0"/>
<text x="1930" y="984">yes</text>
</g>
<path d="M 1813 872 L 1813 880 Q 1813 887 1813 893 L 1813 900" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 880 L 1813 886 Q 1813 891 1813 895 L 1813 900" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 892 L 1813 901 L 1818 892" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1820" y="887" width="15" height="14" stroke-width="0"/>
<rect fill="#ffffff" stroke="none" x="1820" y="883" width="18" height="18" stroke-width="0"/>
<text x="1820" y="896">no</text>
</g>
<rect x="1968" y="947" width="160" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
@ -192,25 +193,28 @@
<path d="M 1813 1032 L 1813 1047 Q 1813 1057 1813 1067 L 1813 1080" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 1072 L 1813 1081 L 1818 1072" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1815" y="1044" width="15" height="14" stroke-width="0"/>
<rect fill="#ffffff" stroke="none" x="1815" y="1040" width="18" height="18" stroke-width="0"/>
<text x="1815" y="1053">no</text>
</g>
<rect x="1716" y="1182" width="195" height="70" rx="28" ry="28" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<rect x="1716" y="1162" width="195" height="90" rx="36" ry="36" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="1214">buttons.active = button</text>
<text x="1813" y="1228">state = BUTTON_PRESSED</text>
<text x="1814" y="1197">buttons.active = button</text>
<text x="1814" y="1211">buttons.active_is_top = is_top</text>
<text x="1814" y="1225">state = BUTTON_PRESSED</text>
</g>
<path d="M 1813 1252 L 1813 1282 Q 1813 1292 1803 1292 L 1713 1292 Q 1703 1292 1703 1302 L 1703 1330" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1814 1252 L 1814 1282 Q 1814 1292 1804 1292 L 1713 1292 Q 1703 1292 1703 1302 L 1703 1330" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1699 1322 L 1703 1331 L 1708 1322" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 1122 L 1813 1142 Q 1813 1152 1813 1162 L 1813 1180" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 1172 L 1813 1181 L 1818 1172" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2128 967 L 2158 967 Q 2168 967 2168 977 L 2168 1207 Q 2168 1217 2158 1217 L 1913 1217" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1921 1213 L 1912 1217 L 1921 1222" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="1493" y="1182" width="195" height="70" rx="28" ry="28" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<path d="M 1813 1122 L 1813 1122 Q 1813 1122 1813 1132 L 1813 1152 Q 1813 1162 1813 1161 L 1813 1160" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 1152 L 1813 1161 L 1818 1152" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 2128 967 L 2158 967 Q 2168 967 2168 977 L 2168 1197 Q 2168 1207 2158 1207 L 1913 1207" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1921 1203 L 1912 1207 L 1921 1212" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="1493" y="1162" width="205" height="90" rx="36" ry="36" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1591" y="1207">button = buttons.active</text>
<text x="1591" y="1221">buttons.active = 0</text>
<text x="1591" y="1235">state = BUTTON_RELEASED</text>
<text x="1596" y="1183">button = buttons.active</text>
<text x="1596" y="1197">is_top = buttons.active_is_top</text>
<text x="1596" y="1211">buttons.active = 0</text>
<text x="1596" y="1225">buttons.active_is_top = 0</text>
<text x="1596" y="1239">state = BUTTON_RELEASED</text>
</g>
<rect x="1628" y="1332" width="150" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
@ -218,7 +222,7 @@
</g>
<path d="M 1703 1372 L 1703 1380 Q 1703 1387 1703 1393 L 1703 1400" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1699 1392 L 1703 1401 L 1708 1392" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1591 1252 L 1591 1282 Q 1591 1292 1601 1292 L 1693 1292 Q 1703 1292 1703 1302 L 1703 1330" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1596 1252 L 1596 1282 Q 1596 1292 1606 1292 L 1693 1292 Q 1703 1292 1703 1302 L 1703 1330" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1699 1322 L 1703 1331 L 1708 1322" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1703 1402 L 1743 1422 L 1703 1442 L 1663 1422 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
@ -227,26 +231,26 @@
<path d="M 1743 1422 L 1808 1422 Q 1818 1422 1818 1432 L 1818 1597 Q 1818 1607 1808 1607 L 1720 1607" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1728 1603 L 1719 1607 L 1728 1612" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1745" y="1407" width="15" height="14" stroke-width="0"/>
<rect fill="#ffffff" stroke="none" x="1745" y="1403" width="18" height="18" stroke-width="0"/>
<text x="1745" y="1416">no</text>
</g>
<path d="M 1703 1442 L 1703 1452 Q 1703 1462 1703 1471 L 1703 1480" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1699 1472 L 1703 1481 L 1708 1472" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1705" y="1450" width="18" height="14" stroke-width="0"/>
<rect fill="#ffffff" stroke="none" x="1705" y="1450" width="24" height="18" stroke-width="0"/>
<text x="1705" y="1459">yes</text>
</g>
<rect x="1618" y="1482" width="170" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1703" y="1499">pointer_notify_button(</text>
<text x="1703" y="1513">button, state)</text>
<text x="1703" y="1499">tp_notify_softbutton(</text>
<text x="1703" y="1513">button, is_top, state)</text>
</g>
<path d="M 1703 1522 L 1703 1542 Q 1703 1552 1703 1562 L 1703 1590" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1699 1582 L 1703 1591 L 1708 1582" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<ellipse cx="1703" cy="1607" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1703" cy="1607" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2173" cy="607" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2173" cy="607" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2158" cy="626" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="2158" cy="626" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<path d="M 456 232 C 458 229 461 227 464 227 L 490 227 C 493 227 496 229 498 232 L 514 256 C 514 257 514 259 514 260 L 498 284 C 496 287 493 289 490 289 L 464 289 C 461 289 458 287 456 284 L 440 260 C 440 259 440 257 440 256 L 456 232 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="477" y="255">finger in</text>
@ -261,8 +265,8 @@
<text x="477" y="453">curr = button</text>
<text x="477" y="467">start enter timeout</text>
</g>
<path d="M 477 289 L 477 385" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 477 391 L 474 384 L 477 385 L 481 384 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 477 289 L 477 330 Q 477 340 477 350 L 477 385" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 477 391 L 473 384 L 477 385 L 480 384 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 552 442 L 648 442 Q 658 442 658 452 L 658 762" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="412" y="712" width="130" height="100" rx="6" ry="6" fill="#ccffcc" stroke="#000000" stroke-width="2" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
@ -356,5 +360,27 @@
<path d="M 737 32 L 730 36 L 732 32 L 730 29 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 66 762 L 18 762 Q 8 762 8 752 L 8 42 Q 8 32 18 32 L 732 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 737 32 L 730 36 L 732 32 L 730 29 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 477 L 1876 511 L 1813 546 L 1751 511 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="515">touches in top?</text>
</g>
<path d="M 1876 511 L 1928 511 Q 1938 511 1938 518 L 1938 524" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1934 516 L 1938 525 L 1943 516" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1890" y="500" width="24" height="18" stroke-width="0"/>
<text x="1890" y="509">yes</text>
</g>
<rect x="1898" y="526" width="80" height="30" rx="12" ry="12" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1938" y="545">is_top = 1</text>
</g>
<path d="M 1938 556 L 1938 562 Q 1938 568 1928 568 L 1815 568" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1823 564 L 1814 568 L 1823 573" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1813 546 L 1813 554 Q 1813 562 1813 564 L 1813 566" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1809 558 L 1813 567 L 1818 558" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1820" y="550" width="18" height="18" stroke-width="0"/>
<text x="1820" y="559">no</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -163,6 +163,7 @@ struct input_keymap_entry {
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)

View file

@ -36,7 +36,7 @@ libinput_la_CFLAGS = -I$(top_srcdir)/include \
$(LIBEVDEV_CFLAGS) \
$(GCC_CFLAGS)
libinput_la_LDFLAGS = -version-info $(LIBINPUT_LT_VERSION)
libinput_la_LDFLAGS = -version-info $(LIBINPUT_LT_VERSION) -shared
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libinput.pc

View file

@ -484,6 +484,67 @@ tp_process_button(struct tp_dispatch *tp,
return 0;
}
void
tp_release_all_buttons(struct tp_dispatch *tp,
uint64_t time)
{
if (tp->buttons.state) {
tp->buttons.state = 0;
tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
}
}
void
tp_init_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult)
{
int width, height;
const struct input_absinfo *absinfo_x, *absinfo_y;
int xoffset, yoffset;
int yres;
absinfo_x = device->abs.absinfo_x;
absinfo_y = device->abs.absinfo_y;
xoffset = absinfo_x->minimum,
yoffset = absinfo_y->minimum;
yres = absinfo_y->resolution;
width = abs(absinfo_x->maximum - absinfo_x->minimum);
height = abs(absinfo_y->maximum - absinfo_y->minimum);
/* button height: 10mm or 15% of the touchpad height,
whichever is smaller */
if (yres > 1 && (height * 0.15/yres) > 10) {
tp->buttons.bottom_area.top_edge =
absinfo_y->maximum - 10 * yres;
} else {
tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
}
tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
if (tp->buttons.has_topbuttons) {
/* T440s has the top button line 5mm from the top, event
analysis has shown events to start down to ~10mm from the
top - which maps to 15%. We allow the caller to enlarge the
area using a multiplier for the touchpad disabled case. */
double topsize_mm = 10 * topbutton_size_mult;
double topsize_pct = .15 * topbutton_size_mult;
if (yres > 1) {
tp->buttons.top_area.bottom_edge =
yoffset + topsize_mm * yres;
} else {
tp->buttons.top_area.bottom_edge = height * topsize_pct + yoffset;
}
tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
} else {
tp->buttons.top_area.bottom_edge = INT_MIN;
}
}
int
tp_init_buttons(struct tp_dispatch *tp,
struct evdev_device *device)
@ -521,39 +582,11 @@ tp_init_buttons(struct tp_dispatch *tp,
tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
if (libevdev_get_id_vendor(device->evdev) == 0x5ac) /* Apple */
if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
tp->buttons.use_clickfinger = true;
if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
int xoffset = absinfo_x->minimum,
yoffset = absinfo_y->minimum;
int yres = absinfo_y->resolution;
/* button height: 10mm or 15% of the touchpad height,
whichever is smaller */
if (yres > 1 && (height * 0.15/yres) > 10) {
tp->buttons.bottom_area.top_edge =
absinfo_y->maximum - 10 * yres;
} else {
tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
}
tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
if (tp->buttons.has_topbuttons) {
/* T440s has the top button line 5mm from the top,
make the buttons 6mm high */
if (yres > 1) {
tp->buttons.top_area.bottom_edge =
yoffset + 6 * yres;
} else {
tp->buttons.top_area.bottom_edge = height * .08 + yoffset;
}
tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
} else {
tp->buttons.top_area.bottom_edge = INT_MIN;
}
tp_init_softbuttons(tp, device, 1.0);
} else {
tp->buttons.bottom_area.top_edge = INT_MAX;
tp->buttons.top_area.bottom_edge = INT_MIN;
@ -606,11 +639,12 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
state = LIBINPUT_BUTTON_STATE_RELEASED;
}
if (button)
pointer_notify_button(&tp->device->base,
time,
button,
state);
if (button) {
evdev_pointer_notify_button(tp->device,
time,
button,
state);
}
return 1;
}
@ -632,10 +666,10 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
else
state = LIBINPUT_BUTTON_STATE_RELEASED;
pointer_notify_button(&tp->device->base,
time,
button,
state);
evdev_pointer_notify_button(tp->device,
time,
button,
state);
}
button++;
@ -646,16 +680,46 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
return 0;
}
static void
tp_notify_softbutton(struct tp_dispatch *tp,
uint64_t time,
uint32_t button,
uint32_t is_topbutton,
enum libinput_button_state state)
{
/* If we've a trackpoint, send top buttons through the trackpoint */
if (is_topbutton && tp->buttons.trackpoint) {
struct evdev_dispatch *dispatch = tp->buttons.trackpoint->dispatch;
struct input_event event;
event.time.tv_sec = time/1000;
event.time.tv_usec = (time % 1000) * 1000;
event.type = EV_KEY;
event.code = button;
event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0;
dispatch->interface->process(dispatch, tp->buttons.trackpoint,
&event, time);
return;
}
/* Ignore button events not for the trackpoint while suspended */
if (tp->device->suspended)
return;
evdev_pointer_notify_button(tp->device, time, button, state);
}
static int
tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
{
uint32_t current, old, button;
uint32_t current, old, button, is_top;
enum libinput_button_state state;
enum { AREA = 0x01, LEFT = 0x02, MIDDLE = 0x04, RIGHT = 0x08 };
current = tp->buttons.state;
old = tp->buttons.old_state;
button = 0;
is_top = 0;
if (!tp->buttons.click_pending && current == old)
return 0;
@ -668,15 +732,18 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
case BUTTON_EVENT_IN_AREA:
button |= AREA;
break;
case BUTTON_EVENT_IN_BOTTOM_L:
case BUTTON_EVENT_IN_TOP_L:
is_top = 1;
case BUTTON_EVENT_IN_BOTTOM_L:
button |= LEFT;
break;
case BUTTON_EVENT_IN_TOP_M:
is_top = 1;
button |= MIDDLE;
break;
case BUTTON_EVENT_IN_BOTTOM_R:
case BUTTON_EVENT_IN_TOP_R:
is_top = 1;
case BUTTON_EVENT_IN_BOTTOM_R:
button |= RIGHT;
break;
default:
@ -698,20 +765,21 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
button = BTN_LEFT;
tp->buttons.active = button;
tp->buttons.active_is_topbutton = is_top;
state = LIBINPUT_BUTTON_STATE_PRESSED;
} else {
button = tp->buttons.active;
is_top = tp->buttons.active_is_topbutton;
tp->buttons.active = 0;
tp->buttons.active_is_topbutton = 0;
state = LIBINPUT_BUTTON_STATE_RELEASED;
}
tp->buttons.click_pending = false;
if (button)
pointer_notify_button(&tp->device->base,
time,
button,
state);
tp_notify_softbutton(tp, time, button, is_top, state);
return 1;
}

View file

@ -113,10 +113,10 @@ tp_tap_notify(struct tp_dispatch *tp,
return;
}
pointer_notify_button(&tp->device->base,
time,
button,
state);
evdev_pointer_notify_button(tp->device,
time,
button,
state);
}
static void
@ -221,7 +221,6 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_TOUCH:
tp->tap.state = TAP_STATE_DRAGGING_OR_DOUBLETAP;
tp_tap_clear_timer(tp);
break;
case TAP_EVENT_TIMEOUT:
tp->tap.state = TAP_STATE_IDLE;
@ -253,6 +252,7 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_MOTION:
tp_tap_clear_timer(tp);
/* fallthrough */
case TAP_EVENT_TIMEOUT:
tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
break;
@ -541,7 +541,10 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
struct tp_touch *t;
int filter_motion = 0;
if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
/* Handle queued button pressed events from clickpads. For touchpads
* with separate physical buttons, ignore button pressed events so they
* don't interfere with tapping. */
if (tp->buttons.is_clickpad && tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
tp_tap_handle_event(tp, NULL, TAP_EVENT_BUTTON, time);
tp_for_each_touch(tp, t) {
@ -616,7 +619,7 @@ static int
tp_tap_config_count(struct libinput_device *device)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp;
struct tp_dispatch *tp = NULL;
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
@ -625,32 +628,34 @@ tp_tap_config_count(struct libinput_device *device)
}
static enum libinput_config_status
tp_tap_config_set_enabled(struct libinput_device *device, int enabled)
tp_tap_config_set_enabled(struct libinput_device *device,
enum libinput_config_tap_state enabled)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp;
struct tp_dispatch *tp = NULL;
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
tp->tap.enabled = enabled;
tp->tap.enabled = (enabled == LIBINPUT_CONFIG_TAP_ENABLED);
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
static int
static enum libinput_config_tap_state
tp_tap_config_is_enabled(struct libinput_device *device)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp;
struct tp_dispatch *tp = NULL;
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
return tp->tap.enabled;
return tp->tap.enabled ? LIBINPUT_CONFIG_TAP_ENABLED :
LIBINPUT_CONFIG_TAP_DISABLED;
}
static int
static enum libinput_config_tap_state
tp_tap_config_get_default(struct libinput_device *device)
{
/**
@ -662,7 +667,7 @@ tp_tap_config_get_default(struct libinput_device *device)
* usually know where to enable it, or at least you can search for
* it.
*/
return false;
return LIBINPUT_CONFIG_TAP_DISABLED;
}
int
@ -688,3 +693,9 @@ tp_destroy_tap(struct tp_dispatch *tp)
{
libinput_timer_cancel(&tp->tap.timer);
}
void
tp_release_all_taps(struct tp_dispatch *tp, uint64_t now)
{
tp_tap_handle_timeout(now, tp);
}

View file

@ -128,23 +128,25 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
}
static inline void
tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
if (t->state != TOUCH_UPDATE) {
tp_motion_history_reset(t);
t->dirty = true;
t->state = TOUCH_BEGIN;
t->pinned.is_pinned = false;
tp->nfingers_down++;
assert(tp->nfingers_down >= 1);
tp->queued |= TOUCHPAD_EVENT_MOTION;
}
if (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE)
return;
tp_motion_history_reset(t);
t->dirty = true;
t->state = TOUCH_BEGIN;
t->pinned.is_pinned = false;
t->millis = time;
tp->nfingers_down++;
assert(tp->nfingers_down >= 1);
tp->queued |= TOUCHPAD_EVENT_MOTION;
}
static inline void
tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
if (t->state == TOUCH_NONE)
if (t->state == TOUCH_END || t->state == TOUCH_NONE)
return;
t->dirty = true;
@ -152,6 +154,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
t->palm.is_palm = false;
t->state = TOUCH_END;
t->pinned.is_pinned = false;
t->millis = time;
assert(tp->nfingers_down >= 1);
tp->nfingers_down--;
tp->queued |= TOUCHPAD_EVENT_MOTION;
@ -160,7 +163,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
static double
tp_estimate_delta(int x0, int x1, int x2, int x3)
{
return (x0 + x1 - x2 - x3) / 4;
return (x0 + x1 - x2 - x3) / 4.0;
}
void
@ -206,11 +209,10 @@ tp_process_absolute(struct tp_dispatch *tp,
tp->slot = e->value;
break;
case ABS_MT_TRACKING_ID:
t->millis = time;
if (e->value != -1)
tp_begin_touch(tp, t);
tp_begin_touch(tp, t, time);
else
tp_end_touch(tp, t);
tp_end_touch(tp, t, time);
}
}
@ -245,7 +247,7 @@ tp_process_fake_touch(struct tp_dispatch *tp,
struct tp_touch *t;
unsigned int fake_touches;
unsigned int nfake_touches;
unsigned int i;
unsigned int i, start;
unsigned int shift;
if (e->code != BTN_TOUCH &&
@ -266,23 +268,18 @@ tp_process_fake_touch(struct tp_dispatch *tp,
fake_touches >>= 1;
}
for (i = 0; i < tp->ntouches; i++) {
/* For single touch tps we use BTN_TOUCH for begin / end of touch 0 */
start = tp->has_mt ? tp->real_touches : 0;
for (i = start; i < tp->ntouches; i++) {
t = tp_get_touch(tp, i);
if (i >= nfake_touches) {
if (t->state != TOUCH_NONE) {
tp_end_touch(tp, t);
t->millis = time;
}
} else if (t->state != TOUCH_UPDATE &&
t->state != TOUCH_BEGIN) {
t->state = TOUCH_NONE;
tp_begin_touch(tp, t);
t->millis = time;
t->fake =true;
}
if (i < nfake_touches)
tp_begin_touch(tp, t, time);
else
tp_end_touch(tp, t, time);
}
assert(tp->nfingers_down == nfake_touches);
/* On mt the actual touch info may arrive after BTN_TOOL_FOO */
assert(tp->has_mt || tp->nfingers_down == nfake_touches);
}
static void
@ -300,8 +297,7 @@ tp_process_key(struct tp_dispatch *tp,
case BTN_TOOL_DOUBLETAP:
case BTN_TOOL_TRIPLETAP:
case BTN_TOOL_QUADTAP:
if (!tp->has_mt)
tp_process_fake_touch(tp, e, time);
tp_process_fake_touch(tp, e, time);
break;
}
}
@ -406,17 +402,25 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
struct tp_touch *first = tp_get_touch(tp, 0);
unsigned int i;
tp_for_each_touch(tp, t) {
if (!tp->has_mt && t != first && first->fake) {
for (i = 0; i < tp->ntouches; i++) {
t = tp_get_touch(tp, i);
/* semi-mt finger postions may "jump" when nfingers changes */
if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
tp_motion_history_reset(t);
if (i >= tp->real_touches && t->state != TOUCH_NONE) {
t->x = first->x;
t->y = first->y;
if (!t->dirty)
t->dirty = first->dirty;
} else if (!t->dirty) {
continue;
}
if (!t->dirty)
continue;
tp_palm_detect(tp, t, time);
tp_motion_hysteresis(tp, t);
@ -447,15 +451,15 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
if (!t->dirty)
continue;
if (t->state == TOUCH_END) {
if (t->state == TOUCH_END)
t->state = TOUCH_NONE;
t->fake = false;
} else if (t->state == TOUCH_BEGIN)
else if (t->state == TOUCH_BEGIN)
t->state = TOUCH_UPDATE;
t->dirty = false;
}
tp->old_nfingers_down = tp->nfingers_down;
tp->buttons.old_state = tp->buttons.state;
tp->queued = TOUCHPAD_EVENT_NONE;
@ -488,47 +492,7 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
dy /= nchanged;
tp_filter_motion(tp, &dx, &dy, time);
/* Require at least five px scrolling to start */
if (dy <= -5.0 || dy >= 5.0)
tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
if (dx <= -5.0 || dx >= 5.0)
tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
if (dy != 0.0 &&
(tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))) {
pointer_notify_axis(&tp->device->base,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
dy);
}
if (dx != 0.0 &&
(tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))) {
pointer_notify_axis(&tp->device->base,
time,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
dx);
}
}
static void
tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
{
/* terminate scrolling with a zero scroll event */
if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
pointer_notify_axis(&tp->device->base,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
0);
if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
pointer_notify_axis(&tp->device->base,
time,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
0);
tp->scroll.direction = 0;
evdev_post_scroll(tp->device, time, dx, dy);
}
static int
@ -544,7 +508,7 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
}
if (nfingers_down != 2) {
tp_stop_scroll_events(tp, time);
evdev_stop_scroll(tp->device, time);
return 0;
}
@ -559,11 +523,17 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
double dx, dy;
int consumed = 0;
/* Only post (top) button events while suspended */
if (tp->device->suspended) {
tp_post_button_events(tp, time);
return;
}
consumed |= tp_tap_handle_state(tp, time);
consumed |= tp_post_button_events(tp, time);
if (consumed) {
tp_stop_scroll_events(tp, time);
evdev_stop_scroll(tp->device, time);
return;
}
@ -589,6 +559,15 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
pointer_notify_motion(&tp->device->base, time, dx, dy);
}
static void
tp_handle_state(struct tp_dispatch *tp,
uint64_t time)
{
tp_process_state(tp, time);
tp_post_events(tp, time);
tp_post_process_state(tp, time);
}
static void
tp_process(struct evdev_dispatch *dispatch,
struct evdev_device *device,
@ -609,9 +588,7 @@ tp_process(struct evdev_dispatch *dispatch,
tp_process_key(tp, e, time);
break;
case EV_SYN:
tp_process_state(tp, time);
tp_post_events(tp, time);
tp_post_process_state(tp, time);
tp_handle_state(tp, time);
break;
}
}
@ -630,9 +607,144 @@ tp_destroy(struct evdev_dispatch *dispatch)
free(tp);
}
static void
tp_clear_state(struct tp_dispatch *tp, struct evdev_device *device)
{
uint64_t now = libinput_now(tp->device->base.seat->libinput);
struct tp_touch *t;
/* Unroll the touchpad state.
* Release buttons first. If tp is a clickpad, the button event
* must come before the touch up. If it isn't, the order doesn't
* matter anyway
*
* Then cancel all timeouts on the taps, triggering the last set
* of events.
*
* Then lift all touches so the touchpad is in a neutral state.
*
*/
tp_release_all_buttons(tp, now);
tp_release_all_taps(tp, now);
tp_for_each_touch(tp, t) {
tp_end_touch(tp, t, now);
}
tp_handle_state(tp, now);
}
static void
tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
{
tp_clear_state(tp, device);
/* On devices with top softwarebuttons we don't actually suspend the
* device, to keep the "trackpoint" buttons working. tp_post_events()
* will only send events for the trackpoint while suspended.
*/
if (tp->buttons.has_topbuttons) {
evdev_notify_suspended_device(device);
/* Enlarge topbutton area while suspended */
tp_init_softbuttons(tp, device, 1.5);
} else {
evdev_device_suspend(device);
}
}
static void
tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
{
if (tp->buttons.has_topbuttons) {
/* tap state-machine is offline while suspended, reset state */
tp_clear_state(tp, device);
/* restore original topbutton area size */
tp_init_softbuttons(tp, device, 1.0);
evdev_notify_resumed_device(device);
} else {
evdev_device_resume(device);
}
}
static void
tp_device_added(struct evdev_device *device,
struct evdev_device *added_device)
{
struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
if (tp->buttons.trackpoint == NULL &&
(added_device->tags & EVDEV_TAG_TRACKPOINT)) {
/* Don't send any pending releases to the new trackpoint */
tp->buttons.active_is_topbutton = false;
tp->buttons.trackpoint = added_device;
}
if (tp->sendevents.current_mode !=
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
return;
if (added_device->tags & EVDEV_TAG_EXTERNAL_MOUSE)
tp_suspend(tp, device);
}
static void
tp_device_removed(struct evdev_device *device,
struct evdev_device *removed_device)
{
struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
struct libinput_device *dev;
if (removed_device == tp->buttons.trackpoint) {
/* Clear any pending releases for the trackpoint */
if (tp->buttons.active && tp->buttons.active_is_topbutton) {
tp->buttons.active = 0;
tp->buttons.active_is_topbutton = false;
}
tp->buttons.trackpoint = NULL;
}
if (tp->sendevents.current_mode !=
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
return;
list_for_each(dev, &device->base.seat->devices_list, link) {
struct evdev_device *d = (struct evdev_device*)dev;
if (d != removed_device &&
(d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
return;
}
}
tp_resume(tp, device);
}
static void
tp_tag_device(struct evdev_device *device,
struct udev_device *udev_device)
{
int bustype;
/* simple approach: touchpads on USB or Bluetooth are considered
* external, anything else is internal. Exception is Apple -
* internal touchpads are connected over USB and it doesn't have
* external USB touchpads anyway.
*/
bustype = libevdev_get_id_bustype(device->evdev);
if (bustype == BUS_USB) {
if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
} else if (bustype != BUS_BLUETOOTH)
device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
}
static struct evdev_dispatch_interface tp_interface = {
tp_process,
tp_destroy
tp_destroy,
tp_device_added,
tp_device_removed,
tp_device_removed, /* device_suspended, treat as remove */
tp_device_added, /* device_resumed, treat as add */
tp_tag_device,
};
static void
@ -646,41 +758,43 @@ static int
tp_init_slots(struct tp_dispatch *tp,
struct evdev_device *device)
{
size_t i;
const struct input_absinfo *absinfo;
struct map {
unsigned int code;
int ntouches;
} max_touches[] = {
{ BTN_TOOL_QUINTTAP, 5 },
{ BTN_TOOL_QUADTAP, 4 },
{ BTN_TOOL_TRIPLETAP, 3 },
{ BTN_TOOL_DOUBLETAP, 2 },
};
struct map *m;
unsigned int i, n_btn_tool_touches = 1;
absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
if (absinfo) {
tp->ntouches = absinfo->maximum + 1;
tp->real_touches = absinfo->maximum + 1;
tp->slot = absinfo->value;
tp->has_mt = true;
} else {
struct map {
unsigned int code;
int ntouches;
} max_touches[] = {
{ BTN_TOOL_QUINTTAP, 5 },
{ BTN_TOOL_QUADTAP, 4 },
{ BTN_TOOL_TRIPLETAP, 3 },
{ BTN_TOOL_DOUBLETAP, 2 },
};
struct map *m;
tp->real_touches = 1;
tp->slot = 0;
tp->has_mt = false;
tp->ntouches = 1;
}
ARRAY_FOR_EACH(max_touches, m) {
if (libevdev_has_event_code(device->evdev,
EV_KEY,
m->code)) {
tp->ntouches = m->ntouches;
break;
}
tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT);
ARRAY_FOR_EACH(max_touches, m) {
if (libevdev_has_event_code(device->evdev,
EV_KEY,
m->code)) {
n_btn_tool_touches = m->ntouches;
break;
}
}
tp->touches = calloc(tp->ntouches,
sizeof(struct tp_touch));
tp->ntouches = max(tp->real_touches, n_btn_tool_touches);
tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch));
if (!tp->touches)
return -1;
@ -740,14 +854,6 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
return 0;
}
static int
tp_init_scroll(struct tp_dispatch *tp)
{
tp->scroll.direction = 0;
return 0;
}
static int
tp_init_palmdetect(struct tp_dispatch *tp,
struct evdev_device *device)
@ -757,17 +863,20 @@ tp_init_palmdetect(struct tp_dispatch *tp,
tp->palm.right_edge = INT_MAX;
tp->palm.left_edge = INT_MIN;
/* We don't know how big the touchpad is */
if (device->abs.absinfo_x->resolution == 1)
return 0;
width = abs(device->abs.absinfo_x->maximum -
device->abs.absinfo_x->minimum);
/* Enable palm detection on touchpads >= 80 mm. Anything smaller
probably won't need it, until we find out it does */
if (width/device->abs.absinfo_x->resolution < 80)
return 0;
/* Apple touchpads are always big enough to warrant palm detection */
if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) {
/* We don't know how big the touchpad is */
if (device->abs.absinfo_x->resolution == 1)
return 0;
/* Enable palm detection on touchpads >= 80 mm. Anything smaller
probably won't need it, until we find out it does */
if (width/device->abs.absinfo_x->resolution < 80)
return 0;
}
/* palm edges are 5% of the width on each side */
tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
@ -776,7 +885,6 @@ tp_init_palmdetect(struct tp_dispatch *tp,
return 0;
}
static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
@ -801,9 +909,6 @@ tp_init(struct tp_dispatch *tp,
tp->hysteresis.margin_y =
diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
if (tp_init_scroll(tp) != 0)
return -1;
if (tp_init_accel(tp, diagonal) != 0)
return -1;
@ -816,9 +921,83 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_palmdetect(tp, device) != 0)
return -1;
device->seat_caps |= EVDEV_DEVICE_POINTER;
return 0;
}
static uint32_t
tp_sendevents_get_modes(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED |
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
return modes;
}
static void
tp_suspend_conditional(struct tp_dispatch *tp,
struct evdev_device *device)
{
struct libinput_device *dev;
list_for_each(dev, &device->base.seat->devices_list, link) {
struct evdev_device *d = (struct evdev_device*)dev;
if (d->tags & EVDEV_TAG_EXTERNAL_MOUSE) {
tp_suspend(tp, device);
return;
}
}
}
static enum libinput_config_status
tp_sendevents_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
if (mode == tp->sendevents.current_mode)
return LIBINPUT_CONFIG_STATUS_SUCCESS;
switch(mode) {
case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
tp_resume(tp, evdev);
break;
case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
tp_suspend(tp, evdev);
break;
case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
tp_suspend_conditional(tp, evdev);
break;
default:
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
}
tp->sendevents.current_mode = mode;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
static enum libinput_config_send_events_mode
tp_sendevents_get_mode(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *dispatch = (struct tp_dispatch*)evdev->dispatch;
return dispatch->sendevents.current_mode;
}
static enum libinput_config_send_events_mode
tp_sendevents_get_default_mode(struct libinput_device *device)
{
return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}
struct evdev_dispatch *
evdev_mt_touchpad_create(struct evdev_device *device)
{
@ -833,5 +1012,13 @@ evdev_mt_touchpad_create(struct evdev_device *device)
return NULL;
}
device->base.config.sendevents = &tp->sendevents.config;
tp->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
tp->sendevents.config.get_modes = tp_sendevents_get_modes;
tp->sendevents.config.set_mode = tp_sendevents_set_mode;
tp->sendevents.config.get_mode = tp_sendevents_get_mode;
tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;
return &tp->base;
}

View file

@ -33,6 +33,8 @@
#define TOUCHPAD_HISTORY_LENGTH 4
#define TOUCHPAD_MIN_SAMPLES 4
#define VENDOR_ID_APPLE 0x5ac
enum touchpad_event {
TOUCHPAD_EVENT_NONE = 0,
TOUCHPAD_EVENT_MOTION = (1 << 0),
@ -101,7 +103,6 @@ struct tp_touch {
struct tp_dispatch *tp;
enum touch_state state;
bool dirty;
bool fake; /* a fake touch */
bool is_pointer; /* the pointer-controlling touch */
int32_t x;
int32_t y;
@ -151,10 +152,13 @@ struct tp_dispatch {
struct evdev_dispatch base;
struct evdev_device *device;
unsigned int nfingers_down; /* number of fingers down */
unsigned int old_nfingers_down; /* previous no fingers down */
unsigned int slot; /* current slot */
bool has_mt;
bool semi_mt;
unsigned int ntouches; /* number of slots */
unsigned int real_touches; /* number of slots */
unsigned int ntouches; /* no slots inc. fakes */
struct tp_touch *touches; /* len == ntouches */
unsigned int fake_touches; /* fake touch mask */
@ -179,6 +183,7 @@ struct tp_dispatch {
uint32_t old_state;
uint32_t motion_dist; /* for pinned touches */
unsigned int active; /* currently active button, for release event */
bool active_is_topbutton; /* is active a top button? */
/* Only used for clickpads. The software button areas are
* always 2 horizontal stripes across the touchpad.
@ -194,11 +199,9 @@ struct tp_dispatch {
int32_t rightbutton_left_edge;
int32_t leftbutton_right_edge;
} top_area;
} buttons; /* physical buttons */
struct {
enum libinput_pointer_axis direction;
} scroll;
struct evdev_device *trackpoint;
} buttons; /* physical buttons */
enum touchpad_event queued;
@ -213,6 +216,11 @@ struct tp_dispatch {
int32_t right_edge;
int32_t left_edge;
} palm;
struct {
struct libinput_device_config_send_events config;
enum libinput_config_send_events_mode current_mode;
} sendevents;
};
#define tp_for_each_touch(_tp, _t) \
@ -236,6 +244,11 @@ tp_destroy_tap(struct tp_dispatch *tp);
int
tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device);
void
tp_init_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult);
void
tp_destroy_buttons(struct tp_dispatch *tp);
@ -244,6 +257,10 @@ tp_process_button(struct tp_dispatch *tp,
const struct input_event *e,
uint64_t time);
void
tp_release_all_buttons(struct tp_dispatch *tp,
uint64_t time);
int
tp_post_button_events(struct tp_dispatch *tp, uint64_t time);
@ -256,4 +273,8 @@ tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
bool
tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t);
void
tp_release_all_taps(struct tp_dispatch *tp,
uint64_t time);
#endif

File diff suppressed because it is too large Load diff

View file

@ -26,10 +26,12 @@
#include "config.h"
#include <stdbool.h>
#include "linux/input.h"
#include <libevdev/libevdev.h>
#include "libinput-private.h"
#include "timer.h"
enum evdev_event_type {
EVDEV_NONE,
@ -49,6 +51,12 @@ enum evdev_device_seat_capability {
EVDEV_DEVICE_TABLET = (1 << 3),
};
enum evdev_device_tags {
EVDEV_TAG_EXTERNAL_MOUSE = (1 << 0),
EVDEV_TAG_INTERNAL_TOUCHPAD = (1 << 1),
EVDEV_TAG_TRACKPOINT = (1 << 2),
};
struct mt_slot {
int32_t seat_slot;
int32_t x, y;
@ -64,16 +72,20 @@ struct evdev_device {
char *output_name;
char *devnode;
char *sysname;
char *syspath;
const char *devname;
int fd;
struct {
const struct input_absinfo *absinfo_x, *absinfo_y;
int32_t x, y;
int fake_resolution;
int32_t x, y;
int32_t seat_slot;
int apply_calibration;
float calibration[6];
struct matrix calibration;
struct matrix default_calibration; /* from LIBINPUT_CALIBRATION_MATRIX */
struct matrix usermatrix; /* as supplied by the caller */
} abs;
struct {
@ -87,14 +99,31 @@ struct evdev_device {
int dx, dy;
} rel;
struct {
struct libinput_timer timer;
bool has_middle_button_scroll;
bool middle_button_scroll_active;
double threshold;
uint32_t direction;
} scroll;
enum evdev_event_type pending_event;
enum evdev_device_seat_capability seat_caps;
enum evdev_device_tags tags;
int is_mt;
int suspended;
struct {
struct motion_filter *filter;
} pointer;
/* Bitmask of pressed keys used to ignore initial release events from
* the kernel. */
unsigned long hw_key_mask[NLONGS(KEY_CNT)];
/* Key counter used for multiplexing button events internally in
* libinput. */
uint8_t key_count[KEY_CNT];
};
#define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
@ -110,16 +139,43 @@ struct evdev_dispatch_interface {
/* Destroy an event dispatch handler and free all its resources. */
void (*destroy)(struct evdev_dispatch *dispatch);
/* A new device was added */
void (*device_added)(struct evdev_device *device,
struct evdev_device *added_device);
/* A device was removed */
void (*device_removed)(struct evdev_device *device,
struct evdev_device *removed_device);
/* A device was suspended */
void (*device_suspended)(struct evdev_device *device,
struct evdev_device *suspended_device);
/* A device was resumed */
void (*device_resumed)(struct evdev_device *device,
struct evdev_device *resumed_device);
/* Tag device with one of EVDEV_TAG */
void (*tag_device)(struct evdev_device *device,
struct udev_device *udev_device);
};
struct evdev_dispatch {
struct evdev_dispatch_interface *interface;
struct libinput_device_config_calibration calibration;
struct {
struct libinput_device_config_send_events config;
enum libinput_config_send_events_mode current_mode;
} sendevents;
};
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
const char *devnode,
const char *sysname);
const char *sysname,
const char *syspath);
struct evdev_dispatch *
evdev_touchpad_create(struct evdev_device *device);
@ -130,9 +186,6 @@ evdev_mt_touchpad_create(struct evdev_device *device);
struct evdev_dispatch *
evdev_tablet_create(struct evdev_device *device);
void
evdev_device_proces_event(struct libinput_event *event);
void
evdev_device_led_update(struct evdev_device *device, enum libinput_led leds);
@ -155,7 +208,11 @@ unsigned int
evdev_device_get_id_vendor(struct evdev_device *device);
void
evdev_device_calibrate(struct evdev_device *device, float calibration[6]);
evdev_device_set_default_calibration(struct evdev_device *device,
const float calibration[6]);
void
evdev_device_calibrate(struct evdev_device *device,
const float calibration[6]);
int
evdev_device_has_capability(struct evdev_device *device,
@ -175,6 +232,39 @@ double
evdev_device_transform_y(struct evdev_device *device,
double y,
uint32_t height);
int
evdev_device_suspend(struct evdev_device *device);
int
evdev_device_resume(struct evdev_device *device);
void
evdev_notify_suspended_device(struct evdev_device *device);
void
evdev_notify_resumed_device(struct evdev_device *device);
void
evdev_keyboard_notify_key(struct evdev_device *device,
uint32_t time,
int key,
enum libinput_key_state state);
void
evdev_pointer_notify_button(struct evdev_device *device,
uint32_t time,
int button,
enum libinput_button_state state);
void
evdev_post_scroll(struct evdev_device *device,
uint64_t time,
double dx,
double dy);
void
evdev_stop_scroll(struct evdev_device *device, uint64_t time);
void
evdev_device_remove(struct evdev_device *device);

View file

@ -52,9 +52,6 @@ struct motion_filter {
struct motion_filter_interface *interface;
};
struct motion_filter *
create_linear_acceleration_filter(double speed);
typedef double (*accel_profile_func_t)(struct motion_filter *filter,
void *data,
double velocity,

View file

@ -23,6 +23,8 @@
#ifndef LIBINPUT_PRIVATE_H
#define LIBINPUT_PRIVATE_H
#include <errno.h>
#include "linux/input.h"
#include "libinput.h"
@ -86,13 +88,33 @@ struct libinput_seat {
struct libinput_device_config_tap {
int (*count)(struct libinput_device *device);
enum libinput_config_status (*set_enabled)(struct libinput_device *device,
int enable);
int (*get_enabled)(struct libinput_device *device);
int (*get_default)(struct libinput_device *device);
enum libinput_config_tap_state enable);
enum libinput_config_tap_state (*get_enabled)(struct libinput_device *device);
enum libinput_config_tap_state (*get_default)(struct libinput_device *device);
};
struct libinput_device_config_calibration {
int (*has_matrix)(struct libinput_device *device);
enum libinput_config_status (*set_matrix)(struct libinput_device *device,
const float matrix[6]);
int (*get_matrix)(struct libinput_device *device,
float matrix[6]);
int (*get_default_matrix)(struct libinput_device *device,
float matrix[6]);
};
struct libinput_device_config_send_events {
uint32_t (*get_modes)(struct libinput_device *device);
enum libinput_config_status (*set_mode)(struct libinput_device *device,
enum libinput_config_send_events_mode mode);
enum libinput_config_send_events_mode (*get_mode)(struct libinput_device *device);
enum libinput_config_send_events_mode (*get_default_mode)(struct libinput_device *device);
};
struct libinput_device_config {
struct libinput_device_config_tap *tap;
struct libinput_device_config_calibration *calibration;
struct libinput_device_config_send_events *sendevents;
};
struct libinput_device {
@ -120,8 +142,8 @@ typedef void (*libinput_source_dispatch_t)(void *data);
#define log_info(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__)
#define log_error(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__)
#define log_bug_kernel(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__)
#define log_bug_libinput(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__);
#define log_bug_client(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__);
#define log_bug_libinput(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__)
#define log_bug_client(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__)
void
log_msg(struct libinput *libinput,
@ -255,4 +277,17 @@ tablet_notify_button(struct libinput_device *device,
void
touch_notify_frame(struct libinput_device *device,
uint32_t time);
static inline uint64_t
libinput_now(struct libinput *libinput)
{
struct timespec ts = { 0, 0 };
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
log_error(libinput, "clock_gettime failed: %s\n", strerror(errno));
return 0;
}
return ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000;
}
#endif /* LIBINPUT_PRIVATE_H */

View file

@ -25,6 +25,8 @@
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include "libinput.h"
@ -72,9 +74,11 @@ int list_empty(const struct list *list);
pos = tmp, \
tmp = container_of(pos->member.next, tmp, member))
#define LONG_BITS (sizeof(long) * 8)
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define ARRAY_FOR_EACH(_arr, _elem) \
for (size_t _i = 0; (_elem = &_arr[_i]) && _i < ARRAY_LENGTH(_arr); _i++)
for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
@ -174,4 +178,130 @@ vector_get_direction(int dx, int dy)
return dir;
}
static inline int
long_bit_is_set(const unsigned long *array, int bit)
{
return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
}
static inline void
long_set_bit(unsigned long *array, int bit)
{
array[bit / LONG_BITS] |= (1LL << (bit % LONG_BITS));
}
static inline void
long_clear_bit(unsigned long *array, int bit)
{
array[bit / LONG_BITS] &= ~(1LL << (bit % LONG_BITS));
}
static inline void
long_set_bit_state(unsigned long *array, int bit, int state)
{
if (state)
long_set_bit(array, bit);
else
long_clear_bit(array, bit);
}
struct matrix {
float val[3][3]; /* [row][col] */
};
static inline void
matrix_init_identity(struct matrix *m)
{
memset(m, 0, sizeof(*m));
m->val[0][0] = 1;
m->val[1][1] = 1;
m->val[2][2] = 1;
}
static inline void
matrix_from_farray6(struct matrix *m, const float values[6])
{
matrix_init_identity(m);
m->val[0][0] = values[0];
m->val[0][1] = values[1];
m->val[0][2] = values[2];
m->val[1][0] = values[3];
m->val[1][1] = values[4];
m->val[1][2] = values[5];
}
static inline void
matrix_init_scale(struct matrix *m, float sx, float sy)
{
matrix_init_identity(m);
m->val[0][0] = sx;
m->val[1][1] = sy;
}
static inline void
matrix_init_translate(struct matrix *m, float x, float y)
{
matrix_init_identity(m);
m->val[0][2] = x;
m->val[1][2] = y;
}
static inline int
matrix_is_identity(struct matrix *m)
{
return (m->val[0][0] == 1 &&
m->val[0][1] == 0 &&
m->val[0][2] == 0 &&
m->val[1][0] == 0 &&
m->val[1][1] == 1 &&
m->val[1][2] == 0 &&
m->val[2][0] == 0 &&
m->val[2][1] == 0 &&
m->val[2][2] == 1);
}
static inline void
matrix_mult(struct matrix *dest,
const struct matrix *m1,
const struct matrix *m2)
{
struct matrix m; /* allow for dest == m1 or dest == m2 */
int row, col, i;
for (row = 0; row < 3; row++) {
for (col = 0; col < 3; col++) {
double v = 0;
for (i = 0; i < 3; i++) {
v += m1->val[row][i] * m2->val[i][col];
}
m.val[row][col] = v;
}
}
memcpy(dest, &m, sizeof(m));
}
static inline void
matrix_mult_vec(struct matrix *m, int *x, int *y)
{
int tx, ty;
tx = *x * m->val[0][0] + *y * m->val[0][1] + m->val[0][2];
ty = *x * m->val[1][0] + *y * m->val[1][1] + m->val[1][2];
*x = tx;
*y = ty;
}
static inline void
matrix_to_farray6(const struct matrix *m, float out[6])
{
out[0] = m->val[0][0];
out[1] = m->val[0][1];
out[2] = m->val[0][2];
out[3] = m->val[1][0];
out[4] = m->val[1][1];
out[5] = m->val[1][2];
}
#endif /* LIBINPUT_UTIL_H */

View file

@ -662,7 +662,6 @@ libinput_add_fd(struct libinput *libinput,
ep.data.ptr = source;
if (epoll_ctl(libinput->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
close(source->fd);
free(source);
return NULL;
}
@ -1605,8 +1604,12 @@ libinput_device_config_tap_get_finger_count(struct libinput_device *device)
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_tap_set_enabled(struct libinput_device *device,
int enable)
enum libinput_config_tap_state enable)
{
if (enable != LIBINPUT_CONFIG_TAP_ENABLED &&
enable != LIBINPUT_CONFIG_TAP_DISABLED)
return LIBINPUT_CONFIG_STATUS_INVALID;
if (enable &&
libinput_device_config_tap_get_finger_count(device) == 0)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
@ -1614,20 +1617,96 @@ libinput_device_config_tap_set_enabled(struct libinput_device *device,
return device->config.tap->set_enabled(device, enable);
}
LIBINPUT_EXPORT int
LIBINPUT_EXPORT enum libinput_config_tap_state
libinput_device_config_tap_get_enabled(struct libinput_device *device)
{
if (libinput_device_config_tap_get_finger_count(device) == 0)
return 0;
return LIBINPUT_CONFIG_TAP_DISABLED;
return device->config.tap->get_enabled(device);
}
LIBINPUT_EXPORT int
LIBINPUT_EXPORT enum libinput_config_tap_state
libinput_device_config_tap_get_default_enabled(struct libinput_device *device)
{
if (libinput_device_config_tap_get_finger_count(device) == 0)
return 0;
return LIBINPUT_CONFIG_TAP_DISABLED;
return device->config.tap->get_default(device);
}
LIBINPUT_EXPORT int
libinput_device_config_calibration_has_matrix(struct libinput_device *device)
{
return device->config.calibration ?
device->config.calibration->has_matrix(device) : 0;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_calibration_set_matrix(struct libinput_device *device,
const float matrix[6])
{
if (!libinput_device_config_calibration_has_matrix(device))
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.calibration->set_matrix(device, matrix);
}
LIBINPUT_EXPORT int
libinput_device_config_calibration_get_matrix(struct libinput_device *device,
float matrix[6])
{
if (!libinput_device_config_calibration_has_matrix(device))
return 0;
return device->config.calibration->get_matrix(device, matrix);
}
LIBINPUT_EXPORT int
libinput_device_config_calibration_get_default_matrix(struct libinput_device *device,
float matrix[6])
{
if (!libinput_device_config_calibration_has_matrix(device))
return 0;
return device->config.calibration->get_default_matrix(device, matrix);
}
LIBINPUT_EXPORT uint32_t
libinput_device_config_send_events_get_modes(struct libinput_device *device)
{
uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
if (device->config.sendevents)
modes |= device->config.sendevents->get_modes(device);
return modes;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_send_events_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode)
{
if ((libinput_device_config_send_events_get_modes(device) & mode) == 0)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
if (device->config.sendevents)
return device->config.sendevents->set_mode(device, mode);
else /* mode must be _ENABLED to get here */
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
LIBINPUT_EXPORT enum libinput_config_send_events_mode
libinput_device_config_send_events_get_mode(struct libinput_device *device)
{
if (device->config.sendevents)
return device->config.sendevents->get_mode(device);
else
return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}
LIBINPUT_EXPORT enum libinput_config_send_events_mode
libinput_device_config_send_events_get_default_mode(struct libinput_device *device)
{
return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}

View file

@ -103,6 +103,38 @@ extern "C" {
* middle button click.
*/
/**
* @page udev_config Static device configuration via udev
*
* libinput supports some static configuration through udev properties.
* These propertiesare read when the device is initially added
* to libinput's device list, i.e. before the @ref
* LIBINPUT_EVENT_DEVICE_ADDED event is generated.
*
* The following udev properties are supported:
* <dl>
* <dt>LIBINPUT_CALIBRATION_MATRIX</dt>
* <dd>Sets the calibration matrix, see
* libinput_device_config_calibration_get_default_matrix(). If unset,
* defaults to the identity matrix.</dd>
* <dt>ID_SEAT</dt>
* <dd>Assigns the physical seat for this device. See
* libinput_seat_get_physical_name(). Defaults to "seat0".</dd>
* <dt>WL_SEAT</dt>
* <dd>Assigns the logical seat for this device. See
* libinput_seat_get_logical_name()
* context. Defaults to "default".</dd>
* </dl>
*
* Below is an example udev rule to assign "seat1" to a device from vendor
* 0x012a with the model ID of 0x034b.
* @code
* ACTION=="add|change", KERNEL=="event[0-9]*", ENV{ID_VENDOR_ID}=="012a", \
* ENV{ID_MODEL_ID}=="034b", ENV{ID_SEAT}="seat1"
* @endcode
*
*/
/**
* Log priority for internal logging messages.
*/
@ -513,6 +545,9 @@ libinput_event_pointer_get_time(struct libinput_event_pointer *event);
* events that are not of type LIBINPUT_EVENT_POINTER_MOTION, this function
* returns 0.
*
* If a device employs pointer acceleration, the delta returned by this
* function is the accelerated delta.
*
* @note It is an application bug to call this function for events other than
* LIBINPUT_EVENT_POINTER_MOTION.
*
@ -528,6 +563,9 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event);
* events that are not of type LIBINPUT_EVENT_POINTER_MOTION, this function
* returns 0.
*
* If a device employs pointer acceleration, the delta returned by this
* function is the accelerated delta.
*
* @note It is an application bug to call this function for events other than
* LIBINPUT_EVENT_POINTER_MOTION.
*
@ -1676,24 +1714,18 @@ libinput_device_led_update(struct libinput_device *device,
*/
int
libinput_device_get_keys(struct libinput_device *device,
char *keys, size_t size);
char *keys, size_t size)
LIBINPUT_ATTRIBUTE_DEPRECATED;
/**
* @ingroup device
*
* Apply the 3x3 transformation matrix to absolute device coordinates. This
* matrix has no effect on relative events.
*
* Given a 6-element array [a, b, c, d, e, f], the matrix is applied as
* @code
* [ a b c ] [ x ]
* [ d e f ] * [ y ]
* [ 0 0 1 ] [ 1 ]
* @endcode
* @deprecated Use libinput_device_config_calibration_set_matrix() instead.
*/
void
libinput_device_calibrate(struct libinput_device *device,
float calibration[6]);
float calibration[6])
LIBINPUT_ATTRIBUTE_DEPRECATED;
/**
* @ingroup device
@ -1764,6 +1796,16 @@ enum libinput_config_status {
const char *
libinput_config_status_to_str(enum libinput_config_status status);
/**
* @ingroup config
*/
enum libinput_config_tap_state {
LIBINPUT_CONFIG_TAP_DISABLED, /**< Tapping is to be disabled, or is
currently disabled */
LIBINPUT_CONFIG_TAP_ENABLED, /**< Tapping is to be enabled, or is
currently enabled */
};
/**
* @ingroup config
*
@ -1776,7 +1818,7 @@ libinput_config_status_to_str(enum libinput_config_status status);
*
* @see libinput_device_config_tap_set_enabled
* @see libinput_device_config_tap_get_enabled
* @see libinput_device_config_tap_set_enabled_get_default
* @see libinput_device_config_tap_get_default_enabled
*/
int
libinput_device_config_tap_get_finger_count(struct libinput_device *device);
@ -1791,7 +1833,8 @@ libinput_device_config_tap_get_finger_count(struct libinput_device *device);
* libinput_device_config_tap_get_finger_count().
*
* @param device The device to configure
* @param enable Non-zero to enable, zero to disable
* @param enable @ref LIBINPUT_CONFIG_TAP_ENABLED to enable tapping or @ref
* LIBINPUT_CONFIG_TAP_DISABLED to disable tapping
*
* @return A config status code. Disabling tapping on a device that does not
* support tapping always succeeds.
@ -1802,7 +1845,7 @@ libinput_device_config_tap_get_finger_count(struct libinput_device *device);
*/
enum libinput_config_status
libinput_device_config_tap_set_enabled(struct libinput_device *device,
int enable);
enum libinput_config_tap_state enable);
/**
* @ingroup config
@ -1812,13 +1855,14 @@ libinput_device_config_tap_set_enabled(struct libinput_device *device,
*
* @param device The device to configure
*
* @return 1 if enabled, 0 otherwise.
* @return @ref LIBINPUT_CONFIG_TAP_ENABLED if tapping is currently enabled,
* or @ref LIBINPUT_CONFIG_TAP_DISABLED is currently disabled
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_set_enabled
* @see libinput_device_config_tap_get_default_enabled
*/
int
enum libinput_config_tap_state
libinput_device_config_tap_get_enabled(struct libinput_device *device);
/**
@ -1827,15 +1871,241 @@ libinput_device_config_tap_get_enabled(struct libinput_device *device);
* Return the default setting for whether tapping is enabled on this device.
*
* @param device The device to configure
* @return 1 if tapping is enabled by default, or 0 otherwise
* @return @ref LIBINPUT_CONFIG_TAP_ENABLED if tapping is enabled by default,
* or @ref LIBINPUT_CONFIG_TAP_DISABLED is disabled by default
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_set_enabled
* @see libinput_device_config_tap_get_enabled
*/
int
enum libinput_config_tap_state
libinput_device_config_tap_get_default_enabled(struct libinput_device *device);
/**
* @ingroup config
*
* Check if the device can be calibrated via a calibration matrix.
*
* @param device The device to check
* @return non-zero if the device can be calibrated, zero otherwise.
*
* @see libinput_device_config_calibration_set_matrix
* @see libinput_device_config_calibration_get_matrix
* @see libinput_device_config_calibration_get_default_matrix
*/
int
libinput_device_config_calibration_has_matrix(struct libinput_device *device);
/**
* @ingroup config
*
* Apply the 3x3 transformation matrix to absolute device coordinates. This
* matrix has no effect on relative events.
*
* Given a 6-element array [a, b, c, d, e, f], the matrix is applied as
* @code
* [ a b c ] [ x ]
* [ d e f ] * [ y ]
* [ 0 0 1 ] [ 1 ]
* @endcode
*
* The translation component (c, f) is expected to be normalized to the
* device coordinate range. For example, the matrix
* @code
* [ 1 0 1 ]
* [ 0 1 -1 ]
* [ 0 0 1 ]
* @endcode
* moves all coordinates by 1 device-width to the right and 1 device-height
* up.
*
* The rotation matrix for rotation around the origin is defined as
* @code
* [ cos(a) -sin(a) 0 ]
* [ sin(a) cos(a) 0 ]
* [ 0 0 1 ]
* @endcode
* Note that any rotation requires an additional translation component to
* translate the rotated coordinates back into the original device space.
* The rotation matrixes for 90, 180 and 270 degrees clockwise are:
* @code
* 90 deg cw: 180 deg cw: 270 deg cw:
* [ 0 -1 1] [ -1 0 1] [ 0 1 0 ]
* [ 1 0 0] [ 0 -1 1] [ -1 0 1 ]
* [ 0 0 1] [ 0 0 1] [ 0 0 1 ]
* @endcode
*
* @param device The device to configure
* @param matrix An array representing the first two rows of a 3x3 matrix as
* described above.
*
* @return A config status code.
*
* @see libinput_device_config_calibration_has_matrix
* @see libinput_device_config_calibration_get_matrix
* @see libinput_device_config_calibration_get_default_matrix
*/
enum libinput_config_status
libinput_device_config_calibration_set_matrix(struct libinput_device *device,
const float matrix[6]);
/**
* @ingroup config
*
* Return the current calibration matrix for this device.
*
* @param device The device to configure
* @param matrix Set to the array representing the first two rows of a 3x3 matrix as
* described in libinput_device_config_calibration_set_matrix().
*
* @return 0 if no calibration is set and the returned matrix is the
* identity matrix, 1 otherwise
*
* @see libinput_device_config_calibration_has_matrix
* @see libinput_device_config_calibration_set_matrix
* @see libinput_device_config_calibration_get_default_matrix
*/
int
libinput_device_config_calibration_get_matrix(struct libinput_device *device,
float matrix[6]);
/**
* @ingroup config
*
* Return the default calibration matrix for this device. On most devices,
* this is the identity matrix. If the udev property
* <b>LIBINPUT_CALIBRATION_MATRIX</b> is set on the respective udev device,
* that property's value becomes the default matrix.
*
* The udev property is parsed as 6 floating point numbers separated by a
* single space each (scanf(3) format "%f %f %f %f %f %f").
* The 6 values represent the first two rows of the calibration matrix as
* described in libinput_device_config_calibration_set_matrix().
*
* Example values are:
* @code
* ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0" # default
* ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 1 0 0" # 90 degree clockwise
* ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 0 -1 1" # 180 degree clockwise
* ENV{LIBINPUT_CALIBRATION_MATRIX}="0 1 0 -1 0 1" # 270 degree clockwise
* ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 1 0 0" # reflect along y axis
* @endcode
*
* @param device The device to configure
* @param matrix Set to the array representing the first two rows of a 3x3 matrix as
* described in libinput_device_config_calibration_set_matrix().
*
* @return 0 if no calibration is set and the returned matrix is the
* identity matrix, 1 otherwise
*
* @see libinput_device_config_calibration_has_matrix
* @see libinput_device_config_calibration_set_matrix
* @see libinput_device_config_calibration_get_default_matrix
*/
int
libinput_device_config_calibration_get_default_matrix(struct libinput_device *device,
float matrix[6]);
/**
* The send-event mode of a device defines when a device may generate events
* and pass those events to the caller.
*/
enum libinput_config_send_events_mode {
/**
* Send events from this device normally.
*/
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED = (1 << 0),
/**
* Do not send events through this device. Depending on the device,
* this may close all file descriptors on the device or it may leave
* the file descriptors open and route events through a different
* device.
*/
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED = (1 << 1),
/**
* If an external pointer device is plugged in, do not send events
* from this device. This option may be available on built-in
* touchpads.
*/
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE = (1 << 2),
};
/**
* @ingroup config
*
* Return the possible send-event modes for this device. These modes define
* when a device may process and send events.
*
* @param device The device to configure
*
* @return A bitmask of possible modes.
*
* @see libinput_device_config_send_events_set_mode
* @see libinput_device_config_send_events_get_mode
* @see libinput_device_config_send_events_get_default_mode
*/
uint32_t
libinput_device_config_send_events_get_modes(struct libinput_device *device);
/**
* Set the send-event mode for this device. The mode defines when the device
* processes and sends events to the caller.
*
* The selected mode may not take effect immediately. Events already
* received and processed from this device are unaffected and will be passed
* to the caller on the next call to libinput_get_event().
*
* If the mode is one of @ref LIBINPUT_CONFIG_SEND_EVENTS_DISABLED or
* @ref LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE, the device
* may wait for or generate events until it is in a neutral state.
* For example, this may include waiting for or generating button release
* events.
*
* If the device is already suspended, this function does nothing and
* returns success. Changing the send-event mode on a device that has been
* removed is permitted.
*
* @param device The device to configure
* @param mode The send-event mode for this device.
*
* @return A config status code.
*
* @see libinput_device_config_send_events_get_modes
* @see libinput_device_config_send_events_get_mode
* @see libinput_device_config_send_events_get_default_mode
*/
enum libinput_config_status
libinput_device_config_send_events_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode);
/**
* Get the send-event mode for this device. The mode defines when the device
* processes and sends events to the caller.
*
* @param device The device to configure
* @return The current send-event mode for this device.
*
* @see libinput_device_config_send_events_get_modes
* @see libinput_device_config_send_events_set_mode
* @see libinput_device_config_send_events_get_default_mode
*/
enum libinput_config_send_events_mode
libinput_device_config_send_events_get_mode(struct libinput_device *device);
/**
* Get the default send-event mode for this device. The mode defines when
* the device processes and sends events to the caller.
*
* @param device The device to configure
* @return The current send-event mode for this device.
*
* @see libinput_device_config_send_events_get_modes
* @see libinput_device_config_send_events_set_mode
* @see libinput_device_config_send_events_get_default_mode
*/
enum libinput_config_send_events_mode
libinput_device_config_send_events_get_default_mode(struct libinput_device *device);
#ifdef __cplusplus
}
#endif

View file

@ -112,6 +112,7 @@ path_seat_get_named(struct path_input *input,
static int
path_get_udev_properties(const char *path,
char **sysname,
char **syspath,
char **seat_name,
char **seat_logical_name)
{
@ -133,6 +134,7 @@ path_get_udev_properties(const char *path,
goto out;
*sysname = strdup(udev_device_get_sysname(device));
*syspath = strdup(udev_device_get_syspath(device));
seat = udev_device_get_property_value(device, "ID_SEAT");
*seat_name = strdup(seat ? seat : default_seat);
@ -155,10 +157,10 @@ path_device_enable(struct path_input *input, const char *devnode)
{
struct path_seat *seat;
struct evdev_device *device = NULL;
char *sysname = NULL;
char *sysname = NULL, *syspath = NULL;
char *seat_name = NULL, *seat_logical_name = NULL;
if (path_get_udev_properties(devnode, &sysname,
if (path_get_udev_properties(devnode, &sysname, &syspath,
&seat_name, &seat_logical_name) == -1) {
log_info(&input->base,
"failed to obtain sysname for device '%s'.\n",
@ -180,7 +182,7 @@ path_device_enable(struct path_input *input, const char *devnode)
}
}
device = evdev_device_create(&seat->base, devnode, sysname);
device = evdev_device_create(&seat->base, devnode, sysname, syspath);
libinput_seat_unref(&seat->base);
if (device == EVDEV_UNHANDLED_DEVICE) {
@ -198,6 +200,7 @@ path_device_enable(struct path_input *input, const char *devnode)
out:
free(sysname);
free(syspath);
free(seat_name);
free(seat_logical_name);

View file

@ -67,19 +67,12 @@ void
libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
{
#ifndef NDEBUG
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
uint64_t now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000;
if (abs(expire - now) > 5000)
log_bug_libinput(timer->libinput,
"timer offset more than 5s, now %"
PRIu64 " expire %" PRIu64 "\n",
now, expire);
} else {
log_error(timer->libinput,
"clock_gettime error: %s\n", strerror(errno));
}
uint64_t now = libinput_now(timer->libinput);
if (abs(expire - now) > 5000)
log_bug_libinput(timer->libinput,
"timer offset more than 5s, now %"
PRIu64 " expire %" PRIu64 "\n",
now, expire);
#endif
assert(expire);
@ -107,17 +100,11 @@ libinput_timer_handler(void *data)
{
struct libinput *libinput = data;
struct libinput_timer *timer, *tmp;
struct timespec ts;
uint64_t now;
int r;
r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r) {
log_error(libinput, "clock_gettime error: %s\n", strerror(errno));
now = libinput_now(libinput);
if (now == 0)
return;
}
now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000;
list_for_each_safe(timer, tmp, &libinput->timer.list, link) {
if (timer->expire <= now) {

View file

@ -47,8 +47,10 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
struct evdev_device *device;
const char *devnode;
const char *sysname;
const char *syspath;
const char *device_seat, *seat_name, *output_name;
const char *calibration_values;
float calibration[6];
struct udev_seat *seat;
device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
@ -60,6 +62,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
devnode = udev_device_get_devnode(udev_device);
sysname = udev_device_get_sysname(udev_device);
syspath = udev_device_get_syspath(udev_device);
/* Search for matching logical seat */
seat_name = udev_device_get_property_value(udev_device, "WL_SEAT");
@ -76,7 +79,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
return -1;
}
device = evdev_device_create(&seat->base, devnode, sysname);
device = evdev_device_create(&seat->base, devnode, sysname, syspath);
libinput_seat_unref(&seat->base);
if (device == EVDEV_UNHANDLED_DEVICE) {
@ -89,25 +92,25 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
calibration_values =
udev_device_get_property_value(udev_device,
"WL_CALIBRATION");
"LIBINPUT_CALIBRATION_MATRIX");
if (calibration_values && sscanf(calibration_values,
"%f %f %f %f %f %f",
&device->abs.calibration[0],
&device->abs.calibration[1],
&device->abs.calibration[2],
&device->abs.calibration[3],
&device->abs.calibration[4],
&device->abs.calibration[5]) == 6) {
device->abs.apply_calibration = 1;
&calibration[0],
&calibration[1],
&calibration[2],
&calibration[3],
&calibration[4],
&calibration[5]) == 6) {
evdev_device_set_default_calibration(device, calibration);
log_info(&input->base,
"Applying calibration: %f %f %f %f %f %f\n",
device->abs.calibration[0],
device->abs.calibration[1],
device->abs.calibration[2],
device->abs.calibration[3],
device->abs.calibration[4],
device->abs.calibration[5]);
calibration[0],
calibration[1],
calibration[2],
calibration[3],
calibration[4],
calibration[5]);
}
output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
@ -216,7 +219,6 @@ udev_input_remove_devices(struct udev_input *input)
}
}
static void
udev_input_disable(struct libinput *libinput)
{

View file

@ -15,7 +15,9 @@ liblitest_la_SOURCES = \
../src/libinput-util.c \
litest.h \
litest-int.h \
litest-alps-semi-mt.c \
litest-bcm5974.c \
litest-generic-singletouch.c \
litest-keyboard.c \
litest-mouse.c \
litest-synaptics.c \
@ -37,8 +39,10 @@ run_tests = \
test-log \
test-tablet \
test-touchpad \
test-trackpoint \
test-misc \
test-keyboard
test-keyboard \
test-device
build_tests = \
test-build-cxx \
test-build-linker \
@ -52,23 +56,23 @@ TESTS = $(run_tests)
test_udev_SOURCES = udev.c
test_udev_LDADD = $(TEST_LIBS)
test_udev_LDFLAGS = -static
test_udev_LDFLAGS = -no-install
test_path_SOURCES = path.c
test_path_LDADD = $(TEST_LIBS)
test_path_LDFLAGS = -static
test_path_LDFLAGS = -no-install
test_pointer_SOURCES = pointer.c
test_pointer_LDADD = $(TEST_LIBS)
test_pointer_LDFLAGS = -static
test_pointer_LDFLAGS = -no-install
test_touch_SOURCES = touch.c
test_touch_LDADD = $(TEST_LIBS)
test_touch_LDFLAGS = -static
test_touch_LDFLAGS = -no-install
test_log_SOURCES = log.c
test_log_LDADD = $(TEST_LIBS)
test_log_LDFLAGS = -static
test_log_LDFLAGS = -no-install
test_tablet_SOURCES = tablet.c
test_tablet_CFLAGS = $(AM_CPPFLAGS)
@ -77,15 +81,23 @@ test_tablet_LDFLAGS = -static
test_touchpad_SOURCES = touchpad.c
test_touchpad_LDADD = $(TEST_LIBS)
test_touchpad_LDFLAGS = -static
test_touchpad_LDFLAGS = -no-install
test_trackpoint_SOURCES = trackpoint.c
test_trackpoint_LDADD = $(TEST_LIBS)
test_trackpoint_LDFLAGS = -no-install
test_misc_SOURCES = misc.c
test_misc_LDADD = $(TEST_LIBS)
test_misc_LDFLAGS = -static
test_misc_LDFLAGS = -no-install
test_keyboard_SOURCES = keyboard.c
test_keyboard_LDADD = $(TEST_LIBS)
test_keyboard_LDFLAGS = -static
test_keyboard_LDFLAGS = -no-install
test_device_SOURCES = device.c
test_device_LDADD = $(TEST_LIBS)
test_device_LDFLAGS = -no-install
# build-test only
test_build_pedantic_c99_SOURCES = build-pedantic.c

589
test/device.c Normal file
View file

@ -0,0 +1,589 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <check.h>
#include <errno.h>
#include <fcntl.h>
#include <libinput.h>
#include <libudev.h>
#include <unistd.h>
#include "litest.h"
#include "libinput-util.h"
START_TEST(device_sendevents_config)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device;
uint32_t modes;
device = dev->libinput_device;
modes = libinput_device_config_send_events_get_modes(device);
ck_assert_int_eq(modes,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
}
END_TEST
START_TEST(device_sendevents_config_touchpad)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device;
uint32_t modes;
device = dev->libinput_device;
modes = libinput_device_config_send_events_get_modes(device);
ck_assert_int_eq(modes,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
}
END_TEST
START_TEST(device_sendevents_config_default)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device;
uint32_t mode;
device = dev->libinput_device;
mode = libinput_device_config_send_events_get_mode(device);
ck_assert_int_eq(mode,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
mode = libinput_device_config_send_events_get_default_mode(device);
ck_assert_int_eq(mode,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
}
END_TEST
START_TEST(device_disable)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
litest_drain_events(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* no event from disabling */
litest_assert_empty_queue(li);
/* no event from disabled device */
litest_event(dev, EV_REL, REL_X, 10);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
/* no event from resuming */
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_touchpad)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
litest_drain_events(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* no event from disabling */
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
/* no event from resuming */
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_events_pending)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
struct libinput_event *event;
int i;
device = dev->libinput_device;
litest_drain_events(li);
/* put a couple of events in the queue, enough to
feed the ptraccel trackers */
for (i = 0; i < 10; i++) {
litest_event(dev, EV_REL, REL_X, 10);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
libinput_dispatch(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* expect above events */
litest_wait_for_event(li);
while ((event = libinput_get_event(li)) != NULL) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(event);
}
}
END_TEST
START_TEST(device_double_disable)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
litest_drain_events(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_double_enable)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
litest_drain_events(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_reenable_syspath_changed)
{
struct libinput *li;
struct litest_device *litest_device;
struct libinput_device *device1, *device2;
enum libinput_config_status status;
struct libinput_event *event;
li = litest_create_context();
litest_device = litest_add_device(li, LITEST_MOUSE);
device1 = litest_device->libinput_device;
libinput_device_ref(device1);
status = libinput_device_config_send_events_set_mode(device1,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_delete_device(litest_device);
litest_drain_events(li);
litest_device = litest_add_device(li, LITEST_MOUSE);
device2 = litest_device->libinput_device;
ck_assert_str_eq(libinput_device_get_sysname(device1),
libinput_device_get_sysname(device2));
status = libinput_device_config_send_events_set_mode(device1,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* can't really check for much here, other than that if we pump
events through libinput, none of them should be from the first
device */
litest_event(litest_device, EV_REL, REL_X, 1);
litest_event(litest_device, EV_REL, REL_Y, 1);
litest_event(litest_device, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
while ((event = libinput_get_event(li))) {
ck_assert(libinput_event_get_device(event) != device1);
libinput_event_destroy(event);
}
litest_delete_device(litest_device);
libinput_device_unref(device1);
libinput_unref(li);
}
END_TEST
START_TEST(device_reenable_device_removed)
{
struct libinput *li;
struct litest_device *litest_device;
struct libinput_device *device;
enum libinput_config_status status;
li = litest_create_context();
litest_device = litest_add_device(li, LITEST_MOUSE);
device = litest_device->libinput_device;
libinput_device_ref(device);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_delete_device(litest_device);
litest_drain_events(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* can't really check for much here, this really just exercises the
code path. */
litest_assert_empty_queue(li);
libinput_device_unref(device);
libinput_unref(li);
}
END_TEST
START_TEST(device_disable_release_buttons)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
struct libinput_event *event;
struct libinput_event_pointer *ptrevent;
enum libinput_config_status status;
device = dev->libinput_device;
litest_button_click(dev, BTN_LEFT, true);
litest_drain_events(li);
litest_assert_empty_queue(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_wait_for_event(li);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_BUTTON);
ptrevent = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_button(ptrevent),
BTN_LEFT);
ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrevent),
LIBINPUT_BUTTON_STATE_RELEASED);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_release_keys)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
struct libinput_event *event;
struct libinput_event_keyboard *kbdevent;
enum libinput_config_status status;
device = dev->libinput_device;
litest_button_click(dev, KEY_A, true);
litest_drain_events(li);
litest_assert_empty_queue(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_wait_for_event(li);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_KEYBOARD_KEY);
kbdevent = libinput_event_get_keyboard_event(event);
ck_assert_int_eq(libinput_event_keyboard_get_key(kbdevent),
KEY_A);
ck_assert_int_eq(libinput_event_keyboard_get_key_state(kbdevent),
LIBINPUT_KEY_STATE_RELEASED);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_release_tap)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
libinput_device_config_tap_set_enabled(device,
LIBINPUT_CONFIG_TAP_ENABLED);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
libinput_dispatch(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* tap happened before suspending, so we still expect the event */
msleep(300); /* tap-n-drag timeout */
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
/* resume, make sure we don't get anything */
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
libinput_dispatch(li);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_release_tap_n_drag)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
libinput_device_config_tap_set_enabled(device,
LIBINPUT_CONFIG_TAP_ENABLED);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
libinput_dispatch(li);
msleep(400); /* tap-n-drag timeout */
libinput_dispatch(li);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
libinput_dispatch(li);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_release_softbutton)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 90);
litest_button_click(dev, BTN_LEFT, true);
/* make sure softbutton works */
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
/* disable */
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
litest_button_click(dev, BTN_LEFT, false);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
/* resume, make sure we don't get anything */
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
libinput_dispatch(li);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(device_disable_topsoftbutton)
{
struct litest_device *dev = litest_current_device();
struct litest_device *trackpoint;
struct libinput *li = dev->libinput;
struct libinput_device *device;
enum libinput_config_status status;
struct libinput_event *event;
struct libinput_event_pointer *ptrevent;
device = dev->libinput_device;
trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 10);
litest_button_click(dev, BTN_LEFT, true);
litest_button_click(dev, BTN_LEFT, false);
litest_touch_up(dev, 0);
litest_wait_for_event(li);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_BUTTON);
ck_assert_int_eq(libinput_event_get_device(event),
trackpoint->libinput_device);
ptrevent = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_button(ptrevent),
BTN_RIGHT);
ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrevent),
LIBINPUT_BUTTON_STATE_PRESSED);
libinput_event_destroy(event);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_BUTTON);
ck_assert_int_eq(libinput_event_get_device(event),
trackpoint->libinput_device);
ptrevent = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_button(ptrevent),
BTN_RIGHT);
ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrevent),
LIBINPUT_BUTTON_STATE_RELEASED);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
litest_delete_device(trackpoint);
}
END_TEST
int main (int argc, char **argv)
{
litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_touchpad, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_default, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_disable, LITEST_POINTER, LITEST_TABLET);
litest_add("device:sendevents", device_disable_touchpad, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_disable_events_pending, LITEST_POINTER, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_double_disable, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_double_enable, LITEST_ANY, LITEST_TABLET);
litest_add_no_device("device:sendevents", device_reenable_syspath_changed);
litest_add_no_device("device:sendevents", device_reenable_device_removed);
litest_add_for_device("device:sendevents", device_disable_release_buttons, LITEST_MOUSE);
litest_add_for_device("device:sendevents", device_disable_release_keys, LITEST_KEYBOARD);
litest_add("device:sendevents", device_disable_release_tap, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_disable_release_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_disable_release_softbutton, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
litest_add("device:sendevents", device_disable_topsoftbutton, LITEST_TOPBUTTONPAD, LITEST_ANY);
return litest_run(argc, argv);
}

View file

@ -25,6 +25,7 @@
#include <check.h>
#include <stdio.h>
#include "libinput-util.h"
#include "litest.h"
START_TEST(keyboard_seat_key_count)
@ -112,10 +113,189 @@ START_TEST(keyboard_seat_key_count)
}
END_TEST
START_TEST(keyboard_ignore_no_pressed_release)
{
struct litest_device *dev;
struct libinput *unused_libinput;
struct libinput *libinput;
struct libinput_event *event;
struct libinput_event_keyboard *kevent;
int events[] = {
EV_KEY, KEY_A,
-1, -1,
};
enum libinput_key_state *state;
enum libinput_key_state expected_states[] = {
LIBINPUT_KEY_STATE_PRESSED,
LIBINPUT_KEY_STATE_RELEASED,
};
/* We can't send pressed -> released -> pressed events using uinput
* as such non-symmetric events are dropped. Work-around this by first
* adding the test device to the tested context after having sent an
* initial pressed event. */
unused_libinput = litest_create_context();
dev = litest_add_device_with_overrides(unused_libinput,
LITEST_KEYBOARD,
"Generic keyboard",
NULL, NULL, events);
litest_keyboard_key(dev, KEY_A, true);
litest_drain_events(unused_libinput);
libinput = litest_create_context();
libinput_path_add_device(libinput,
libevdev_uinput_get_devnode(dev->uinput));
litest_drain_events(libinput);
litest_keyboard_key(dev, KEY_A, false);
litest_keyboard_key(dev, KEY_A, true);
litest_keyboard_key(dev, KEY_A, false);
libinput_dispatch(libinput);
ARRAY_FOR_EACH(expected_states, state) {
event = libinput_get_event(libinput);
ck_assert_notnull(event);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_KEYBOARD_KEY);
kevent = libinput_event_get_keyboard_event(event);
ck_assert_int_eq(libinput_event_keyboard_get_key(kevent),
KEY_A);
ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
*state);
libinput_event_destroy(event);
libinput_dispatch(libinput);
}
litest_assert_empty_queue(libinput);
litest_delete_device(dev);
libinput_unref(libinput);
libinput_unref(unused_libinput);
}
END_TEST
static void
test_key_event(struct litest_device *dev, unsigned int key, int state)
{
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_keyboard *kevent;
litest_event(dev, EV_KEY, key, state);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_KEYBOARD_KEY);
kevent = libinput_event_get_keyboard_event(event);
ck_assert(kevent != NULL);
ck_assert_int_eq(libinput_event_keyboard_get_key(kevent), key);
ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
state ? LIBINPUT_KEY_STATE_PRESSED :
LIBINPUT_KEY_STATE_RELEASED);
libinput_event_destroy(event);
}
START_TEST(keyboard_key_auto_release)
{
struct libinput *libinput;
struct litest_device *dev;
struct libinput_event *event;
enum libinput_event_type type;
struct libinput_event_keyboard *kevent;
struct {
int code;
int released;
} keys[] = {
{ .code = KEY_A, },
{ .code = KEY_S, },
{ .code = KEY_D, },
{ .code = KEY_G, },
{ .code = KEY_Z, },
{ .code = KEY_DELETE, },
{ .code = KEY_F24, },
};
int events[2 * (ARRAY_LENGTH(keys) + 1)];
unsigned i;
int key;
int valid_code;
/* Enable all tested keys on the device */
i = 0;
while (i < 2 * ARRAY_LENGTH(keys)) {
key = keys[i / 2].code;
events[i++] = EV_KEY;
events[i++] = key;
}
events[i++] = -1;
events[i++] = -1;
libinput = litest_create_context();
dev = litest_add_device_with_overrides(libinput,
LITEST_KEYBOARD,
"Generic keyboard",
NULL, NULL, events);
litest_drain_events(libinput);
/* Send pressed events, without releasing */
for (i = 0; i < ARRAY_LENGTH(keys); ++i) {
test_key_event(dev, keys[i].code, 1);
}
litest_drain_events(libinput);
/* "Disconnect" device */
litest_delete_device(dev);
/* Mark all released keys until device is removed */
while (1) {
event = libinput_get_event(libinput);
ck_assert_notnull(event);
type = libinput_event_get_type(event);
if (type == LIBINPUT_EVENT_DEVICE_REMOVED) {
libinput_event_destroy(event);
break;
}
ck_assert_int_eq(type, LIBINPUT_EVENT_KEYBOARD_KEY);
kevent = libinput_event_get_keyboard_event(event);
ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
LIBINPUT_KEY_STATE_RELEASED);
key = libinput_event_keyboard_get_key(kevent);
valid_code = 0;
for (i = 0; i < ARRAY_LENGTH(keys); ++i) {
if (keys[i].code == key) {
ck_assert_int_eq(keys[i].released, 0);
keys[i].released = 1;
valid_code = 1;
}
}
ck_assert_int_eq(valid_code, 1);
libinput_event_destroy(event);
}
/* Check that all pressed keys has been released. */
for (i = 0; i < ARRAY_LENGTH(keys); ++i) {
ck_assert_int_eq(keys[i].released, 1);
}
libinput_unref(libinput);
}
END_TEST
int
main(int argc, char **argv)
{
litest_add_no_device("keyboard:seat key count", keyboard_seat_key_count);
litest_add_no_device("keyboard:key counting", keyboard_ignore_no_pressed_release);
litest_add_no_device("keyboard:key counting", keyboard_key_auto_release);
return litest_run(argc, argv);
}

260
test/litest-alps-semi-mt.c Normal file
View file

@ -0,0 +1,260 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include "libinput-util.h"
#include "litest.h"
#include "litest-int.h"
static int tracking_id;
/* this is a semi-mt device, so we keep track of the touches that the tests
* send and modify them so that the first touch is always slot 0 and sends
* the top-left of the bounding box, the second is always slot 1 and sends
* the bottom-right of the bounding box.
* Lifting any of two fingers terminates slot 1
*/
struct alps {
/* The actual touches requested by the test for the two slots
* in the 0..100 range used by litest */
struct {
double x, y;
} touches[2];
};
static void alps_create(struct litest_device *d);
static void
litest_alps_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_ALPS_SEMI_MT);
litest_set_current_device(d);
}
static void
send_abs_xy(struct litest_device *d, double x, double y)
{
struct input_event e;
int val;
e.type = EV_ABS;
e.code = ABS_X;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_X, val);
e.code = ABS_Y;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_Y, val);
}
static void
send_abs_mt_xy(struct litest_device *d, double x, double y)
{
struct input_event e;
int val;
e.type = EV_ABS;
e.code = ABS_MT_POSITION_X;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_MT_POSITION_X, val);
e.code = ABS_MT_POSITION_Y;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val);
}
static void
alps_touch_down(struct litest_device *d, unsigned int slot, double x, double y)
{
struct alps *alps = d->private;
double t, l, r = 0, b = 0; /* top, left, right, bottom */
if (d->ntouches_down > 2 || slot > 1)
return;
if (d->ntouches_down == 1) {
l = x;
t = y;
} else {
int other = (slot + 1) % 2;
l = min(x, alps->touches[other].x);
t = min(y, alps->touches[other].y);
r = max(x, alps->touches[other].x);
b = max(y, alps->touches[other].y);
}
send_abs_xy(d, l, t);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
if (d->ntouches_down == 1)
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id);
send_abs_mt_xy(d, l, t);
if (d->ntouches_down == 2) {
litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id);
send_abs_mt_xy(d, r, b);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
alps->touches[slot].x = x;
alps->touches[slot].y = y;
}
static void
alps_touch_move(struct litest_device *d, unsigned int slot, double x, double y)
{
struct alps *alps = d->private;
double t, l, r = 0, b = 0; /* top, left, right, bottom */
if (d->ntouches_down > 2 || slot > 1)
return;
if (d->ntouches_down == 1) {
l = x;
t = y;
} else {
int other = (slot + 1) % 2;
l = min(x, alps->touches[other].x);
t = min(y, alps->touches[other].y);
r = max(x, alps->touches[other].x);
b = max(y, alps->touches[other].y);
}
send_abs_xy(d, l, t);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
send_abs_mt_xy(d, l, t);
if (d->ntouches_down == 2) {
litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
send_abs_mt_xy(d, r, b);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
alps->touches[slot].x = x;
alps->touches[slot].y = y;
}
static void
alps_touch_up(struct litest_device *d, unsigned int slot)
{
struct alps *alps = d->private;
/* note: ntouches_down is decreased before we get here */
if (d->ntouches_down >= 2 || slot > 1)
return;
litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down);
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1);
/* if we have one finger left, send x/y coords for that finger left.
this is likely to happen with a real touchpad */
if (d->ntouches_down == 1) {
int other = (slot + 1) % 2;
send_abs_xy(d, alps->touches[other].x, alps->touches[other].y);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
send_abs_mt_xy(d, alps->touches[other].x, alps->touches[other].y);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static struct litest_device_interface interface = {
.touch_down = alps_touch_down,
.touch_move = alps_touch_move,
.touch_up = alps_touch_up,
};
static struct input_id input_id = {
.bustype = 0x11,
.vendor = 0x2,
.product = 0x8,
};
static int events[] = {
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_KEY, BTN_TOOL_FINGER,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_TOOL_DOUBLETAP,
EV_KEY, BTN_TOOL_TRIPLETAP,
EV_KEY, BTN_TOOL_QUADTAP,
INPUT_PROP_MAX, INPUT_PROP_POINTER,
INPUT_PROP_MAX, INPUT_PROP_SEMI_MT,
-1, -1,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 2000, 0, 0, 0 },
{ ABS_Y, 0, 1400, 0, 0, 0 },
{ ABS_PRESSURE, 0, 127, 0, 0, 0 },
{ ABS_MT_SLOT, 0, 1, 0, 0, 0 },
{ ABS_MT_POSITION_X, 0, 2000, 0, 0, 0 },
{ ABS_MT_POSITION_Y, 0, 1400, 0, 0, 0 },
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
{ .value = -1 }
};
struct litest_test_device litest_alps_device = {
.type = LITEST_ALPS_SEMI_MT,
.features = LITEST_TOUCHPAD | LITEST_BUTTON | LITEST_SEMI_MT,
.shortname = "alps semi-mt",
.setup = litest_alps_setup,
.interface = &interface,
.create = alps_create,
.name = "AlpsPS/2 ALPS GlidePoint",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};
static void
alps_create(struct litest_device *d)
{
struct alps *alps = zalloc(sizeof(*alps));
assert(alps);
d->private = alps;
d->uinput = litest_create_uinput_device_from_description(litest_alps_device.name,
litest_alps_device.id,
absinfo,
events);
d->interface = &interface;
}

View file

@ -34,8 +34,6 @@ static void litest_bcm5974_setup(void)
}
struct input_event down[] = {
{ .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
@ -53,8 +51,6 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
@ -65,13 +61,18 @@ static struct litest_device_interface interface = {
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 1472, 5472, 0, 0, 75 },
{ ABS_Y, 1408, 4448, 0, 0, 129 },
{ ABS_PRESSURE, 0, 255, 0, 0, 0 },
{ ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 },
{ ABS_MT_SLOT, 0, 1, 0, 0, 0 },
{ ABS_MT_POSITION_X, 1472, 5472, 0, 0, 75 },
{ ABS_MT_POSITION_Y, 1408, 4448, 0, 0, 129 },
{ ABS_X, -4824, 4824, 0, 0, 0 },
{ ABS_Y, -172, 4290, 0, 0, 0 },
{ ABS_PRESSURE, 0, 256, 5, 0, 0 },
{ ABS_TOOL_WIDTH, 0, 16, 0, 0, 0 },
{ ABS_MT_SLOT, 0, 15, 0, 0, 0 },
{ ABS_MT_POSITION_X, -4824, 4824, 17, 0, 0 },
{ ABS_MT_POSITION_Y, -172, 4290, 17, 0, 0 },
{ ABS_MT_ORIENTATION, -16384, 16384, 3276, 0, 0 },
{ ABS_MT_TOUCH_MAJOR, 0, 2048, 81, 0, 0 },
{ ABS_MT_TOUCH_MINOR, 0, 2048, 81, 0, 0 },
{ ABS_MT_WIDTH_MAJOR, 0, 2048, 81, 0, 0 },
{ ABS_MT_WIDTH_MINOR, 0, 2048, 81, 0, 0 },
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
{ ABS_MT_PRESSURE, 0, 255, 0, 0, 0 },
{ .value = -1 },

View file

@ -0,0 +1,88 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "litest.h"
#include "litest-int.h"
static void
litest_generic_singletouch_touch_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_GENERIC_SINGLETOUCH);
litest_set_current_device(d);
}
static struct input_event down[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct litest_device_interface interface = {
.touch_down_events = down,
.touch_move_events = move,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 10000, 20000, 0, 0, 10 },
{ ABS_Y, -2000, 2000, 0, 0, 9 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x01,
.vendor = 0x02,
.product = 0x03,
};
static int events[] = {
EV_KEY, BTN_TOUCH,
INPUT_PROP_MAX, INPUT_PROP_DIRECT,
-1, -1,
};
struct litest_test_device litest_generic_singletouch_device = {
.type = LITEST_GENERIC_SINGLETOUCH,
.features = LITEST_SINGLE_TOUCH,
.shortname = "generic-singletouch",
.setup = litest_generic_singletouch_touch_setup,
.interface = &interface,
.name = "generic_singletouch",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -72,8 +72,8 @@ struct litest_test_device {
};
struct litest_device_interface {
void (*touch_down)(struct litest_device *d, unsigned int slot, int x, int y);
void (*touch_move)(struct litest_device *d, unsigned int slot, int x, int y);
void (*touch_down)(struct litest_device *d, unsigned int slot, double x, double y);
void (*touch_move)(struct litest_device *d, unsigned int slot, double x, double y);
void (*touch_up)(struct litest_device *d, unsigned int slot);
/**

View file

@ -195,7 +195,6 @@ static int events[] = {
-1, -1,
};
struct litest_test_device litest_keyboard_device = {
.type = LITEST_KEYBOARD,
.features = LITEST_KEYS,

View file

@ -35,7 +35,6 @@ litest_synaptics_touchpad_setup(void)
}
static struct input_event down[] = {
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
@ -47,13 +46,11 @@ static struct input_event down[] = {
static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
struct input_event up[] = {
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 0 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};

View file

@ -35,8 +35,6 @@ litest_synaptics_t440_setup(void)
}
static struct input_event down[] = {
{ .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
@ -54,8 +52,6 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};

View file

@ -35,8 +35,6 @@ litest_synaptics_clickpad_setup(void)
}
static struct input_event down[] = {
{ .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
@ -54,8 +52,6 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 },
{ .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};

View file

@ -49,12 +49,14 @@ static int events[] = {
EV_KEY, BTN_MIDDLE,
EV_REL, REL_X,
EV_REL, REL_Y,
INPUT_PROP_MAX, INPUT_PROP_POINTER,
INPUT_PROP_MAX, INPUT_PROP_POINTING_STICK,
-1, -1,
};
struct litest_test_device litest_trackpoint_device = {
.type = LITEST_TRACKPOINT,
.features = LITEST_POINTER | LITEST_BUTTON,
.features = LITEST_POINTER | LITEST_BUTTON | LITEST_POINTINGSTICK,
.shortname = "trackpoint",
.setup = litest_trackpoint_setup,
.interface = &interface,

View file

@ -24,6 +24,7 @@
#include "config.h"
#endif
#include <assert.h>
#include <check.h>
#include <errno.h>
#include <fcntl.h>
@ -88,6 +89,8 @@ extern struct litest_test_device litest_wacom_bamboo_tablet_device;
extern struct litest_test_device litest_wacom_cintiq_tablet_device;
extern struct litest_test_device litest_wacom_intuos_tablet_device;
extern struct litest_test_device litest_wacom_isdv4_tablet_device;
extern struct litest_test_device litest_alps_device;
extern struct litest_test_device litest_generic_singletouch_device;
struct litest_test_device* devices[] = {
&litest_synaptics_clickpad_device,
@ -102,10 +105,11 @@ struct litest_test_device* devices[] = {
&litest_wacom_cintiq_tablet_device,
&litest_wacom_intuos_tablet_device,
&litest_wacom_isdv4_tablet_device,
&litest_alps_device,
&litest_generic_singletouch_device,
NULL,
};
static struct list all_tests;
static void
@ -163,6 +167,9 @@ litest_add_tcase(struct suite *suite, void *func,
{
struct litest_test_device **dev = devices;
assert(required >= LITEST_DISABLE_DEVICE);
assert(excluded >= LITEST_DISABLE_DEVICE);
if (required == LITEST_DISABLE_DEVICE &&
excluded == LITEST_DISABLE_DEVICE) {
litest_add_tcase_no_device(suite, func);
@ -187,11 +194,8 @@ litest_add_no_device(const char *name, void *func)
litest_add(name, func, LITEST_DISABLE_DEVICE, LITEST_DISABLE_DEVICE);
}
void
litest_add(const char *name,
void *func,
enum litest_device_feature required,
enum litest_device_feature excluded)
static struct suite *
get_suite(const char *name)
{
struct suite *s;
@ -199,10 +203,8 @@ litest_add(const char *name,
list_init(&all_tests);
list_for_each(s, &all_tests, node) {
if (strcmp(s->name, name) == 0) {
litest_add_tcase(s, func, required, excluded);
return;
}
if (strcmp(s->name, name) == 0)
return s;
}
s = zalloc(sizeof(*s));
@ -211,7 +213,39 @@ litest_add(const char *name,
list_init(&s->tests);
list_insert(&all_tests, &s->node);
litest_add_tcase(s, func, required, excluded);
return s;
}
void
litest_add(const char *name,
void *func,
enum litest_device_feature required,
enum litest_device_feature excluded)
{
litest_add_tcase(get_suite(name), func, required, excluded);
}
void
litest_add_for_device(const char *name,
void *func,
enum litest_device_type type)
{
struct suite *s;
struct litest_test_device **dev = devices;
assert(type < LITEST_NO_DEVICE);
s = get_suite(name);
while (*dev) {
if ((*dev)->type == type) {
litest_add_tcase_for_device(s, func, *dev);
return;
}
dev++;
}
ck_abort_msg("Invalid test device type");
}
static int
@ -243,7 +277,6 @@ is_debugger_attached(void)
return rc;
}
static void
litest_list_tests(struct list *tests)
{
@ -339,7 +372,7 @@ litest_run(int argc, char **argv) {
}
}
srunner_run_all(sr, CK_NORMAL);
srunner_run_all(sr, CK_ENV);
failed = srunner_ntests_failed(sr);
srunner_free(sr);
@ -429,7 +462,6 @@ merge_events(const int *orig, const int *override)
return events;
}
static struct litest_device *
litest_create(enum litest_device_type which,
const char *name_override,
@ -539,6 +571,18 @@ litest_add_device_with_overrides(struct libinput *libinput,
return d;
}
struct litest_device *
litest_add_device(struct libinput *libinput,
enum litest_device_type which)
{
return litest_add_device_with_overrides(libinput,
which,
NULL,
NULL,
NULL,
NULL);
}
struct litest_device *
litest_create_device_with_overrides(enum litest_device_type which,
const char *name_override,
@ -584,10 +628,12 @@ litest_delete_device(struct litest_device *d)
return;
libinput_device_unref(d->libinput_device);
libinput_path_remove_device(d->libinput_device);
if (d->owns_context)
libinput_unref(d->libinput);
libevdev_free(d->evdev);
libevdev_uinput_destroy(d->uinput);
free(d->private);
memset(d,0, sizeof(*d));
free(d);
}
@ -600,10 +646,10 @@ litest_event(struct litest_device *d, unsigned int type,
ck_assert_int_eq(ret, 0);
}
static int
auto_assign_value(struct litest_device *d,
const struct input_event *ev,
int slot, double x, double y)
int
litest_auto_assign_value(struct litest_device *d,
const struct input_event *ev,
int slot, double x, double y)
{
static int tracking_id;
int value = ev->value;
@ -631,6 +677,16 @@ auto_assign_value(struct litest_device *d,
return value;
}
static void
send_btntool(struct litest_device *d)
{
litest_event(d, EV_KEY, BTN_TOUCH, d->ntouches_down != 0);
litest_event(d, EV_KEY, BTN_TOOL_FINGER, d->ntouches_down == 1);
litest_event(d, EV_KEY, BTN_TOOL_DOUBLETAP, d->ntouches_down == 2);
litest_event(d, EV_KEY, BTN_TOOL_TRIPLETAP, d->ntouches_down == 3);
litest_event(d, EV_KEY, BTN_TOOL_QUADTAP, d->ntouches_down == 4);
litest_event(d, EV_KEY, BTN_TOOL_QUINTTAP, d->ntouches_down == 5);
}
void
litest_touch_down(struct litest_device *d, unsigned int slot,
@ -638,6 +694,10 @@ litest_touch_down(struct litest_device *d, unsigned int slot,
{
struct input_event *ev;
assert(++d->ntouches_down > 0);
send_btntool(d);
if (d->interface->touch_down) {
d->interface->touch_down(d, slot, x, y);
return;
@ -645,7 +705,7 @@ litest_touch_down(struct litest_device *d, unsigned int slot,
ev = d->interface->touch_down_events;
while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
int value = auto_assign_value(d, ev, slot, x, y);
int value = litest_auto_assign_value(d, ev, slot, x, y);
litest_event(d, ev->type, ev->code, value);
ev++;
}
@ -662,6 +722,10 @@ litest_touch_up(struct litest_device *d, unsigned int slot)
{ .type = -1, .code = -1 }
};
assert(--d->ntouches_down >= 0);
send_btntool(d);
if (d->interface->touch_up) {
d->interface->touch_up(d, slot);
return;
@ -671,7 +735,7 @@ litest_touch_up(struct litest_device *d, unsigned int slot)
ev = up;
while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
int value = auto_assign_value(d, ev, slot, 0, 0);
int value = litest_auto_assign_value(d, ev, slot, 0, 0);
litest_event(d, ev->type, ev->code, value);
ev++;
}
@ -690,7 +754,7 @@ litest_touch_move(struct litest_device *d, unsigned int slot,
ev = d->interface->touch_move_events;
while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
int value = auto_assign_value(d, ev, slot, x, y);
int value = litest_auto_assign_value(d, ev, slot, x, y);
litest_event(d, ev->type, ev->code, value);
ev++;
}
@ -832,6 +896,53 @@ litest_scale(const struct litest_device *d, unsigned int axis, double val)
return (max - min) * val/100.0 + min;
}
void
litest_wait_for_event(struct libinput *li)
{
return litest_wait_for_event_of_type(li, -1);
}
void
litest_wait_for_event_of_type(struct libinput *li, ...)
{
va_list args;
enum libinput_event_type types[32] = {LIBINPUT_EVENT_NONE};
size_t ntypes = 0;
enum libinput_event_type type;
va_start(args, li);
type = va_arg(args, int);
while ((int)type != -1) {
assert(type > 0);
assert(ntypes < ARRAY_LENGTH(types));
types[ntypes++] = type;
type = va_arg(args, int);
}
va_end(args);
while (1) {
size_t i;
struct libinput_event *event;
while ((type = libinput_next_event_type(li)) == LIBINPUT_EVENT_NONE) {
msleep(10);
libinput_dispatch(li);
}
/* no event mask means wait for any event */
if (ntypes == 0)
return;
for (i = 0; i < ntypes; i++) {
if (type == types[i])
return;
}
event = libinput_get_event(li);
libinput_event_destroy(event);
}
}
void
litest_drain_events(struct libinput *li)
{
@ -952,8 +1063,6 @@ litest_create_uinput_device_from_description(const char *name,
if (type == INPUT_PROP_MAX) {
rc = libevdev_enable_property(dev, code);
} else {
if (type != EV_SYN)
ck_assert(!libevdev_has_event_code(dev, type, code));
rc = libevdev_enable_event_code(dev, type, code,
type == EV_ABS ? &default_abs : NULL);
}
@ -963,7 +1072,11 @@ litest_create_uinput_device_from_description(const char *name,
rc = libevdev_uinput_create_from_device(dev,
LIBEVDEV_UINPUT_OPEN_MANAGED,
&uinput);
ck_assert_int_eq(rc, 0);
/* workaround for a bug in libevdev pre-1.3
http://cgit.freedesktop.org/libevdev/commit/?id=debe9b030c8069cdf78307888ef3b65830b25122 */
if (rc == -EBADF)
rc = -EACCES;
ck_assert_msg(rc == 0, "Failed to create uinput device: %s", strerror(-rc));
libevdev_free(dev);
@ -1047,3 +1160,63 @@ litest_create_uinput_device(const char *name, struct input_id *id, ...)
return uinput;
}
void
litest_assert_button_event(struct libinput *li, unsigned int button,
enum libinput_button_state state)
{
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
litest_wait_for_event(li);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_BUTTON);
ptrev = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_button(ptrev),
button);
ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrev),
state);
libinput_event_destroy(event);
}
void litest_assert_scroll(struct libinput *li, unsigned int axis, int dir)
{
struct libinput_event *event, *next_event;
struct libinput_event_pointer *ptrev;
event = libinput_get_event(li);
next_event = libinput_get_event(li);
ck_assert(next_event != NULL); /* At least 1 scroll + stop scroll */
while (event) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_AXIS);
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev), axis);
if (next_event) {
/* Normal scroll event, check dir */
if (dir > 0) {
ck_assert_int_ge(
libinput_event_pointer_get_axis_value(ptrev),
dir);
} else {
ck_assert_int_le(
libinput_event_pointer_get_axis_value(ptrev),
dir);
}
} else {
/* Last scroll event, must be 0 */
ck_assert_int_eq(
libinput_event_pointer_get_axis_value(ptrev),
0);
}
libinput_event_destroy(event);
event = next_event;
next_event = libinput_get_event(li);
}
}

View file

@ -35,18 +35,20 @@
enum litest_device_type {
LITEST_NO_DEVICE = -1,
LITEST_SYNAPTICS_CLICKPAD,
LITEST_SYNAPTICS_TOUCHPAD,
LITEST_SYNAPTICS_TOPBUTTONPAD,
LITEST_BCM5974,
LITEST_KEYBOARD,
LITEST_TRACKPOINT,
LITEST_MOUSE,
LITEST_WACOM_TOUCH,
LITEST_WACOM_BAMBOO,
LITEST_WACOM_CINTIQ,
LITEST_WACOM_INTUOS,
LITEST_WACOM_ISDV4,
LITEST_SYNAPTICS_CLICKPAD = -2,
LITEST_SYNAPTICS_TOUCHPAD = -3,
LITEST_SYNAPTICS_TOPBUTTONPAD = -4,
LITEST_BCM5974 = -5,
LITEST_KEYBOARD = -6,
LITEST_TRACKPOINT = -7,
LITEST_MOUSE = -8,
LITEST_WACOM_TOUCH = -9,
LITEST_ALPS_SEMI_MT = -10,
LITEST_GENERIC_SINGLETOUCH = -11,
LITEST_WACOM_BAMBOO = -12,
LITEST_WACOM_CINTIQ = -13,
LITEST_WACOM_INTUOS = -14,
LITEST_WACOM_ISDV4 = -15,
};
enum litest_device_feature {
@ -62,9 +64,11 @@ enum litest_device_feature {
LITEST_SINGLE_TOUCH = 1 << 7,
LITEST_APPLE_CLICKPAD = 1 << 8,
LITEST_TOPBUTTONPAD = 1 << 9,
LITEST_TABLET = 1 << 10,
LITEST_DISTANCE = 1 << 11,
LITEST_TOOL_SERIAL = 1 << 12,
LITEST_SEMI_MT = 1 << 10,
LITEST_POINTINGSTICK = 1 << 11,
LITEST_TABLET = 1 << 12,
LITEST_DISTANCE = 1 << 13,
LITEST_TOOL_SERIAL = 1 << 14,
};
struct litest_device {
@ -74,6 +78,9 @@ struct litest_device {
bool owns_context;
struct libinput_device *libinput_device;
struct litest_device_interface *interface;
int ntouches_down;
void *private; /* device-specific data */
};
struct libinput *litest_create_context(void);
@ -85,10 +92,16 @@ struct axis_replacement {
void litest_add(const char *name, void *func,
enum litest_device_feature required_feature,
enum litest_device_feature excluded_feature);
void
litest_add_for_device(const char *name,
void *func,
enum litest_device_type type);
void litest_add_no_device(const char *name, void *func);
int litest_run(int argc, char **argv);
struct litest_device * litest_create_device(enum litest_device_type which);
struct litest_device * litest_add_device(struct libinput *libinput,
enum litest_device_type which);
struct libevdev_uinput *
litest_create_uinput_device_from_description(const char *name,
const struct input_id *id,
@ -116,6 +129,9 @@ void litest_event(struct litest_device *t,
unsigned int type,
unsigned int code,
int value);
int litest_auto_assign_value(struct litest_device *d,
const struct input_event *ev,
int slot, double x, double y);
void litest_touch_up(struct litest_device *d, unsigned int slot);
void litest_touch_move(struct litest_device *d,
unsigned int slot,
@ -143,8 +159,14 @@ void litest_button_click(struct litest_device *d,
void litest_keyboard_key(struct litest_device *d,
unsigned int key,
bool is_press);
void litest_wait_for_event(struct libinput *li);
void litest_wait_for_event_of_type(struct libinput *li, ...);
void litest_drain_events(struct libinput *li);
void litest_assert_empty_queue(struct libinput *li);
void litest_assert_button_event(struct libinput *li,
unsigned int button,
enum libinput_button_state state);
void litest_assert_scroll(struct libinput *li, unsigned int axis, int dir);
struct libevdev_uinput * litest_create_uinput_device(const char *name,
struct input_id *id,

View file

@ -469,6 +469,83 @@ START_TEST(config_status_string)
}
END_TEST
START_TEST(matrix_helpers)
{
struct matrix m1, m2, m3;
float f[6] = { 1, 2, 3, 4, 5, 6 };
int x, y;
int row, col;
matrix_init_identity(&m1);
for (row = 0; row < 3; row++) {
for (col = 0; col < 3; col++) {
ck_assert_int_eq(m1.val[row][col],
(row == col) ? 1 : 0);
}
}
ck_assert(matrix_is_identity(&m1));
matrix_from_farray6(&m2, f);
ck_assert_int_eq(m2.val[0][0], 1);
ck_assert_int_eq(m2.val[0][1], 2);
ck_assert_int_eq(m2.val[0][2], 3);
ck_assert_int_eq(m2.val[1][0], 4);
ck_assert_int_eq(m2.val[1][1], 5);
ck_assert_int_eq(m2.val[1][2], 6);
ck_assert_int_eq(m2.val[2][0], 0);
ck_assert_int_eq(m2.val[2][1], 0);
ck_assert_int_eq(m2.val[2][2], 1);
x = 100;
y = 5;
matrix_mult_vec(&m1, &x, &y);
ck_assert_int_eq(x, 100);
ck_assert_int_eq(y, 5);
matrix_mult(&m3, &m1, &m1);
ck_assert(matrix_is_identity(&m3));
matrix_init_scale(&m2, 2, 4);
ck_assert_int_eq(m2.val[0][0], 2);
ck_assert_int_eq(m2.val[0][1], 0);
ck_assert_int_eq(m2.val[0][2], 0);
ck_assert_int_eq(m2.val[1][0], 0);
ck_assert_int_eq(m2.val[1][1], 4);
ck_assert_int_eq(m2.val[1][2], 0);
ck_assert_int_eq(m2.val[2][0], 0);
ck_assert_int_eq(m2.val[2][1], 0);
ck_assert_int_eq(m2.val[2][2], 1);
matrix_mult_vec(&m2, &x, &y);
ck_assert_int_eq(x, 200);
ck_assert_int_eq(y, 20);
matrix_init_translate(&m2, 10, 100);
ck_assert_int_eq(m2.val[0][0], 1);
ck_assert_int_eq(m2.val[0][1], 0);
ck_assert_int_eq(m2.val[0][2], 10);
ck_assert_int_eq(m2.val[1][0], 0);
ck_assert_int_eq(m2.val[1][1], 1);
ck_assert_int_eq(m2.val[1][2], 100);
ck_assert_int_eq(m2.val[2][0], 0);
ck_assert_int_eq(m2.val[2][1], 0);
ck_assert_int_eq(m2.val[2][2], 1);
matrix_mult_vec(&m2, &x, &y);
ck_assert_int_eq(x, 210);
ck_assert_int_eq(y, 120);
matrix_to_farray6(&m2, f);
ck_assert_int_eq(f[0], 1);
ck_assert_int_eq(f[1], 0);
ck_assert_int_eq(f[2], 10);
ck_assert_int_eq(f[3], 0);
ck_assert_int_eq(f[4], 1);
ck_assert_int_eq(f[5], 100);
}
END_TEST
int main (int argc, char **argv) {
litest_add_no_device("events:conversion", event_conversion_device_notify);
litest_add_no_device("events:conversion", event_conversion_pointer);
@ -480,5 +557,6 @@ int main (int argc, char **argv) {
litest_add("device:id", device_ids, LITEST_ANY, LITEST_ANY);
litest_add_no_device("config:status string", config_status_string);
litest_add_no_device("misc:matrix", matrix_helpers);
return litest_run(argc, argv);
}

View file

@ -53,7 +53,6 @@ const struct libinput_interface simple_interface = {
.close_restricted = close_restricted,
};
START_TEST(path_create_NULL)
{
struct libinput *li;
@ -244,12 +243,11 @@ END_TEST
START_TEST(path_add_invalid_path)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput *li;
struct libinput_event *event;
struct libinput_device *device;
litest_drain_events(li);
li = litest_create_context();
device = libinput_path_add_device(li, "/tmp/");
ck_assert(device == NULL);
@ -258,6 +256,8 @@ START_TEST(path_add_invalid_path)
while ((event = libinput_get_event(li)))
ck_abort();
libinput_unref(li);
}
END_TEST
@ -492,7 +492,6 @@ START_TEST(path_add_device_suspend_resume)
ck_assert_int_eq(nevents, 2);
libinput_suspend(li);
libinput_dispatch(li);
@ -576,7 +575,6 @@ START_TEST(path_add_device_suspend_resume_fail)
ck_assert_int_eq(nevents, 2);
libinput_suspend(li);
libinput_dispatch(li);
@ -667,7 +665,6 @@ START_TEST(path_add_device_suspend_resume_remove_device)
ck_assert_int_eq(nevents, 2);
libinput_suspend(li);
libinput_dispatch(li);
@ -796,26 +793,26 @@ START_TEST(path_seat_recycle)
}
END_TEST
int main (int argc, char **argv) {
litest_add("path:create", path_create_NULL, LITEST_ANY, LITEST_ANY);
litest_add("path:create", path_create_invalid, LITEST_ANY, LITEST_ANY);
litest_add("path:create", path_create_destroy, LITEST_ANY, LITEST_ANY);
litest_add("path:suspend", path_suspend, LITEST_ANY, LITEST_ANY);
litest_add("path:suspend", path_double_suspend, LITEST_ANY, LITEST_ANY);
litest_add("path:suspend", path_double_resume, LITEST_ANY, LITEST_ANY);
litest_add("path:suspend", path_add_device_suspend_resume, LITEST_ANY, LITEST_ANY);
litest_add("path:suspend", path_add_device_suspend_resume_fail, LITEST_ANY, LITEST_ANY);
litest_add("path:suspend", path_add_device_suspend_resume_remove_device, LITEST_ANY, LITEST_ANY);
litest_add("path:seat events", path_added_seat, LITEST_ANY, LITEST_ANY);
int
main(int argc, char **argv)
{
litest_add_no_device("path:create", path_create_NULL);
litest_add_no_device("path:create", path_create_invalid);
litest_add_no_device("path:create", path_create_destroy);
litest_add_no_device("path:suspend", path_suspend);
litest_add_no_device("path:suspend", path_double_suspend);
litest_add_no_device("path:suspend", path_double_resume);
litest_add_no_device("path:suspend", path_add_device_suspend_resume);
litest_add_no_device("path:suspend", path_add_device_suspend_resume_fail);
litest_add_no_device("path:suspend", path_add_device_suspend_resume_remove_device);
litest_add_for_device("path:seat events", path_added_seat, LITEST_SYNAPTICS_CLICKPAD);
litest_add("path:device events", path_added_device, LITEST_ANY, LITEST_ANY);
litest_add("path:device events", path_device_sysname, LITEST_ANY, LITEST_ANY);
litest_add("path:device events", path_add_device, LITEST_ANY, LITEST_ANY);
litest_add("path:device events", path_add_invalid_path, LITEST_ANY, LITEST_ANY);
litest_add("path:device events", path_remove_device, LITEST_ANY, LITEST_ANY);
litest_add("path:device events", path_double_remove_device, LITEST_ANY, LITEST_ANY);
litest_add("path:seat", path_seat_recycle,
LITEST_DISABLE_DEVICE, LITEST_DISABLE_DEVICE);
litest_add_for_device("path:device events", path_add_device, LITEST_SYNAPTICS_CLICKPAD);
litest_add_no_device("path:device events", path_add_invalid_path);
litest_add_for_device("path:device events", path_remove_device, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("path:device events", path_double_remove_device, LITEST_SYNAPTICS_CLICKPAD);
litest_add_no_device("path:seat", path_seat_recycle);
return litest_run(argc, argv);
}

View file

@ -105,26 +105,13 @@ static void
test_button_event(struct litest_device *dev, unsigned int button, int state)
{
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
litest_event(dev, EV_KEY, button, state);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_BUTTON);
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ck_assert_int_eq(libinput_event_pointer_get_button(ptrev), button);
ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrev),
state ?
LIBINPUT_BUTTON_STATE_PRESSED :
LIBINPUT_BUTTON_STATE_RELEASED);
libinput_event_destroy(event);
litest_assert_button_event(li, button,
state ? LIBINPUT_BUTTON_STATE_PRESSED :
LIBINPUT_BUTTON_STATE_RELEASED);
}
START_TEST(pointer_button)
@ -145,13 +132,104 @@ START_TEST(pointer_button)
test_button_event(dev, BTN_RIGHT, 0);
}
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE)) {
/* Skip middle button test on trackpoints (used for scrolling) */
if (!libevdev_has_property(dev->evdev, INPUT_PROP_POINTING_STICK) &&
libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE)) {
test_button_event(dev, BTN_MIDDLE, 1);
test_button_event(dev, BTN_MIDDLE, 0);
}
}
END_TEST
START_TEST(pointer_button_auto_release)
{
struct libinput *libinput;
struct litest_device *dev;
struct libinput_event *event;
enum libinput_event_type type;
struct libinput_event_pointer *pevent;
struct {
int code;
int released;
} buttons[] = {
{ .code = BTN_LEFT, },
{ .code = BTN_MIDDLE, },
{ .code = BTN_EXTRA, },
{ .code = BTN_SIDE, },
{ .code = BTN_BACK, },
{ .code = BTN_FORWARD, },
{ .code = BTN_4, },
};
int events[2 * (ARRAY_LENGTH(buttons) + 1)];
unsigned i;
int button;
int valid_code;
/* Enable all tested buttons on the device */
for (i = 0; i < 2 * ARRAY_LENGTH(buttons);) {
button = buttons[i / 2].code;
events[i++] = EV_KEY;
events[i++] = button;
}
events[i++] = -1;
events[i++] = -1;
libinput = litest_create_context();
dev = litest_add_device_with_overrides(libinput,
LITEST_MOUSE,
"Generic mouse",
NULL, NULL, events);
litest_drain_events(libinput);
/* Send pressed events, without releasing */
for (i = 0; i < ARRAY_LENGTH(buttons); ++i) {
test_button_event(dev, buttons[i].code, 1);
}
litest_drain_events(libinput);
/* "Disconnect" device */
litest_delete_device(dev);
/* Mark all released buttons until device is removed */
while (1) {
event = libinput_get_event(libinput);
ck_assert_notnull(event);
type = libinput_event_get_type(event);
if (type == LIBINPUT_EVENT_DEVICE_REMOVED) {
libinput_event_destroy(event);
break;
}
ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_BUTTON);
pevent = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_button_state(pevent),
LIBINPUT_BUTTON_STATE_RELEASED);
button = libinput_event_pointer_get_button(pevent);
valid_code = 0;
for (i = 0; i < ARRAY_LENGTH(buttons); ++i) {
if (buttons[i].code == button) {
ck_assert_int_eq(buttons[i].released, 0);
buttons[i].released = 1;
valid_code = 1;
}
}
ck_assert_int_eq(valid_code, 1);
libinput_event_destroy(event);
}
/* Check that all pressed buttons has been released. */
for (i = 0; i < ARRAY_LENGTH(buttons); ++i) {
ck_assert_int_eq(buttons[i].released, 1);
}
libinput_unref(libinput);
}
END_TEST
static void
test_wheel_event(struct litest_device *dev, int which, int amount)
{
@ -296,12 +374,37 @@ START_TEST(pointer_seat_button_count)
}
END_TEST
START_TEST(pointer_no_calibration)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
enum libinput_config_status status;
int rc;
float calibration[6] = {0};
rc = libinput_device_config_calibration_has_matrix(d);
ck_assert_int_eq(rc, 0);
rc = libinput_device_config_calibration_get_matrix(d, calibration);
ck_assert_int_eq(rc, 0);
rc = libinput_device_config_calibration_get_default_matrix(d,
calibration);
ck_assert_int_eq(rc, 0);
status = libinput_device_config_calibration_set_matrix(d,
calibration);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST
int main (int argc, char **argv) {
litest_add("pointer:motion", pointer_motion_relative, LITEST_POINTER, LITEST_ANY);
litest_add("pointer:button", pointer_button, LITEST_BUTTON, LITEST_CLICKPAD);
litest_add_no_device("pointer:button_auto_release", pointer_button_auto_release);
litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_ANY);
litest_add_no_device("pointer:seat button count", pointer_seat_button_count);
litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH);
return litest_run(argc, argv);
}

View file

@ -26,6 +26,7 @@
#include <errno.h>
#include <fcntl.h>
#include <libinput.h>
#include <libevdev/libevdev.h>
#include <unistd.h>
#include "libinput-util.h"
@ -112,7 +113,6 @@ START_TEST(touch_abs_transform)
}
END_TEST
START_TEST(touch_many_slots)
{
struct libinput *libinput;
@ -213,6 +213,194 @@ START_TEST(touch_double_touch_down_up)
}
END_TEST
START_TEST(touch_calibration_scale)
{
struct libinput *li;
struct litest_device *dev;
struct libinput_event *ev;
struct libinput_event_touch *tev;
float matrix[6] = {
1, 0, 0,
0, 1, 0
};
float calibration;
double x, y;
const int width = 640, height = 480;
dev = litest_current_device();
li = dev->libinput;
for (calibration = 0.1; calibration < 1; calibration += 0.1) {
libinput_device_config_calibration_set_matrix(dev->libinput_device,
matrix);
litest_drain_events(li);
litest_touch_down(dev, 0, 100, 100);
litest_touch_up(dev, 0);
litest_wait_for_event(li);
ev = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(ev),
LIBINPUT_EVENT_TOUCH_DOWN);
tev = libinput_event_get_touch_event(ev);
x = libinput_event_touch_get_x_transformed(tev, width);
y = libinput_event_touch_get_y_transformed(tev, height);
ck_assert_int_eq(round(x), round(width * matrix[0]));
ck_assert_int_eq(round(y), round(height * matrix[4]));
libinput_event_destroy(ev);
litest_drain_events(li);
matrix[0] = calibration;
matrix[4] = 1 - calibration;
}
}
END_TEST
START_TEST(touch_calibration_rotation)
{
struct libinput *li;
struct litest_device *dev;
struct libinput_event *ev;
struct libinput_event_touch *tev;
float matrix[6];
int i;
double x, y;
int width = 1024, height = 480;
dev = litest_current_device();
li = dev->libinput;
for (i = 0; i < 4; i++) {
float angle = i * M_PI/2;
/* [ cos -sin tx ]
[ sin cos ty ]
[ 0 0 1 ] */
matrix[0] = cos(angle);
matrix[1] = -sin(angle);
matrix[3] = sin(angle);
matrix[4] = cos(angle);
switch(i) {
case 0: /* 0 deg */
matrix[2] = 0;
matrix[5] = 0;
break;
case 1: /* 90 deg cw */
matrix[2] = 1;
matrix[5] = 0;
break;
case 2: /* 180 deg cw */
matrix[2] = 1;
matrix[5] = 1;
break;
case 3: /* 270 deg cw */
matrix[2] = 0;
matrix[5] = 1;
break;
}
libinput_device_config_calibration_set_matrix(dev->libinput_device,
matrix);
litest_drain_events(li);
litest_touch_down(dev, 0, 80, 20);
litest_touch_up(dev, 0);
litest_wait_for_event(li);
ev = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(ev),
LIBINPUT_EVENT_TOUCH_DOWN);
tev = libinput_event_get_touch_event(ev);
x = libinput_event_touch_get_x_transformed(tev, width);
y = libinput_event_touch_get_y_transformed(tev, height);
/* rounding errors... */
#define almost_equal(a_, b_) \
{ ck_assert_int_ge((a_) + 0.5, (b_) - 1); \
ck_assert_int_le((a_) + 0.5, (b_) + 1); }
switch(i) {
case 0: /* 0 deg */
almost_equal(x, width * 0.8);
almost_equal(y, height * 0.2);
break;
case 1: /* 90 deg cw */
almost_equal(x, width * 0.8);
almost_equal(y, height * 0.8);
break;
case 2: /* 180 deg cw */
almost_equal(x, width * 0.2);
almost_equal(y, height * 0.8);
break;
case 3: /* 270 deg cw */
almost_equal(x, width * 0.2);
almost_equal(y, height * 0.2);
break;
}
#undef almost_equal
libinput_event_destroy(ev);
litest_drain_events(li);
}
}
END_TEST
START_TEST(touch_calibration_translation)
{
struct libinput *li;
struct litest_device *dev;
struct libinput_event *ev;
struct libinput_event_touch *tev;
float matrix[6] = {
1, 0, 0,
0, 1, 0
};
float translate;
double x, y;
const int width = 640, height = 480;
dev = litest_current_device();
li = dev->libinput;
/* translating from 0 up to 1 device width/height */
for (translate = 0.1; translate <= 1; translate += 0.1) {
libinput_device_config_calibration_set_matrix(dev->libinput_device,
matrix);
litest_drain_events(li);
litest_touch_down(dev, 0, 100, 100);
litest_touch_up(dev, 0);
litest_wait_for_event(li);
ev = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(ev),
LIBINPUT_EVENT_TOUCH_DOWN);
tev = libinput_event_get_touch_event(ev);
x = libinput_event_touch_get_x_transformed(tev, width);
y = libinput_event_touch_get_y_transformed(tev, height);
/* sigh. rounding errors */
ck_assert_int_ge(round(x), width + round(width * matrix[2]) - 1);
ck_assert_int_ge(round(y), height + round(height * matrix[5]) - 1);
ck_assert_int_le(round(x), width + round(width * matrix[2]) + 1);
ck_assert_int_le(round(y), height + round(height * matrix[5]) + 1);
libinput_event_destroy(ev);
litest_drain_events(li);
matrix[2] = translate;
matrix[5] = 1 - translate;
}
}
END_TEST
int
main(int argc, char **argv)
{
@ -220,6 +408,12 @@ main(int argc, char **argv)
litest_add_no_device("touch:abs-transform", touch_abs_transform);
litest_add_no_device("touch:many-slots", touch_many_slots);
litest_add("touch:double-touch-down-up", touch_double_touch_down_up, LITEST_TOUCH, LITEST_ANY);
litest_add("touch:calibration", touch_calibration_scale, LITEST_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:calibration", touch_calibration_scale, LITEST_SINGLE_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:calibration", touch_calibration_rotation, LITEST_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:calibration", touch_calibration_rotation, LITEST_SINGLE_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:calibration", touch_calibration_translation, LITEST_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:calibration", touch_calibration_translation, LITEST_SINGLE_TOUCH, LITEST_TOUCHPAD);
return litest_run(argc, argv);
}

File diff suppressed because it is too large Load diff

103
test/trackpoint.c Normal file
View file

@ -0,0 +1,103 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <check.h>
#include <errno.h>
#include <fcntl.h>
#include <libinput.h>
#include <unistd.h>
#include "libinput-util.h"
#include "litest.h"
START_TEST(trackpoint_middlebutton)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
litest_drain_events(li);
/* A quick middle button click should get reported normally */
litest_button_click(dev, BTN_MIDDLE, 1);
litest_button_click(dev, BTN_MIDDLE, 0);
litest_assert_button_event(li, BTN_MIDDLE, 1);
litest_assert_button_event(li, BTN_MIDDLE, 0);
litest_assert_empty_queue(li);
}
END_TEST
static void
test_2fg_scroll(struct litest_device *dev, double dx, double dy)
{
struct libinput *li = dev->libinput;
litest_button_click(dev, BTN_MIDDLE, 1);
libinput_dispatch(li);
msleep(300);
libinput_dispatch(li);
litest_event(dev, EV_REL, REL_X, dx);
litest_event(dev, EV_REL, REL_Y, dy);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_button_click(dev, BTN_MIDDLE, 0);
libinput_dispatch(li);
}
START_TEST(trackpoint_scroll)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
litest_drain_events(li);
test_2fg_scroll(dev, 1, 6);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 6);
test_2fg_scroll(dev, 1, -7);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -7);
test_2fg_scroll(dev, 8, 1);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 8);
test_2fg_scroll(dev, -9, 1);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
/* scroll smaller than the threshold should not generate events */
test_2fg_scroll(dev, 1, 1);
/* long middle press without movement should not generate events */
test_2fg_scroll(dev, 0, 0);
litest_assert_empty_queue(li);
}
END_TEST
int main(int argc, char **argv) {
litest_add("trackpoint:middlebutton", trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY);
litest_add("trackpoint:scroll", trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY);
return litest_run(argc, argv);
}

View file

@ -47,7 +47,6 @@ const struct libinput_interface simple_interface = {
.close_restricted = close_restricted,
};
START_TEST(udev_create_NULL)
{
struct libinput *li;
@ -408,19 +407,20 @@ START_TEST(udev_seat_recycle)
}
END_TEST
int main (int argc, char **argv) {
int
main(int argc, char **argv)
{
litest_add_no_device("udev:create", udev_create_NULL);
litest_add_no_device("udev:create", udev_create_seat0);
litest_add_no_device("udev:create", udev_create_empty_seat);
litest_add_no_device("udev:seat events", udev_added_seat_default);
litest_add("udev:suspend", udev_double_suspend, LITEST_ANY, LITEST_ANY);
litest_add("udev:suspend", udev_double_resume, LITEST_ANY, LITEST_ANY);
litest_add("udev:suspend", udev_suspend_resume, LITEST_ANY, LITEST_ANY);
litest_add("udev:device events", udev_device_sysname, LITEST_ANY, LITEST_ANY);
litest_add("udev:seat", udev_seat_recycle, LITEST_ANY, LITEST_ANY);
litest_add_for_device("udev:suspend", udev_double_suspend, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("udev:suspend", udev_double_resume, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("udev:suspend", udev_suspend_resume, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("udev:device events", udev_device_sysname, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("udev:seat", udev_seat_recycle, LITEST_SYNAPTICS_CLICKPAD);
return litest_run(argc, argv);
}

View file

@ -5,7 +5,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \
event_debug_SOURCES = event-debug.c
event_debug_LDADD = ../src/libinput.la $(LIBUDEV_LIBS)
event_debug_LDFLAGS = -static
event_debug_LDFLAGS = -no-install
event_debug_CFLAGS = $(LIBUDEV_CFLAGS)
if BUILD_EVENTGUI
@ -14,5 +14,5 @@ noinst_PROGRAMS += event-gui
event_gui_SOURCES = event-gui.c
event_gui_LDADD = ../src/libinput.la $(CAIRO_LIBS) $(GTK_LIBS) $(LIBUDEV_LIBS)
event_gui_CFLAGS = $(CAIRO_CFLAGS) $(GTK_CFLAGS) $(LIBUDEV_CFLAGS)
event_gui_LDFLAGS = -static
event_gui_LDFLAGS = -no-install
endif

View file

@ -223,6 +223,15 @@ handle_event_device_notify(struct libinput_event *ev)
type = "removed";
msg("%s %s\n", libinput_device_get_sysname(dev), type);
if (libinput_device_config_tap_get_finger_count(dev) > 0) {
enum libinput_config_status status;
status = libinput_device_config_tap_set_enabled(dev,
LIBINPUT_CONFIG_TAP_ENABLED);
if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
error("%s: Failed to enable tapping\n",
libinput_device_get_sysname(dev));
}
}
static void
@ -427,7 +436,6 @@ parse_opts(int argc, char *argv[])
return 0;
}
static int
open_restricted(const char *path, int flags, void *user_data)
{