Merge branch 'master' into tablet-support

This commit is contained in:
Peter Hutterer 2014-07-21 09:31:37 +10:00
commit 0891bc0d92
30 changed files with 2313 additions and 1718 deletions

View file

@ -20,7 +20,7 @@ AC_SUBST([LIBINPUT_VERSION], [libinput_version])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
# Before making a release, the LIBINPUT_LT_VERSION string should be
# modified.
@ -57,6 +57,8 @@ PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0])
PKG_CHECK_MODULES(LIBUDEV, [libudev])
PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4])
AC_CHECK_LIB([m], [atan2])
AC_CHECK_LIB([rt], [clock_gettime])
if test "x$GCC" = "xyes"; then
GCC_CXXFLAGS="-Wall -Wextra -Wno-unused-parameter -g -fvisibility=hidden"
@ -119,3 +121,12 @@ AC_CONFIG_FILES([Makefile
test/Makefile
tools/Makefile])
AC_OUTPUT
AC_MSG_RESULT([
Prefix ${prefix}
Build documentation ${have_doxygen}
Build tests ${build_tests}
Tests use valgrind ${VALGRIND}
Build GUI event tool ${build_eventgui}
])

View file

@ -1,532 +1,360 @@
<?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">
<defs/>
<g transform="translate(0.5,0.5)">
<path d="M 862 425 L 894 418" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 899 417 L 893 422 L 894 418 L 891 415 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<ellipse cx="785" cy="151" rx="49.5" ry="30" fill="#ccccff" stroke="#000000" stroke-width="2" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="785" y="141">
NONE</text>
<text x="785" y="155">
on-entry:</text>
<text x="785" y="169">
curr = none</text>
</g>
<rect x="712" y="391" width="150" height="101" 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">
<text x="787" y="424">
BOTTOM_NEW</text>
<text x="787" y="438">
on-entry:</text>
<text x="787" y="452">
curr = button</text>
<text x="787" y="466">
start enter timeout</text>
</g>
<rect x="1023" y="392" 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">
<text x="1088" y="425">
AREA</text>
<text x="1088" y="439">
on-entry:</text>
<text x="1088" y="453">
curr =area</text>
<text x="1088" y="467">
set_pointer()</text>
</g>
<path d="M 921 376 C 923 373 927 370 932 370 L 965 370 C 970 370 974 373 976 376 L 996 404 C 997 405 997 407 996 409 L 976 436 C 974 440 970 442 965 442 L 932 442 C 927 442 923 440 921 436 L 901 409 C 900 407 900 405 901 404 L 921 376 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="949" y="403">
finger in</text>
<text x="949" y="417">
area or top</text>
</g>
<rect x="722" 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">
<text x="787" y="766">
BOTTOM</text>
</g>
<path d="M 759 7 C 762 4 766 2 770 2 L 804 2 C 808 2 812 4 815 7 L 835 30 C 836 31 836 33 835 34 L 815 57 C 812 60 808 62 804 62 L 770 62 C 766 62 762 60 759 57 L 739 34 C 739 33 739 31 739 30 L 759 7 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="787" y="29">
finger</text>
<text x="787" y="43">
up</text>
</g>
<path d="M 694 571 C 697 568 701 566 705 566 L 739 566 C 743 566 747 568 750 571 L 770 594 C 771 596 771 597 770 598 L 750 621 C 747 625 743 626 739 626 L 705 626 C 701 626 697 625 694 621 L 674 598 C 674 597 674 596 674 594 L 694 571 Z" fill="#000000" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#FFFFFF" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="722" y="586">
phys</text>
<text x="722" y="600">
button</text>
<text x="722" y="614">
press</text>
</g>
<path d="M 997 419 L 1017 424" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1022 425 L 1014 427 L 1017 424 L 1016 420 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 798 571 C 800 568 804 566 809 566 L 842 566 C 847 566 851 568 853 571 L 873 594 C 874 596 874 597 873 598 L 853 621 C 851 625 847 626 842 626 L 809 626 C 804 626 800 625 798 621 L 778 598 C 777 597 777 596 778 594 L 798 571 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="826" y="593">
enter</text>
<text x="826" y="607">
timeout</text>
</g>
<path d="M 787 492 L 812 560" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 814 565 L 808 560 L 812 560 L 815 558 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 819 626 L 800 706" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 799 711 L 797 703 L 800 706 L 804 705 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 895 694 C 898 690 902 688 906 688 L 940 688 C 944 688 948 690 951 694 L 971 718 C 971 719 971 721 971 722 L 951 747 C 948 750 944 752 940 752 L 906 752 C 902 752 898 750 895 747 L 875 722 C 874 721 874 719 875 718 L 895 694 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="923" y="717">
finger in</text>
<text x="923" y="731">
area or top</text>
</g>
<path d="M 852 762 L 871 726" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 874 721 L 874 729 L 871 726 L 867 726 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="991" y="718" width="194" height="94" 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">
<text x="1088" y="755">
BOTTOM_TO_AREA</text>
<text x="1088" y="769">
on-entry:</text>
<text x="1088" y="783">
start leave timeout</text>
</g>
<path d="M 971 720 L 988 759" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 991 764 L 985 759 L 988 759 L 991 756 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1060 541 C 1063 538 1067 536 1071 536 L 1105 536 C 1109 536 1113 538 1116 541 L 1136 564 C 1136 566 1136 567 1136 568 L 1116 591 C 1113 595 1109 596 1105 596 L 1071 596 C 1067 596 1063 595 1060 591 L 1040 568 C 1039 567 1039 566 1040 564 L 1060 541 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="1088" y="563">
leave</text>
<text x="1088" y="577">
timeout</text>
</g>
<path d="M 1088 718 L 1088 603" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1088 597 L 1091 604 L 1088 603 L 1084 604 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1088 536 L 1088 498" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1088 493 L 1091 500 L 1088 498 L 1084 500 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 766 235 C 768 232 771 230 774 230 L 800 230 C 803 230 806 232 808 235 L 824 259 C 824 260 824 262 824 263 L 808 287 C 806 290 803 292 800 292 L 774 292 C 771 292 768 290 766 287 L 750 263 C 750 262 750 260 750 259 L 766 235 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="787" y="258">
finger in</text>
<text x="787" y="272">
bottom</text>
</g>
<path d="M 785 181 L 786 224" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 786 229 L 783 222 L 786 224 L 790 222 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 787 292 L 787 384" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 787 390 L 784 383 L 787 384 L 791 383 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1068 236 C 1070 233 1073 231 1076 231 L 1100 231 C 1103 231 1105 233 1107 236 L 1121 259 C 1122 261 1122 262 1121 263 L 1107 287 C 1105 290 1103 292 1100 292 L 1076 292 C 1073 292 1070 290 1068 287 L 1054 263 C 1054 262 1054 261 1054 259 L 1068 236 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="1088" y="258">
finger in</text>
<text x="1088" y="272">
area</text>
</g>
<path d="M 1088 292 L 1088 386" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1088 391 L 1084 384 L 1088 386 L 1091 384 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 834 151 L 1048 246" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1053 248 L 1045 249 L 1048 246 L 1048 242 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 922 563 C 925 559 930 556 934 556 L 971 556 C 975 556 980 559 983 563 L 1004 594 C 1005 595 1005 597 1004 599 L 983 630 C 980 634 975 636 971 636 L 934 636 C 930 636 925 634 922 630 L 901 599 C 900 597 900 595 901 594 L 922 563 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="952" y="586">
finger in</text>
<text x="952" y="600">
bottom</text>
<text x="952" y="614">
button != curr</text>
</g>
<path d="M 927 558 L 872 487" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 869 483 L 876 486 L 872 487 L 870 491 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1050 718 L 988 641" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 985 637 L 992 641 L 988 641 L 987 645 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 722 626 L 783 707" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 786 711 L 779 708 L 783 707 L 785 703 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 787 492 L 726 562" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 723 566 L 725 558 L 726 562 L 730 563 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 896 772 C 899 768 903 765 908 765 L 944 765 C 949 765 953 768 956 772 L 977 802 C 978 804 978 806 977 808 L 956 838 C 953 843 949 845 944 845 L 908 845 C 903 845 899 843 896 838 L 875 808 C 874 806 874 804 875 802 L 896 772 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="926" y="788">
finger in</text>
<text x="926" y="802">
bottom</text>
<text x="926" y="816">
button == curr</text>
</g>
<path d="M 991 765 L 980 799" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 978 804 L 977 796 L 980 799 L 984 799 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 874 805 L 855 768" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 853 763 L 859 768 L 855 768 L 853 771 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 837 712 L 908 641" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 912 637 L 909 645 L 908 641 L 904 640 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 808 492 L 895 555" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 899 558 L 891 557 L 895 555 L 895 551 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1185 765 L 1358 765 Q 1368 765 1368 755 L 1368 42 Q 1368 32 1358 32 L 842 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 837 32 L 844 29 L 842 32 L 844 36 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1153 442 L 1358 442 Q 1368 442 1368 432 L 1368 42 Q 1368 32 1358 32 L 842 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 837 32 L 844 29 L 842 32 L 844 36 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 712 441 L 668 441 Q 658 441 658 451 L 658 862" 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"/>
<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>
</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"/>
<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"/>
<rect x="1763" y="17" width="100" height="40" fill="none" stroke="none" pointer-events="none"/>
<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"/>
<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>
</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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1998" y="248" width="24" height="18" stroke-width="0"/>
<text x="1999" y="261">
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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1815" y="330" width="18" height="18" stroke-width="0"/>
<text x="1815" y="339">
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"/>
<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>
</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"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="611">
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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1820" y="683" width="18" height="18" stroke-width="0"/>
<text x="1820" y="696">
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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1930" y="615" width="24" height="18" stroke-width="0"/>
<text x="1930" y="624">
yes</text>
</g>
<rect x="1968" y="587" 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>
</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"/>
<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>
</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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1941" y="795" width="24" height="18" stroke-width="0"/>
<text x="1942" y="804">
yes</text>
</g>
<rect x="1968" y="767" 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>
</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"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="400">
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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1688" y="377" width="18" height="18" stroke-width="0"/>
<text x="1688" y="390">
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"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="1815" y="438" width="24" height="18" stroke-width="0"/>
<text x="1815" y="448">
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">
<text x="1813" y="971">
Some touches are in right</text>
</g>
<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="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 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="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"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="2048" y="971">
button = BTN_RIGHT</text>
</g>
<rect x="1733" y="1082" 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="1813" y="1106">
button = BTN_LEFT</text>
</g>
<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="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"/>
<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>
</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 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"/>
<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>
</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">
<text x="1703" y="1356">
buttons.click_pend = 0</text>
</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 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">
<text x="1703" y="1426">
button</text>
</g>
<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="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="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>
</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"/>
<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>
<text x="477" y="269">
top</text>
</g>
<path d="M 722 762 L 668 762 Q 658 762 658 772 L 658 892 Q 658 902 668 902 L 1358 902 Q 1368 902 1368 892 L 1368 52" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 735 151 L 520 243" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 515 245 L 520 239 L 520 243 L 523 245 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="402" y="392" width="150" height="101" 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">
<text x="477" y="425">
TOP_NEW</text>
<text x="477" y="439">
on-entry:</text>
<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 552 442 L 648 442 Q 658 442 658 452 L 658 872" 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">
<text x="477" y="766">
TOP</text>
</g>
<path d="M 542 762 L 648 762 Q 658 762 658 772 L 658 872" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 524 571 C 527 568 531 566 535 566 L 569 566 C 573 566 577 568 580 571 L 600 594 C 601 596 601 597 600 598 L 580 621 C 577 625 573 626 569 626 L 535 626 C 531 626 527 625 524 621 L 504 598 C 504 597 504 596 504 594 L 524 571 Z" fill="#000000" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#FFFFFF" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="552" y="586">
phys</text>
<text x="552" y="600">
button</text>
<text x="552" y="614">
press</text>
</g>
<path d="M 412 571 C 414 568 418 566 423 566 L 456 566 C 461 566 465 568 467 571 L 487 594 C 488 596 488 597 487 598 L 467 621 C 465 625 461 626 456 626 L 423 626 C 418 626 414 625 412 621 L 392 598 C 391 597 391 596 392 594 L 412 571 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="440" y="593">
enter</text>
<text x="440" y="607">
timeout</text>
</g>
<path d="M 280 563 C 283 559 288 556 292 556 L 329 556 C 333 556 338 559 341 563 L 362 594 C 363 595 363 597 362 599 L 341 630 C 338 634 333 636 329 636 L 292 636 C 288 636 283 634 280 630 L 259 599 C 258 597 258 595 259 594 L 280 563 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="310" y="586">
finger in</text>
<text x="310" y="600">
top</text>
<text x="310" y="614">
button != curr</text>
</g>
<path d="M 477 493 L 547 562" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 551 566 L 544 563 L 547 562 L 549 558 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 477 493 L 442 561" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 440 565 L 440 558 L 442 561 L 446 561 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 465 492 L 368 557" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 364 560 L 368 554 L 368 557 L 371 559 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 344 556 L 396 494" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 399 490 L 397 497 L 396 494 L 392 493 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 440 626 L 470 703" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 472 708 L 466 703 L 470 703 L 472 700 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 552 626 L 503 704" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 501 708 L 501 700 L 503 704 L 507 704 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 427 712 L 355 641" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 351 637 L 359 640 L 355 641 L 354 645 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 636 325 C 638 321 642 319 645 319 L 675 319 C 679 319 682 321 684 325 L 702 353 C 702 354 702 356 702 357 L 684 385 C 682 389 679 391 675 391 L 645 391 C 642 391 638 389 636 385 L 618 357 C 618 356 618 354 618 353 L 636 325 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="660" y="345">
finger in</text>
<text x="660" y="359">
area or</text>
<text x="660" y="373">
bottom</text>
</g>
<path d="M 702 355 L 1048 355 Q 1058 355 1058 365 L 1058 386" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1058 391 L 1055 384 L 1058 386 L 1062 384 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 612 355 L 518 355 Q 508 355 508 365 L 508 392" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 617 355 L 610 359 L 612 355 L 610 352 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="66" y="715" width="194" height="94" 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">
<text x="163" y="752">
TOP_TO_IGNORE</text>
<text x="163" y="766">
on-entry:</text>
<text x="163" y="780">
start leave timeout</text>
</g>
<path d="M 301 678 C 304 674 309 672 314 672 L 352 672 C 357 672 362 674 365 678 L 387 708 C 388 709 388 711 387 713 L 365 742 C 362 746 357 748 352 748 L 314 748 C 309 748 304 746 301 742 L 279 713 C 278 711 278 709 279 708 L 301 678 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="333" y="700">
finger in</text>
<text x="333" y="714">
area or bottom</text>
</g>
<path d="M 304 769 C 307 765 311 762 316 762 L 352 762 C 357 762 361 765 364 769 L 385 799 C 386 801 386 803 385 805 L 364 835 C 361 840 357 842 352 842 L 316 842 C 311 842 307 840 304 835 L 283 805 C 282 803 282 801 283 799 L 304 769 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="334" y="785">
finger in</text>
<text x="334" y="799">
top</text>
<text x="334" y="813">
button == curr</text>
</g>
<path d="M 278 710 L 262 756" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 260 761 L 259 753 L 262 756 L 266 756 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 279 797 L 260 762" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 282 801 L 275 797 L 279 797 L 281 793 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 412 762 L 391 716" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 388 711 L 395 716 L 391 716 L 388 719 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 409 767 L 386 802" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 411 763 L 410 771 L 409 767 L 405 767 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 238 712 L 282 642" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 285 637 L 284 645 L 282 642 L 278 641 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="98" y="391" 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">
<text x="163" y="431">
IGNORE</text>
<text x="163" y="445">
on-entry:</text>
<text x="163" y="459">
curr =none</text>
</g>
<path d="M 135 541 C 138 538 142 536 146 536 L 180 536 C 184 536 188 538 191 541 L 211 564 C 211 566 211 567 211 568 L 191 591 C 188 595 184 596 180 596 L 146 596 C 142 596 138 595 135 591 L 115 568 C 114 567 114 566 115 564 L 135 541 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="163" y="563">
leave</text>
<text x="163" y="577">
timeout</text>
</g>
<path d="M 163 536 L 163 497" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 163 492 L 166 499 L 163 497 L 159 499 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 163 715 L 163 603" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 163 597 L 166 604 L 163 603 L 159 604 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 98 441 L 18 441 Q 8 441 8 431 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 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"/>
</g>
<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"/>
<path d="M 899 441 L 892 445 L 894 441 L 892 438 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<ellipse cx="785" cy="151" rx="49.5" ry="30" fill="#ccccff" stroke="#000000" stroke-width="2" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="785" y="141">NONE</text>
<text x="785" y="155">on-entry:</text>
<text x="785" y="169">curr = none</text>
</g>
<rect x="712" y="391" width="150" height="101" 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">
<text x="787" y="431">BOTTOM</text>
<text x="787" y="445">on-entry:</text>
<text x="787" y="459">curr = button</text>
</g>
<rect x="1023" y="392" 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">
<text x="1088" y="425">AREA</text>
<text x="1088" y="439">on-entry:</text>
<text x="1088" y="453">curr =area</text>
<text x="1088" y="467">set_pointer()</text>
</g>
<path d="M 921 411 C 923 408 927 405 932 405 L 965 405 C 970 405 974 408 976 411 L 996 439 C 997 440 997 442 996 444 L 976 471 C 974 475 970 477 965 477 L 932 477 C 927 477 923 475 921 471 L 901 444 C 900 442 900 440 901 439 L 921 411 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="949" y="438">finger in</text>
<text x="949" y="452">area or top</text>
</g>
<path d="M 759 7 C 762 4 766 2 770 2 L 804 2 C 808 2 812 4 815 7 L 835 30 C 836 31 836 33 835 34 L 815 57 C 812 60 808 62 804 62 L 770 62 C 766 62 762 60 759 57 L 739 34 C 739 33 739 31 739 30 L 759 7 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="787" y="29">finger</text>
<text x="787" y="43">up</text>
</g>
<path d="M 997 441 L 1016 442" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1022 442 L 1015 445 L 1016 442 L 1015 438 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 766 235 C 768 232 771 230 774 230 L 800 230 C 803 230 806 232 808 235 L 824 259 C 824 260 824 262 824 263 L 808 287 C 806 290 803 292 800 292 L 774 292 C 771 292 768 290 766 287 L 750 263 C 750 262 750 260 750 259 L 766 235 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="787" y="258">finger in</text>
<text x="787" y="272">bottom</text>
</g>
<path d="M 785 181 L 786 224" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 786 229 L 783 222 L 786 224 L 790 222 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 787 292 L 787 384" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 787 390 L 784 383 L 787 384 L 791 383 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1068 236 C 1070 233 1073 231 1076 231 L 1100 231 C 1103 231 1105 233 1107 236 L 1121 259 C 1122 261 1122 262 1121 263 L 1107 287 C 1105 290 1103 292 1100 292 L 1076 292 C 1073 292 1070 290 1068 287 L 1054 263 C 1054 262 1054 261 1054 259 L 1068 236 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="1088" y="258">finger in</text>
<text x="1088" y="272">area</text>
</g>
<path d="M 1088 292 L 1088 386" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1088 391 L 1084 384 L 1088 386 L 1091 384 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 834 151 L 1048 246" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1053 248 L 1045 249 L 1048 246 L 1048 242 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 922 563 C 925 559 930 556 934 556 L 971 556 C 975 556 980 559 983 563 L 1004 594 C 1005 595 1005 597 1004 599 L 983 630 C 980 634 975 636 971 636 L 934 636 C 930 636 925 634 922 630 L 901 599 C 900 597 900 595 901 594 L 922 563 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="952" y="586">finger in</text>
<text x="952" y="600">bottom</text>
<text x="952" y="614">button != curr</text>
</g>
<path d="M 927 558 L 872 487" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 869 483 L 876 486 L 872 487 L 870 491 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 808 492 L 895 555" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 899 558 L 891 557 L 895 555 L 895 551 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1153 442 L 1358 442 Q 1368 442 1368 432 L 1368 42 Q 1368 32 1358 32 L 842 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 837 32 L 844 29 L 842 32 L 844 36 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<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"/>
<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>
</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"/>
<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"/>
<rect x="1763" y="17" width="100" height="40" fill="none" stroke="none" pointer-events="none"/>
<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"/>
<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>
</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"/>
<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>
</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"/>
<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>
</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"/>
<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>
</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"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="611">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"/>
<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>
</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"/>
<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>
</g>
<rect x="1968" y="587" 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>
</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"/>
<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>
</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"/>
<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>
</g>
<rect x="1968" y="767" 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>
</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"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1813" y="400">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"/>
<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>
</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"/>
<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>
</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">
<text x="1813" y="971">Some touches are in right</text>
</g>
<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"/>
<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 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"/>
<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"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="2048" y="971">button = BTN_RIGHT</text>
</g>
<rect x="1733" y="1082" 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="1813" y="1106">button = BTN_LEFT</text>
</g>
<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"/>
<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"/>
<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>
</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 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"/>
<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>
</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">
<text x="1703" y="1356">buttons.click_pend = 0</text>
</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 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">
<text x="1703" y="1426">button</text>
</g>
<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"/>
<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"/>
<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>
</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"/>
<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>
<text x="477" y="269">top</text>
</g>
<path d="M 735 151 L 520 243" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 515 245 L 520 239 L 520 243 L 523 245 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="402" y="392" width="150" height="101" 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">
<text x="477" y="425">TOP_NEW</text>
<text x="477" y="439">on-entry:</text>
<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 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">
<text x="477" y="766">TOP</text>
</g>
<path d="M 542 762 L 658 762" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 524 571 C 527 568 531 566 535 566 L 569 566 C 573 566 577 568 580 571 L 600 594 C 601 596 601 597 600 598 L 580 621 C 577 625 573 626 569 626 L 535 626 C 531 626 527 625 524 621 L 504 598 C 504 597 504 596 504 594 L 524 571 Z" fill="#000000" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#FFFFFF" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="552" y="586">phys</text>
<text x="552" y="600">button</text>
<text x="552" y="614">press</text>
</g>
<path d="M 412 571 C 414 568 418 566 423 566 L 456 566 C 461 566 465 568 467 571 L 487 594 C 488 596 488 597 487 598 L 467 621 C 465 625 461 626 456 626 L 423 626 C 418 626 414 625 412 621 L 392 598 C 391 597 391 596 392 594 L 412 571 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="440" y="593">enter</text>
<text x="440" y="607">timeout</text>
</g>
<path d="M 280 563 C 283 559 288 556 292 556 L 329 556 C 333 556 338 559 341 563 L 362 594 C 363 595 363 597 362 599 L 341 630 C 338 634 333 636 329 636 L 292 636 C 288 636 283 634 280 630 L 259 599 C 258 597 258 595 259 594 L 280 563 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="310" y="586">finger in</text>
<text x="310" y="600">top</text>
<text x="310" y="614">button != curr</text>
</g>
<path d="M 477 493 L 547 562" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 551 566 L 544 563 L 547 562 L 549 558 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 477 493 L 442 561" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 440 565 L 440 558 L 442 561 L 446 561 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 465 492 L 368 557" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 364 560 L 368 554 L 368 557 L 371 559 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 344 556 L 396 494" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 399 490 L 397 497 L 396 494 L 392 493 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 440 626 L 470 703" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 472 708 L 466 703 L 470 703 L 472 700 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 552 626 L 503 704" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 501 708 L 501 700 L 503 704 L 507 704 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 427 712 L 355 641" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 351 637 L 359 640 L 355 641 L 354 645 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 636 325 C 638 321 642 319 645 319 L 675 319 C 679 319 682 321 684 325 L 702 353 C 702 354 702 356 702 357 L 684 385 C 682 389 679 391 675 391 L 645 391 C 642 391 638 389 636 385 L 618 357 C 618 356 618 354 618 353 L 636 325 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="660" y="345">finger in</text>
<text x="660" y="359">area or</text>
<text x="660" y="373">bottom</text>
</g>
<path d="M 702 355 L 1048 355 Q 1058 355 1058 365 L 1058 386" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1058 391 L 1055 384 L 1058 386 L 1062 384 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 612 355 L 518 355 Q 508 355 508 365 L 508 392" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 617 355 L 610 359 L 612 355 L 610 352 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="66" y="715" width="194" height="94" 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">
<text x="163" y="752">TOP_TO_IGNORE</text>
<text x="163" y="766">on-entry:</text>
<text x="163" y="780">start leave timeout</text>
</g>
<path d="M 301 678 C 304 674 309 672 314 672 L 352 672 C 357 672 362 674 365 678 L 387 708 C 388 709 388 711 387 713 L 365 742 C 362 746 357 748 352 748 L 314 748 C 309 748 304 746 301 742 L 279 713 C 278 711 278 709 279 708 L 301 678 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="333" y="700">finger in</text>
<text x="333" y="714">area or bottom</text>
</g>
<path d="M 304 769 C 307 765 311 762 316 762 L 352 762 C 357 762 361 765 364 769 L 385 799 C 386 801 386 803 385 805 L 364 835 C 361 840 357 842 352 842 L 316 842 C 311 842 307 840 304 835 L 283 805 C 282 803 282 801 283 799 L 304 769 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="334" y="785">finger in</text>
<text x="334" y="799">top</text>
<text x="334" y="813">button == curr</text>
</g>
<path d="M 278 710 L 262 756" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 260 761 L 259 753 L 262 756 L 266 756 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 279 797 L 260 762" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 282 801 L 275 797 L 279 797 L 281 793 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 412 762 L 391 716" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 388 711 L 395 716 L 391 716 L 388 719 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 409 767 L 386 802" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 411 763 L 410 771 L 409 767 L 405 767 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 238 712 L 282 642" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 285 637 L 284 645 L 282 642 L 278 641 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="98" y="391" 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">
<text x="163" y="431">IGNORE</text>
<text x="163" y="445">on-entry:</text>
<text x="163" y="459">curr =none</text>
</g>
<path d="M 135 541 C 138 538 142 536 146 536 L 180 536 C 184 536 188 538 191 541 L 211 564 C 211 566 211 567 211 568 L 191 591 C 188 595 184 596 180 596 L 146 596 C 142 596 138 595 135 591 L 115 568 C 114 567 114 566 115 564 L 135 541 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="163" y="563">leave</text>
<text x="163" y="577">timeout</text>
</g>
<path d="M 163 536 L 163 497" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 163 492 L 166 499 L 163 497 L 159 499 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 163 715 L 163 603" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 163 597 L 166 604 L 163 603 L 159 604 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 98 441 L 18 441 Q 8 441 8 431 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 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"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -29,8 +29,7 @@ libinput_la_SOURCES = \
libinput_la_LIBADD = $(MTDEV_LIBS) \
$(LIBUDEV_LIBS) \
$(LIBEVDEV_LIBS) \
-lm
$(LIBEVDEV_LIBS)
libinput_la_CFLAGS = -I$(top_srcdir)/include \
$(MTDEV_CFLAGS) \
$(LIBUDEV_CFLAGS) \

View file

@ -52,8 +52,6 @@ button_state_to_str(enum button_state state) {
CASE_RETURN_STRING(BUTTON_STATE_NONE);
CASE_RETURN_STRING(BUTTON_STATE_AREA);
CASE_RETURN_STRING(BUTTON_STATE_BOTTOM);
CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_NEW);
CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_TO_AREA);
CASE_RETURN_STRING(BUTTON_STATE_TOP);
CASE_RETURN_STRING(BUTTON_STATE_TOP_NEW);
CASE_RETURN_STRING(BUTTON_STATE_TOP_TO_IGNORE);
@ -161,13 +159,7 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t,
tp_set_pointer(tp, t);
break;
case BUTTON_STATE_BOTTOM:
break;
case BUTTON_STATE_BOTTOM_NEW:
t->button.curr = event;
tp_button_set_enter_timer(tp, t);
break;
case BUTTON_STATE_BOTTOM_TO_AREA:
tp_button_set_leave_timer(tp, t);
break;
case BUTTON_STATE_TOP:
break;
@ -192,7 +184,7 @@ tp_button_none_handle_event(struct tp_dispatch *tp,
switch (event) {
case BUTTON_EVENT_IN_BOTTOM_R:
case BUTTON_EVENT_IN_BOTTOM_L:
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, event);
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
break;
case BUTTON_EVENT_IN_TOP_R:
case BUTTON_EVENT_IN_TOP_M:
@ -237,92 +229,28 @@ tp_button_area_handle_event(struct tp_dispatch *tp,
static void
tp_button_bottom_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum button_event event)
struct tp_touch *t,
enum button_event event)
{
switch (event) {
case BUTTON_EVENT_IN_BOTTOM_R:
case BUTTON_EVENT_IN_BOTTOM_L:
if (event != t->button.curr)
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
event);
break;
case BUTTON_EVENT_IN_TOP_R:
case BUTTON_EVENT_IN_TOP_M:
case BUTTON_EVENT_IN_TOP_L:
case BUTTON_EVENT_IN_AREA:
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_TO_AREA, event);
break;
case BUTTON_EVENT_UP:
tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
break;
case BUTTON_EVENT_PRESS:
case BUTTON_EVENT_RELEASE:
case BUTTON_EVENT_TIMEOUT:
break;
}
}
static void
tp_button_bottom_new_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum button_event event)
{
switch(event) {
case BUTTON_EVENT_IN_BOTTOM_R:
case BUTTON_EVENT_IN_BOTTOM_L:
if (event != t->button.curr)
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
event);
break;
case BUTTON_EVENT_IN_TOP_R:
case BUTTON_EVENT_IN_TOP_M:
case BUTTON_EVENT_IN_TOP_L:
case BUTTON_EVENT_IN_AREA:
tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
break;
case BUTTON_EVENT_UP:
tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
break;
case BUTTON_EVENT_PRESS:
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
break;
case BUTTON_EVENT_RELEASE:
break;
case BUTTON_EVENT_TIMEOUT:
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
break;
}
}
static void
tp_button_bottom_to_area_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum button_event event)
{
switch(event) {
case BUTTON_EVENT_IN_BOTTOM_R:
case BUTTON_EVENT_IN_BOTTOM_L:
if (event == t->button.curr)
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM,
event);
else
tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
event);
break;
case BUTTON_EVENT_IN_TOP_R:
case BUTTON_EVENT_IN_TOP_M:
case BUTTON_EVENT_IN_TOP_L:
case BUTTON_EVENT_IN_AREA:
tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
break;
case BUTTON_EVENT_UP:
tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
break;
case BUTTON_EVENT_PRESS:
case BUTTON_EVENT_RELEASE:
break;
case BUTTON_EVENT_TIMEOUT:
tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
break;
}
}
@ -465,12 +393,6 @@ tp_button_handle_event(struct tp_dispatch *tp,
case BUTTON_STATE_BOTTOM:
tp_button_bottom_handle_event(tp, t, event);
break;
case BUTTON_STATE_BOTTOM_NEW:
tp_button_bottom_new_handle_event(tp, t, event);
break;
case BUTTON_STATE_BOTTOM_TO_AREA:
tp_button_bottom_to_area_handle_event(tp, t, event);
break;
case BUTTON_STATE_TOP:
tp_button_top_handle_event(tp, t, event);
break;
@ -581,11 +503,13 @@ tp_init_buttons(struct tp_dispatch *tp,
libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
if (tp->buttons.is_clickpad)
log_bug_kernel(libinput,
"clickpad advertising right button\n");
"%s: clickpad advertising right button\n",
device->sysname);
} else {
if (!tp->buttons.is_clickpad)
log_bug_kernel(libinput,
"non clickpad without right button?\n");
"%s: non clickpad without right button?\n",
device->sysname);
}
absinfo_x = device->abs.absinfo_x;
@ -603,11 +527,28 @@ tp_init_buttons(struct tp_dispatch *tp,
if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
int xoffset = absinfo_x->minimum,
yoffset = absinfo_y->minimum;
tp->buttons.bottom_area.top_edge = height * .8 + yoffset;
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) {
tp->buttons.top_area.bottom_edge = height * .08 + yoffset;
/* 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 {
@ -792,3 +733,9 @@ tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return t->button.state == BUTTON_STATE_AREA;
}
bool
tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t)
{
return is_inside_top_button_area(tp, t) || is_inside_bottom_button_area(tp, t);
}

View file

@ -95,12 +95,16 @@ tap_event_to_str(enum tap_event event) {
static void
tp_tap_notify(struct tp_dispatch *tp,
struct tp_touch *t,
uint64_t time,
int nfingers,
enum libinput_button_state state)
{
int32_t button;
if (t && t->tap.state == TAP_TOUCH_STATE_DEAD)
return;
switch (nfingers) {
case 1: button = BTN_LEFT; break;
case 2: button = BTN_RIGHT; break;
@ -128,7 +132,9 @@ tp_tap_clear_timer(struct tp_dispatch *tp)
}
static void
tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_idle_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
struct libinput *libinput = tp->device->base.seat->libinput;
@ -151,7 +157,9 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t
}
static void
tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_touch_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -161,7 +169,7 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_TAPPED;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_set_timer(tp, time);
break;
case TAP_EVENT_TIMEOUT:
@ -176,7 +184,9 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t
}
static void
tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_hold_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -197,7 +207,9 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t
}
static void
tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_tapped_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
struct libinput *libinput = tp->device->base.seat->libinput;
@ -213,17 +225,19 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_
break;
case TAP_EVENT_TIMEOUT:
tp->tap.state = TAP_STATE_IDLE;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
static void
tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_touch2_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -233,8 +247,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_HOLD;
tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_clear_timer(tp);
break;
case TAP_EVENT_MOTION:
@ -249,7 +263,9 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_
}
static void
tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -271,7 +287,9 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, ui
}
static void
tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_touch3_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -286,8 +304,8 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
@ -296,7 +314,9 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_
}
static void
tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -317,7 +337,9 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, ui
}
static void
tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
case TAP_EVENT_TOUCH:
@ -325,9 +347,9 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_IDLE;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_clear_timer(tp);
break;
case TAP_EVENT_MOTION:
@ -336,13 +358,15 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
static void
tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_dragging_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -359,13 +383,15 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint6
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
static void
tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -378,17 +404,19 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event,
break;
case TAP_EVENT_TIMEOUT:
tp->tap.state = TAP_STATE_IDLE;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
static void
tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_dragging2_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event, uint64_t time)
{
switch (event) {
@ -397,7 +425,7 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint
break;
case TAP_EVENT_TOUCH:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_MOTION:
case TAP_EVENT_TIMEOUT:
@ -405,13 +433,16 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
static void
tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_dead_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event,
uint64_t time)
{
switch (event) {
@ -428,55 +459,58 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t
}
static void
tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time)
tp_tap_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum tap_event event,
uint64_t time)
{
struct libinput *libinput = tp->device->base.seat->libinput;
enum tp_tap_state current;
if (!tp->tap.enabled)
return;
current = tp->tap.state;
switch(tp->tap.state) {
case TAP_STATE_IDLE:
tp_tap_idle_handle_event(tp, event, time);
if (!tp->tap.enabled)
break;
tp_tap_idle_handle_event(tp, t, event, time);
break;
case TAP_STATE_TOUCH:
tp_tap_touch_handle_event(tp, event, time);
tp_tap_touch_handle_event(tp, t, event, time);
break;
case TAP_STATE_HOLD:
tp_tap_hold_handle_event(tp, event, time);
tp_tap_hold_handle_event(tp, t, event, time);
break;
case TAP_STATE_TAPPED:
tp_tap_tapped_handle_event(tp, event, time);
tp_tap_tapped_handle_event(tp, t, event, time);
break;
case TAP_STATE_TOUCH_2:
tp_tap_touch2_handle_event(tp, event, time);
tp_tap_touch2_handle_event(tp, t, event, time);
break;
case TAP_STATE_TOUCH_2_HOLD:
tp_tap_touch2_hold_handle_event(tp, event, time);
tp_tap_touch2_hold_handle_event(tp, t, event, time);
break;
case TAP_STATE_TOUCH_3:
tp_tap_touch3_handle_event(tp, event, time);
tp_tap_touch3_handle_event(tp, t, event, time);
break;
case TAP_STATE_TOUCH_3_HOLD:
tp_tap_touch3_hold_handle_event(tp, event, time);
tp_tap_touch3_hold_handle_event(tp, t, event, time);
break;
case TAP_STATE_DRAGGING_OR_DOUBLETAP:
tp_tap_dragging_or_doubletap_handle_event(tp, event, time);
tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time);
break;
case TAP_STATE_DRAGGING:
tp_tap_dragging_handle_event(tp, event, time);
tp_tap_dragging_handle_event(tp, t, event, time);
break;
case TAP_STATE_DRAGGING_WAIT:
tp_tap_dragging_wait_handle_event(tp, event, time);
tp_tap_dragging_wait_handle_event(tp, t, event, time);
break;
case TAP_STATE_DRAGGING_2:
tp_tap_dragging2_handle_event(tp, event, time);
tp_tap_dragging2_handle_event(tp, t, event, time);
break;
case TAP_STATE_DEAD:
tp_tap_dead_handle_event(tp, event, time);
tp_tap_dead_handle_event(tp, t, event, time);
break;
}
@ -508,19 +542,34 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
int filter_motion = 0;
if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
tp_tap_handle_event(tp, TAP_EVENT_BUTTON, time);
tp_tap_handle_event(tp, NULL, TAP_EVENT_BUTTON, time);
tp_for_each_touch(tp, t) {
if (!t->dirty || t->state == TOUCH_NONE)
continue;
if (t->state == TOUCH_BEGIN)
tp_tap_handle_event(tp, TAP_EVENT_TOUCH, time);
else if (t->state == TOUCH_END)
tp_tap_handle_event(tp, TAP_EVENT_RELEASE, time);
else if (tp->tap.state != TAP_STATE_IDLE &&
tp_tap_exceeds_motion_threshold(tp, t))
tp_tap_handle_event(tp, TAP_EVENT_MOTION, time);
if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
t->tap.state = TAP_TOUCH_STATE_DEAD;
if (t->state == TOUCH_BEGIN) {
t->tap.state = TAP_TOUCH_STATE_TOUCH;
tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time);
} else if (t->state == TOUCH_END) {
tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time);
t->tap.state = TAP_TOUCH_STATE_DEAD;
} else if (tp->tap.state != TAP_STATE_IDLE &&
tp_tap_exceeds_motion_threshold(tp, t)) {
struct tp_touch *tmp;
/* Any touch exceeding the threshold turns all
* touches into DEAD */
tp_for_each_touch(tp, tmp) {
if (tmp->tap.state == TAP_TOUCH_STATE_TOUCH)
tmp->tap.state = TAP_TOUCH_STATE_DEAD;
}
tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
}
}
/**
@ -550,21 +599,87 @@ static void
tp_tap_handle_timeout(uint64_t time, void *data)
{
struct tp_dispatch *tp = data;
struct tp_touch *t;
tp_tap_handle_event(tp, TAP_EVENT_TIMEOUT, time);
tp_tap_handle_event(tp, NULL, TAP_EVENT_TIMEOUT, time);
tp_for_each_touch(tp, t) {
if (t->state == TOUCH_NONE ||
t->tap.state == TAP_TOUCH_STATE_IDLE)
continue;
t->tap.state = TAP_TOUCH_STATE_DEAD;
}
}
static int
tp_tap_config_count(struct libinput_device *device)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp;
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
return min(tp->ntouches, 3); /* we only do up to 3 finger tap */
}
static enum libinput_config_status
tp_tap_config_set_enabled(struct libinput_device *device, int enabled)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp;
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
tp->tap.enabled = enabled;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
static int
tp_tap_config_is_enabled(struct libinput_device *device)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp;
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
return tp->tap.enabled;
}
static int
tp_tap_config_get_default(struct libinput_device *device)
{
/**
* Tapping is disabled by default for two reasons:
* * if you don't know that tapping is a thing (or enabled by
* default), you get spurious mouse events that make the desktop
* feel buggy.
* * if you do know what tapping is and you want it, you
* usually know where to enable it, or at least you can search for
* it.
*/
return false;
}
int
tp_init_tap(struct tp_dispatch *tp)
{
tp->tap.config.count = tp_tap_config_count;
tp->tap.config.set_enabled = tp_tap_config_set_enabled;
tp->tap.config.get_enabled = tp_tap_config_is_enabled;
tp->tap.config.get_default = tp_tap_config_get_default;
tp->device->base.config.tap = &tp->tap.config;
tp->tap.state = TAP_STATE_IDLE;
libinput_timer_init(&tp->tap.timer,
tp->device->base.seat->libinput,
tp_tap_handle_timeout, tp);
tp->tap.enabled = 1; /* FIXME */
return 0;
}

View file

@ -25,12 +25,11 @@
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <limits.h>
#include "evdev-mt-touchpad.h"
#define DEFAULT_CONSTANT_ACCEL_NUMERATOR 100
#define DEFAULT_MIN_ACCEL_FACTOR 0.20
#define DEFAULT_MAX_ACCEL_FACTOR 0.40
#define DEFAULT_ACCEL_NUMERATOR 1200.0
#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
static inline int
@ -42,30 +41,8 @@ tp_hysteresis(int in, int center, int margin)
if (diff > margin)
return center + diff - margin;
else if (diff < -margin)
else
return center + diff + margin;
return center + diff;
}
static double
tp_accel_profile(struct motion_filter *filter,
void *data,
double velocity,
uint64_t time)
{
struct tp_dispatch *tp =
(struct tp_dispatch *) data;
double accel_factor;
accel_factor = velocity * tp->accel.constant_factor;
if (accel_factor > tp->accel.max_factor)
accel_factor = tp->accel.max_factor;
else if (accel_factor < tp->accel.min_factor)
accel_factor = tp->accel.min_factor;
return accel_factor;
}
static inline struct tp_motion *
@ -87,7 +64,8 @@ tp_filter_motion(struct tp_dispatch *tp,
motion.dx = *dx * tp->accel.x_scale_coeff;
motion.dy = *dy * tp->accel.y_scale_coeff;
filter_dispatch(tp->filter, &motion, tp, time);
if (motion.dx != 0.0 || motion.dy != 0.0)
filter_dispatch(tp->filter, &motion, tp, time);
*dx = motion.dx;
*dy = motion.dy;
@ -171,6 +149,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
t->dirty = true;
t->is_pointer = false;
t->palm.is_palm = false;
t->state = TOUCH_END;
t->pinned.is_pinned = false;
assert(tp->nfingers_down >= 1);
@ -362,6 +341,7 @@ static int
tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
!t->palm.is_palm &&
!t->pinned.is_pinned && tp_button_touch_active(tp, t);
}
@ -380,6 +360,47 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
t->is_pointer = true;
}
static void
tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
const int PALM_TIMEOUT = 200; /* ms */
const int DIRECTIONS = NE|E|SE|SW|W|NW;
/* If labelled a touch as palm, we unlabel as palm when
we move out of the palm edge zone within the timeout, provided
the direction is within 45 degrees of the horizontal.
*/
if (t->palm.is_palm) {
if (time < t->palm.time + PALM_TIMEOUT &&
(t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) {
int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y);
if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
t->palm.is_palm = false;
tp_set_pointer(tp, t);
}
}
return;
}
/* palm must start in exclusion zone, it's ok to move into
the zone without being a palm */
if (t->state != TOUCH_BEGIN ||
(t->x > tp->palm.left_edge && t->x < tp->palm.right_edge))
return;
/* don't detect palm in software button areas, it's
likely that legitimate touches start in the area
covered by the exclusion zone */
if (tp->buttons.is_clickpad &&
tp_button_is_inside_softbutton_area(tp, t))
return;
t->palm.is_palm = true;
t->palm.time = time;
t->palm.x = t->x;
t->palm.y = t->y;
}
static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
@ -392,8 +413,11 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
t->y = first->y;
if (!t->dirty)
t->dirty = first->dirty;
} else if (!t->dirty)
} else if (!t->dirty) {
continue;
}
tp_palm_detect(tp, t, time);
tp_motion_hysteresis(tp, t);
tp_motion_history_push(t);
@ -465,11 +489,11 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
tp_filter_motion(tp, &dx, &dy, time);
/* Require at least three px scrolling to start */
if (dy <= -3.0 || dy >= 3.0)
/* 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 <= -3.0 || dx >= 3.0)
if (dx <= -5.0 || dx >= 5.0)
tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
if (dy != 0.0 &&
@ -546,23 +570,23 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
if (tp_post_scroll_events(tp, time) != 0)
return;
if (t->history.count >= TOUCHPAD_MIN_SAMPLES) {
if (!t->is_pointer) {
tp_for_each_touch(tp, t) {
if (t->is_pointer)
break;
}
if (!t->is_pointer) {
tp_for_each_touch(tp, t) {
if (t->is_pointer)
break;
}
if (!t->is_pointer)
return;
tp_get_delta(t, &dx, &dy);
tp_filter_motion(tp, &dx, &dy, time);
if (dx != 0.0 || dy != 0.0)
pointer_notify_motion(&tp->device->base, time, dx, dy);
}
if (!t->is_pointer ||
!t->dirty ||
t->history.count < TOUCHPAD_MIN_SAMPLES)
return;
tp_get_delta(t, &dx, &dy);
tp_filter_motion(tp, &dx, &dy, time);
if (dx != 0.0 || dy != 0.0)
pointer_notify_motion(&tp->device->base, time, dx, dy);
}
static void
@ -601,7 +625,7 @@ tp_destroy(struct evdev_dispatch *dispatch)
tp_destroy_tap(tp);
tp_destroy_buttons(tp);
motion_filter_destroy(tp->filter);
filter_destroy(tp->filter);
free(tp->touches);
free(tp);
}
@ -666,9 +690,10 @@ tp_init_slots(struct tp_dispatch *tp,
return 0;
}
static void
calculate_scale_coefficients(struct tp_dispatch *tp)
static int
tp_init_accel(struct tp_dispatch *tp, double diagonal)
{
struct motion_filter *accel;
int res_x, res_y;
if (tp->has_mt) {
@ -683,35 +708,34 @@ calculate_scale_coefficients(struct tp_dispatch *tp)
ABS_Y);
}
if (res_x <= 0 || res_y <= 0) {
tp->accel.x_scale_coeff = 1.0;
tp->accel.y_scale_coeff = 1.0;
} else if (res_x > res_y) {
tp->accel.x_scale_coeff = res_y / (double) res_x;
tp->accel.y_scale_coeff = 1.0f;
/*
* Not all touchpads report the same amount of units/mm (resolution).
* Normalize motion events to a resolution of 15.74 units/mm
* (== 400 dpi) as base (unaccelerated) speed. This also evens out any
* differences in x and y resolution, so that a circle on the
* touchpad does not turn into an elipse on the screen.
*
* We pick 400dpi as thats one of the many default resolutions
* for USB mice, so we end up with a similar base speed on the device.
*/
if (res_x > 1 && res_y > 1) {
tp->accel.x_scale_coeff = (400/25.4) / res_x;
tp->accel.y_scale_coeff = (400/25.4) / res_y;
} else {
tp->accel.y_scale_coeff = res_x / (double) res_y;
tp->accel.x_scale_coeff = 1.0f;
/*
* For touchpads where the driver does not provide resolution, fall
* back to scaling motion events based on the diagonal size in units.
*/
tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
}
}
static int
tp_init_accel(struct tp_dispatch *touchpad, double diagonal)
{
struct motion_filter *accel;
calculate_scale_coefficients(touchpad);
touchpad->accel.constant_factor =
DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR;
touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR;
accel = create_pointer_accelator_filter(tp_accel_profile);
accel = create_pointer_accelator_filter(
pointer_accel_profile_smooth_simple);
if (accel == NULL)
return -1;
touchpad->filter = accel;
tp->filter = accel;
return 0;
}
@ -724,6 +748,35 @@ tp_init_scroll(struct tp_dispatch *tp)
return 0;
}
static int
tp_init_palmdetect(struct tp_dispatch *tp,
struct evdev_device *device)
{
int width;
/* 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) {
tp->palm.right_edge = INT_MAX;
tp->palm.left_edge = INT_MIN;
return 0;
}
/* palm edges are 5% of the width on each side */
tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
return 0;
}
static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
@ -760,6 +813,9 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_buttons(tp, device) != 0)
return -1;
if (tp_init_palmdetect(tp, device) != 0)
return -1;
return 0;
}

View file

@ -64,8 +64,6 @@ enum button_state {
BUTTON_STATE_NONE,
BUTTON_STATE_AREA,
BUTTON_STATE_BOTTOM,
BUTTON_STATE_BOTTOM_NEW,
BUTTON_STATE_BOTTOM_TO_AREA,
BUTTON_STATE_TOP,
BUTTON_STATE_TOP_NEW,
BUTTON_STATE_TOP_TO_IGNORE,
@ -88,6 +86,12 @@ enum tp_tap_state {
TAP_STATE_DEAD, /**< finger count exceeded */
};
enum tp_tap_touch_state {
TAP_TOUCH_STATE_IDLE = 16, /**< not in touch */
TAP_TOUCH_STATE_TOUCH, /**< touching, may tap */
TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */
};
struct tp_motion {
int32_t x;
int32_t y;
@ -131,6 +135,16 @@ struct tp_touch {
enum button_event curr;
struct libinput_timer timer;
} button;
struct {
enum tp_tap_touch_state state;
} tap;
struct {
bool is_palm;
int32_t x, y; /* first coordinates if is_palm == true */
uint32_t time; /* first timestamp if is_palm == true */
} palm;
};
struct tp_dispatch {
@ -152,10 +166,6 @@ struct tp_dispatch {
struct motion_filter *filter;
struct {
double constant_factor;
double min_factor;
double max_factor;
double x_scale_coeff;
double y_scale_coeff;
} accel;
@ -193,10 +203,16 @@ struct tp_dispatch {
enum touchpad_event queued;
struct {
struct libinput_device_config_tap config;
bool enabled;
struct libinput_timer timer;
enum tp_tap_state state;
} tap;
struct {
int32_t right_edge;
int32_t left_edge;
} palm;
};
#define tp_for_each_touch(_tp, _t) \
@ -237,4 +253,7 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time);
int
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);
#endif

View file

@ -866,6 +866,24 @@ evdev_device_get_sysname(struct evdev_device *device)
return device->sysname;
}
const char *
evdev_device_get_name(struct evdev_device *device)
{
return device->devname;
}
unsigned int
evdev_device_get_id_product(struct evdev_device *device)
{
return libevdev_get_id_product(device->evdev);
}
unsigned int
evdev_device_get_id_vendor(struct evdev_device *device)
{
return libevdev_get_id_vendor(device->evdev);
}
void
evdev_device_calibrate(struct evdev_device *device, float calibration[6])
{
@ -936,7 +954,7 @@ evdev_device_destroy(struct evdev_device *device)
if (dispatch)
dispatch->interface->destroy(dispatch);
motion_filter_destroy(device->pointer.filter);
filter_destroy(device->pointer.filter);
libinput_seat_unref(device->base.seat);
libevdev_free(device->evdev);
free(device->mt.slots);

View file

@ -145,6 +145,15 @@ evdev_device_get_output(struct evdev_device *device);
const char *
evdev_device_get_sysname(struct evdev_device *device);
const char *
evdev_device_get_name(struct evdev_device *device);
unsigned int
evdev_device_get_id_product(struct evdev_device *device);
unsigned int
evdev_device_get_id_vendor(struct evdev_device *device);
void
evdev_device_calibrate(struct evdev_device *device, float calibration[6]);

View file

@ -29,6 +29,7 @@
#include <math.h>
#include "filter.h"
#include "libinput-util.h"
void
filter_dispatch(struct motion_filter *filter,
@ -38,26 +39,34 @@ filter_dispatch(struct motion_filter *filter,
filter->interface->filter(filter, motion, data, time);
}
void
filter_destroy(struct motion_filter *filter)
{
if (!filter)
return;
filter->interface->destroy(filter);
}
/*
* Default parameters for pointer acceleration profiles.
*/
#define DEFAULT_CONSTANT_ACCELERATION 10.0
#define DEFAULT_THRESHOLD 4.0
#define DEFAULT_ACCELERATION 2.0
#define DEFAULT_THRESHOLD 0.4 /* in units/ms */
#define DEFAULT_ACCELERATION 2.0 /* unitless factor */
/*
* Pointer acceleration filter constants
*/
#define MAX_VELOCITY_DIFF 1.0
#define MAX_VELOCITY_DIFF 1.0 /* units/ms */
#define MOTION_TIMEOUT 300 /* (ms) */
#define NUM_POINTER_TRACKERS 16
struct pointer_tracker {
double dx;
double dy;
uint64_t time;
double dx; /* delta to most recent event, in device units */
double dy; /* delta to most recent event, in device units */
uint64_t time; /* ms */
int dir;
};
@ -67,72 +76,15 @@ struct pointer_accelerator {
accel_profile_func_t profile;
double velocity;
double last_velocity;
int last_dx;
int last_dy;
double velocity; /* units/ms */
double last_velocity; /* units/ms */
int last_dx; /* device units */
int last_dy; /* device units */
struct pointer_tracker *trackers;
int cur_tracker;
};
enum directions {
N = 1 << 0,
NE = 1 << 1,
E = 1 << 2,
SE = 1 << 3,
S = 1 << 4,
SW = 1 << 5,
W = 1 << 6,
NW = 1 << 7,
UNDEFINED_DIRECTION = 0xff
};
static int
get_direction(int dx, int dy)
{
int dir = UNDEFINED_DIRECTION;
int d1, d2;
double r;
if (abs(dx) < 2 && abs(dy) < 2) {
if (dx > 0 && dy > 0)
dir = S | SE | E;
else if (dx > 0 && dy < 0)
dir = N | NE | E;
else if (dx < 0 && dy > 0)
dir = S | SW | W;
else if (dx < 0 && dy < 0)
dir = N | NW | W;
else if (dx > 0)
dir = NE | E | SE;
else if (dx < 0)
dir = NW | W | SW;
else if (dy > 0)
dir = SE | S | SW;
else if (dy < 0)
dir = NE | N | NW;
} else {
/* Calculate r within the interval [0 to 8)
*
* r = [0 .. 2π] where 0 is North
* d_f = r / 2π ([0 .. 1))
* d_8 = 8 * d_f
*/
r = atan2(dy, dx);
r = fmod(r + 2.5*M_PI, 2*M_PI);
r *= 4*M_1_PI;
/* Mark one or two close enough octants */
d1 = (int)(r + 0.9) % 8;
d2 = (int)(r + 0.1) % 8;
dir = (1 << d1) | (1 << d2);
}
return dir;
}
static void
feed_trackers(struct pointer_accelerator *accel,
double dx, double dy,
@ -152,7 +104,7 @@ feed_trackers(struct pointer_accelerator *accel,
trackers[current].dx = 0.0;
trackers[current].dy = 0.0;
trackers[current].time = time;
trackers[current].dir = get_direction(dx, dy);
trackers[current].dir = vector_get_direction(dx, dy);
}
static struct pointer_tracker *
@ -174,7 +126,7 @@ calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time)
dx = tracker->dx;
dy = tracker->dy;
distance = sqrt(dx*dx + dy*dy);
return distance / (double)(time - tracker->time);
return distance / (double)(time - tracker->time); /* units/ms */
}
static double
@ -218,7 +170,7 @@ calculate_velocity(struct pointer_accelerator *accel, uint64_t time)
}
}
return result;
return result; /* units/ms */
}
static double
@ -245,28 +197,7 @@ calculate_acceleration(struct pointer_accelerator *accel,
factor = factor / 6.0;
return factor;
}
static double
soften_delta(double last_delta, double delta)
{
if (delta < -1.0 || delta > 1.0) {
if (delta > last_delta)
return delta - 0.5;
else if (delta < last_delta)
return delta + 0.5;
}
return delta;
}
static void
apply_softening(struct pointer_accelerator *accel,
struct motion_params *motion)
{
motion->dx = soften_delta(accel->last_dx, motion->dx);
motion->dy = soften_delta(accel->last_dy, motion->dy);
return factor; /* unitless factor */
}
static void
@ -276,8 +207,8 @@ accelerator_filter(struct motion_filter *filter,
{
struct pointer_accelerator *accel =
(struct pointer_accelerator *) filter;
double velocity;
double accel_value;
double velocity; /* units/ms */
double accel_value; /* unitless factor */
feed_trackers(accel, motion->dx, motion->dy, time);
velocity = calculate_velocity(accel, time);
@ -286,8 +217,6 @@ accelerator_filter(struct motion_filter *filter,
motion->dx = accel_value * motion->dx;
motion->dy = accel_value * motion->dy;
apply_softening(accel, motion);
accel->last_dx = motion->dx;
accel->last_dy = motion->dy;
@ -332,15 +261,6 @@ create_pointer_accelator_filter(accel_profile_func_t profile)
return &filter->base;
}
void
motion_filter_destroy(struct motion_filter *filter)
{
if (!filter)
return;
filter->interface->destroy(filter);
}
static inline double
calc_penumbral_gradient(double x)
{
@ -352,27 +272,39 @@ calc_penumbral_gradient(double x)
double
pointer_accel_profile_smooth_simple(struct motion_filter *filter,
void *data,
double velocity,
double velocity, /* units/ms */
uint64_t time)
{
double threshold = DEFAULT_THRESHOLD;
double accel = DEFAULT_ACCELERATION;
double smooth_accel_coefficient;
double threshold = DEFAULT_THRESHOLD; /* units/ms */
double accel = DEFAULT_ACCELERATION; /* unitless factor */
double smooth_accel_coefficient; /* unitless factor */
double factor; /* unitless factor */
velocity *= DEFAULT_CONSTANT_ACCELERATION;
if (threshold < 0.1)
threshold = 0.1;
if (accel < 1.0)
accel = 1.0;
/* We use units/ms as velocity but it has no real meaning unless all
devices have the same resolution. For touchpads, we normalize to
400dpi (15.75 units/mm), but the resolution on USB mice is all
over the place. Though most mice these days have either 400
dpi (15.75 units/mm), 800 dpi or 1000dpi, excluding gaming mice
that can usually adjust it on the fly anyway and currently go up
to 8200dpi.
*/
if (velocity < (threshold / 2.0))
return calc_penumbral_gradient(0.5 + velocity / threshold) * 2.0 - 1.0;
if (velocity < 1.0)
return calc_penumbral_gradient(0.5 + velocity * 0.5) * 2.0 - 1.0;
if (threshold < 1.0)
threshold = 1.0;
if (velocity <= threshold)
return 1;
velocity /= threshold;
if (velocity >= accel) {
return 1.0;
factor = velocity/threshold;
if (factor >= accel)
return accel;
} else {
smooth_accel_coefficient =
calc_penumbral_gradient(velocity / accel);
return 1.0 + (smooth_accel_coefficient * (accel - 1.0));
}
/* factor is between 1.0 and accel, scale this to 0.0 - 1.0 */
factor = (factor - 1.0) / (accel - 1.0);
smooth_accel_coefficient = calc_penumbral_gradient(factor);
return 1.0 + (smooth_accel_coefficient * (accel - 1.0));
}

View file

@ -25,8 +25,10 @@
#include "config.h"
#include <stdint.h>
struct motion_params {
double dx, dy;
double dx, dy; /* in units/ms @ 400dpi */
};
struct motion_filter;
@ -35,6 +37,8 @@ void
filter_dispatch(struct motion_filter *filter,
struct motion_params *motion,
void *data, uint64_t time);
void
filter_destroy(struct motion_filter *filter);
struct motion_filter_interface {
@ -59,8 +63,6 @@ typedef double (*accel_profile_func_t)(struct motion_filter *filter,
struct motion_filter *
create_pointer_accelator_filter(accel_profile_func_t filter);
void
motion_filter_destroy(struct motion_filter *filter);
/*
* Pointer acceleration profiles.

View file

@ -83,12 +83,25 @@ struct libinput_seat {
uint32_t button_count[KEY_CNT];
};
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);
};
struct libinput_device_config {
struct libinput_device_config_tap *tap;
};
struct libinput_device {
struct libinput_seat *seat;
struct list link;
void *user_data;
int terminated;
int refcount;
struct libinput_device_config config;
};
struct libinput_tool {

View file

@ -24,6 +24,7 @@
#define LIBINPUT_UTIL_H
#include <unistd.h>
#include <math.h>
#include "libinput.h"
@ -116,4 +117,61 @@ msleep(unsigned int ms)
usleep(ms * 1000);
}
enum directions {
N = 1 << 0,
NE = 1 << 1,
E = 1 << 2,
SE = 1 << 3,
S = 1 << 4,
SW = 1 << 5,
W = 1 << 6,
NW = 1 << 7,
UNDEFINED_DIRECTION = 0xff
};
static inline int
vector_get_direction(int dx, int dy)
{
int dir = UNDEFINED_DIRECTION;
int d1, d2;
double r;
if (abs(dx) < 2 && abs(dy) < 2) {
if (dx > 0 && dy > 0)
dir = S | SE | E;
else if (dx > 0 && dy < 0)
dir = N | NE | E;
else if (dx < 0 && dy > 0)
dir = S | SW | W;
else if (dx < 0 && dy < 0)
dir = N | NW | W;
else if (dx > 0)
dir = NE | E | SE;
else if (dx < 0)
dir = NW | W | SW;
else if (dy > 0)
dir = SE | S | SW;
else if (dy < 0)
dir = NE | N | NW;
} else {
/* Calculate r within the interval [0 to 8)
*
* r = [0 .. 2π] where 0 is North
* d_f = r / 2π ([0 .. 1))
* d_8 = 8 * d_f
*/
r = atan2(dy, dx);
r = fmod(r + 2.5*M_PI, 2*M_PI);
r *= 4*M_1_PI;
/* Mark one or two close enough octants */
d1 = (int)(r + 0.9) % 8;
d2 = (int)(r + 0.1) % 8;
dir = (1 << d1) | (1 << d2);
}
return dir;
}
#endif /* LIBINPUT_UTIL_H */

View file

@ -1446,6 +1446,24 @@ libinput_device_get_sysname(struct libinput_device *device)
return evdev_device_get_sysname((struct evdev_device *) device);
}
LIBINPUT_EXPORT const char *
libinput_device_get_name(struct libinput_device *device)
{
return evdev_device_get_name((struct evdev_device *) device);
}
LIBINPUT_EXPORT unsigned int
libinput_device_get_id_product(struct libinput_device *device)
{
return evdev_device_get_id_product((struct evdev_device *) device);
}
LIBINPUT_EXPORT unsigned int
libinput_device_get_id_vendor(struct libinput_device *device)
{
return evdev_device_get_id_vendor((struct evdev_device *) device);
}
LIBINPUT_EXPORT const char *
libinput_device_get_output_name(struct libinput_device *device)
{
@ -1522,3 +1540,58 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event)
{
return &event->base;
}
LIBINPUT_EXPORT const char *
libinput_config_status_to_str(enum libinput_config_status status)
{
const char *str = NULL;
switch(status) {
case LIBINPUT_CONFIG_STATUS_SUCCESS:
str = "Success";
break;
case LIBINPUT_CONFIG_STATUS_UNSUPPORTED:
str = "Unsupported configuration option";
break;
case LIBINPUT_CONFIG_STATUS_INVALID:
str = "Invalid argument range";
break;
}
return str;
}
LIBINPUT_EXPORT int
libinput_device_config_tap_get_finger_count(struct libinput_device *device)
{
return device->config.tap ? device->config.tap->count(device) : 0;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_tap_set_enabled(struct libinput_device *device,
int enable)
{
if (enable &&
libinput_device_config_tap_get_finger_count(device) == 0)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.tap->set_enabled(device, enable);
}
LIBINPUT_EXPORT int
libinput_device_config_tap_get_enabled(struct libinput_device *device)
{
if (libinput_device_config_tap_get_finger_count(device) == 0)
return 0;
return device->config.tap->get_enabled(device);
}
LIBINPUT_EXPORT int
libinput_device_config_tap_get_default_enabled(struct libinput_device *device)
{
if (libinput_device_config_tap_get_finger_count(device) == 0)
return 0;
return device->config.tap->get_default(device);
}

View file

@ -541,7 +541,7 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event);
*
* Return the current absolute x coordinate of the pointer event, in mm from
* the top left corner of the device. To get the corresponding output screen
* coordinate, use libinput_event_pointer_get_x_transformed().
* coordinate, use libinput_event_pointer_get_absolute_x_transformed().
*
* For pointer events that are not of type
* LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, this function returns 0.
@ -559,7 +559,7 @@ libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event);
*
* Return the current absolute y coordinate of the pointer event, in mm from
* the top left corner of the device. To get the corresponding output screen
* coordinate, use libinput_event_pointer_get_x_transformed().
* coordinate, use libinput_event_pointer_get_absolute_y_transformed().
*
* For pointer events that are not of type
* LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, this function returns 0.
@ -1102,7 +1102,7 @@ libinput_udev_create_context(const struct libinput_interface *interface,
*/
int
libinput_udev_assign_seat(struct libinput *libinput,
const char *seat_id);
const char *seat_id);
/**
* @ingroup base
@ -1535,12 +1535,53 @@ libinput_device_get_user_data(struct libinput_device *device);
*
* Get the system name of the device.
*
* To get the descriptive device name, use libinput_device_get_name().
*
* @param device A previously obtained device
* @return System name of the device
*
*/
const char *
libinput_device_get_sysname(struct libinput_device *device);
/**
* @ingroup device
*
* The descriptive device name as advertised by the kernel and/or the
* hardware itself. To get the sysname for this device, use
* libinput_device_get_sysname().
*
* The lifetime of the returned string is tied to the struct
* libinput_device. The string may be the empty string but is never NULL.
*
* @param device A previously obtained device
* @return The device name
*/
const char *
libinput_device_get_name(struct libinput_device *device);
/**
* @ingroup device
*
* Get the product ID for this device.
*
* @param device A previously obtained device
* @return The product ID of this device
*/
unsigned int
libinput_device_get_id_product(struct libinput_device *device);
/**
* @ingroup device
*
* Get the vendor ID for this device.
*
* @param device A previously obtained device
* @return The vendor ID of this device
*/
unsigned int
libinput_device_get_id_vendor(struct libinput_device *device);
/**
* @ingroup device
*
@ -1648,8 +1689,113 @@ libinput_device_get_size(struct libinput_device *device,
double *width,
double *height);
/**
* @defgroup config Device configuration
*
* Enable, disable, change and/or check for device-specific features. For
* all features, libinput assigns a default based on the hardware
* configuration. This default can be obtained with the respective
* get_default call.
*
* Some configuration option may be dependent on or mutually exclusive with
* with other options. The behavior in those cases is
* implementation-defined, the caller must ensure that the options are set
* in the right order.
*/
enum libinput_config_status {
LIBINPUT_CONFIG_STATUS_SUCCESS = 0, /**< Config applied successfully */
LIBINPUT_CONFIG_STATUS_UNSUPPORTED, /**< Configuration not available on
this device */
LIBINPUT_CONFIG_STATUS_INVALID, /**< Invalid parameter range */
};
/**
* @ingroup config Device configuration
*
* Return a string describing the error.
*
* @param status The status to translate to a string
* @return A human-readable string representing the error or NULL for an
* invalid status.
*/
const char *
libinput_config_status_to_str(enum libinput_config_status status);
/**
* @ingroup config
*
* Check if the device supports tap-to-click. See
* libinput_device_config_tap_set_enabled() for more information.
*
* @param device The device to configure
* @return The number of fingers that can generate a tap event, or 0 if the
* device does not support tapping.
*
* @see libinput_device_config_tap_set_enabled
* @see libinput_device_config_tap_get_enabled
* @see libinput_device_config_tap_set_enabled_get_default
*/
int
libinput_device_config_tap_get_finger_count(struct libinput_device *device);
/**
* @ingroup config
*
* Enable or disable tap-to-click on this device, with a default mapping of
* 1, 2, 3 finger tap mapping to left, right, middle click, respectively.
* Tapping is limited by the number of simultaneous touches
* supported by the device, see
* libinput_device_config_tap_get_finger_count().
*
* @param device The device to configure
* @param enable Non-zero to enable, zero to disable
*
* @return A config status code. Disabling tapping on a device that does not
* support tapping always succeeds.
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_get_enabled
* @see libinput_device_config_tap_get_default_enabled
*/
enum libinput_config_status
libinput_device_config_tap_set_enabled(struct libinput_device *device,
int enable);
/**
* @ingroup config
*
* Check if tap-to-click is enabled on this device. If the device does not
* support tapping, this function always returns 0.
*
* @param device The device to configure
*
* @return 1 if enabled, 0 otherwise.
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_set_enabled
* @see libinput_device_config_tap_get_default_enabled
*/
int
libinput_device_config_tap_get_enabled(struct libinput_device *device);
/**
* @ingroup config
*
* 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
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_set_enabled
* @see libinput_device_config_tap_get_enabled
*/
int
libinput_device_config_tap_get_default_enabled(struct libinput_device *device);
#ifdef __cplusplus
}
#endif
#endif /* LIBINPUT_H */

View file

@ -10,5 +10,5 @@ Description: Input device library
Version: @LIBINPUT_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -linput
Libs.private: -lm
Libs.private: -lm -lrt
Requires.private: libudev

View file

@ -45,7 +45,7 @@ libinput_timer_arm_timer_fd(struct libinput *libinput)
{
int r;
struct libinput_timer *timer;
struct itimerspec its = { { 0 }, { 0 } };
struct itimerspec its = { { 0, 0 }, { 0, 0 } };
uint64_t earliest_expire = UINT64_MAX;
list_for_each(timer, &libinput->timer.list, link) {

View file

@ -2,16 +2,17 @@ if BUILD_TESTS
AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_srcdir)/src \
$(CHECK_CFLAGS) \
$(LIBEVDEV_CFLAGS)
$(LIBEVDEV_CFLAGS) \
$(LIBUDEV_CFLAGS)
AM_CFLAGS = $(GCC_CFLAGS)
AM_CXXFLAGS = $(GCC_CXXFLAGS)
TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la -lm
TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la
noinst_LTLIBRARIES = liblitest.la
liblitest_la_SOURCES = \
$(top_srcdir)/src/libinput-util.h \
$(top_srcdir)/src/libinput-util.c \
../src/libinput-util.h \
../src/libinput-util.c \
litest.h \
litest-int.h \
litest-bcm5974.c \

View file

@ -41,7 +41,7 @@ START_TEST(keyboard_seat_key_count)
libinput = litest_create_context();
for (i = 0; i < num_devices; ++i) {
sprintf(device_name, "Generic keyboard (%d)", i);
sprintf(device_name, "litest Generic keyboard (%d)", i);
devices[i] = litest_add_device_with_overrides(libinput,
LITEST_KEYBOARD,
device_name,

View file

@ -101,7 +101,7 @@ struct litest_device_interface {
};
void litest_set_current_device(struct litest_device *device);
int litest_scale(const struct litest_device *d, unsigned int axis, int val);
int litest_scale(const struct litest_device *d, unsigned int axis, double val);
void litest_generic_device_teardown(void);
#endif

View file

@ -91,8 +91,8 @@ static struct input_absinfo absinfo[] = {
{ 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, 1024, 5112, 0, 0, 75 },
{ ABS_MT_POSITION_Y, 2024, 4832, 0, 0, 129 },
{ ABS_MT_POSITION_X, 1024, 5112, 0, 0, 42 },
{ ABS_MT_POSITION_Y, 2024, 4832, 0, 0, 42 },
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
{ ABS_MT_PRESSURE, 0, 255, 0, 0, 0 },
{ .value = -1 }

View file

@ -365,7 +365,7 @@ merge_absinfo(const struct input_absinfo *orig,
const struct input_absinfo *override)
{
struct input_absinfo *abs;
int nelem, i;
unsigned int nelem, i;
size_t sz = ABS_MAX + 1;
if (!orig)
@ -399,7 +399,7 @@ static int*
merge_events(const int *orig, const int *override)
{
int *events;
int nelem, i;
unsigned int nelem, i;
size_t sz = KEY_MAX * 3;
if (!orig)
@ -596,13 +596,14 @@ void
litest_event(struct litest_device *d, unsigned int type,
unsigned int code, int value)
{
libevdev_uinput_write_event(d->uinput, type, code, value);
int ret = libevdev_uinput_write_event(d->uinput, type, code, value);
ck_assert_int_eq(ret, 0);
}
static int
auto_assign_value(struct litest_device *d,
const struct input_event *ev,
int slot, int x, int y)
int slot, double x, double y)
{
static int tracking_id;
int value = ev->value;
@ -632,7 +633,8 @@ auto_assign_value(struct litest_device *d,
void
litest_touch_down(struct litest_device *d, unsigned int slot, int x, int y)
litest_touch_down(struct litest_device *d, unsigned int slot,
double x, double y)
{
struct input_event *ev;
@ -676,7 +678,8 @@ litest_touch_up(struct litest_device *d, unsigned int slot)
}
void
litest_touch_move(struct litest_device *d, unsigned int slot, int x, int y)
litest_touch_move(struct litest_device *d, unsigned int slot,
double x, double y)
{
struct input_event *ev;
@ -696,8 +699,8 @@ litest_touch_move(struct litest_device *d, unsigned int slot, int x, int y)
void
litest_touch_move_to(struct litest_device *d,
unsigned int slot,
int x_from, int y_from,
int x_to, int y_to,
double x_from, double y_from,
double x_to, double y_to,
int steps)
{
for (int i = 0; i < steps - 1; i++)
@ -816,7 +819,8 @@ litest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press)
litest_button_click(d, key, is_press);
}
int litest_scale(const struct litest_device *d, unsigned int axis, int val)
int
litest_scale(const struct litest_device *d, unsigned int axis, double val)
{
int min, max;
ck_assert_int_ge(val, 0);
@ -904,13 +908,14 @@ litest_assert_empty_queue(struct libinput *li)
struct libevdev_uinput *
litest_create_uinput_device_from_description(const char *name,
const struct input_id *id,
const struct input_absinfo *abs,
const struct input_absinfo *abs_info,
const int *events)
{
struct libevdev_uinput *uinput;
struct libevdev *dev;
int type, code;
int rc;
int rc, fd;
const struct input_absinfo *abs;
const struct input_absinfo default_abs = {
.value = 0,
.minimum = 0,
@ -920,6 +925,7 @@ litest_create_uinput_device_from_description(const char *name,
.resolution = 100
};
char buf[512];
const char *devnode;
dev = libevdev_new();
ck_assert(dev != NULL);
@ -932,6 +938,7 @@ litest_create_uinput_device_from_description(const char *name,
libevdev_set_id_product(dev, id->product);
}
abs = abs_info;
while (abs && abs->value != -1) {
rc = libevdev_enable_event_code(dev, EV_ABS,
abs->value, abs);
@ -960,6 +967,31 @@ litest_create_uinput_device_from_description(const char *name,
libevdev_free(dev);
/* uinput does not yet support setting the resolution, so we set it
* afterwards. This is of course racy as hell but the way we
* _generally_ use this function by the time libinput uses the
* device, we're finished here */
devnode = libevdev_uinput_get_devnode(uinput);
ck_assert_notnull(devnode);
fd = open(devnode, O_RDONLY);
ck_assert_int_gt(fd, -1);
rc = libevdev_new_from_fd(fd, &dev);
ck_assert_int_eq(rc, 0);
abs = abs_info;
while (abs && abs->value != -1) {
if (abs->resolution != 0) {
rc = libevdev_kernel_set_abs_info(dev,
abs->value,
abs);
ck_assert_int_eq(rc, 0);
}
abs++;
}
close(fd);
libevdev_free(dev);
return uinput;
}

View file

@ -119,16 +119,16 @@ void litest_event(struct litest_device *t,
void litest_touch_up(struct litest_device *d, unsigned int slot);
void litest_touch_move(struct litest_device *d,
unsigned int slot,
int x,
int y);
double x,
double y);
void litest_touch_down(struct litest_device *d,
unsigned int slot,
int x,
int y);
double x,
double y);
void litest_touch_move_to(struct litest_device *d,
unsigned int slot,
int x_from, int y_from,
int x_to, int y_to,
double x_from, double y_from,
double x_to, double y_to,
int steps);
void litest_tablet_proximity_in(struct litest_device *d,
int x, int y,

View file

@ -26,6 +26,7 @@
#include <errno.h>
#include <fcntl.h>
#include <libinput.h>
#include <libinput-util.h>
#include <unistd.h>
#include "litest.h"
@ -95,7 +96,7 @@ START_TEST(event_conversion_device_notify)
struct libinput_event *event;
int device_added = 0, device_removed = 0;
uinput = create_simple_test_device("test device",
uinput = create_simple_test_device("litest test device",
EV_REL, REL_X,
EV_REL, REL_Y,
EV_KEY, BTN_LEFT,
@ -149,7 +150,7 @@ START_TEST(event_conversion_pointer)
struct libinput_event *event;
int motion = 0, button = 0;
uinput = create_simple_test_device("test device",
uinput = create_simple_test_device("litest test device",
EV_REL, REL_X,
EV_REL, REL_Y,
EV_KEY, BTN_LEFT,
@ -210,7 +211,7 @@ START_TEST(event_conversion_pointer_abs)
struct libinput_event *event;
int motion = 0, button = 0;
uinput = create_simple_test_device("test device",
uinput = create_simple_test_device("litest test device",
EV_ABS, ABS_X,
EV_ABS, ABS_Y,
EV_KEY, BTN_LEFT,
@ -270,7 +271,7 @@ START_TEST(event_conversion_key)
struct libinput_event *event;
int key = 0;
uinput = create_simple_test_device("test device",
uinput = create_simple_test_device("litest test device",
EV_KEY, KEY_A,
EV_KEY, KEY_B,
-1, -1);
@ -319,7 +320,7 @@ START_TEST(event_conversion_touch)
struct libinput_event *event;
int touch = 0;
uinput = create_simple_test_device("test device",
uinput = create_simple_test_device("litest test device",
EV_KEY, BTN_TOUCH,
EV_ABS, ABS_X,
EV_ABS, ABS_Y,
@ -428,6 +429,46 @@ START_TEST(context_ref_counting)
}
END_TEST
START_TEST(device_ids)
{
struct litest_device *dev = litest_current_device();
const char *name;
unsigned int pid, vid;
name = libevdev_get_name(dev->evdev);
pid = libevdev_get_id_product(dev->evdev);
vid = libevdev_get_id_vendor(dev->evdev);
ck_assert_str_eq(name,
libinput_device_get_name(dev->libinput_device));
ck_assert_int_eq(pid,
libinput_device_get_id_product(dev->libinput_device));
ck_assert_int_eq(vid,
libinput_device_get_id_vendor(dev->libinput_device));
}
END_TEST
START_TEST(config_status_string)
{
const char *strs[3];
const char *invalid;
size_t i, j;
strs[0] = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_SUCCESS);
strs[1] = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
strs[2] = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_INVALID);
for (i = 0; i < ARRAY_LENGTH(strs) - 1; i++)
for (j = i + 1; j < ARRAY_LENGTH(strs); j++)
ck_assert_str_ne(strs[i], strs[j]);
invalid = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_INVALID + 1);
ck_assert(invalid == NULL);
invalid = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_SUCCESS - 1);
ck_assert(invalid == NULL);
}
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);
@ -436,6 +477,8 @@ int main (int argc, char **argv) {
litest_add_no_device("events:conversion", event_conversion_touch);
litest_add_no_device("bitfield_helpers", bitfield_helpers);
litest_add_no_device("context:refcount", context_ref_counting);
litest_add("device:id", device_ids, LITEST_ANY, LITEST_ANY);
litest_add_no_device("config:status string", config_status_string);
return litest_run(argc, argv);
}

View file

@ -63,7 +63,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy)
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
expected_length = sqrt(dx*dx + dy*dy);
expected_length = sqrt(4 * dx*dx + 4 * dy*dy);
expected_dir = atan2(dx, dy);
ev_dx = libinput_event_pointer_get_dx(ptrev);
@ -72,7 +72,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy)
actual_dir = atan2(ev_dx, ev_dy);
/* Check the length of the motion vector (tolerate 1.0 indifference). */
ck_assert(fabs(expected_length - actual_length) < 1.0);
ck_assert(fabs(expected_length) >= actual_length);
/* Check the direction of the motion vector (tolerate 2π/4 radians
* indifference). */
@ -102,7 +102,7 @@ START_TEST(pointer_motion_relative)
END_TEST
static void
test_button_event(struct litest_device *dev, int button, int state)
test_button_event(struct litest_device *dev, unsigned int button, int state)
{
struct libinput *li = dev->libinput;
struct libinput_event *event;
@ -223,7 +223,7 @@ START_TEST(pointer_seat_button_count)
libinput = litest_create_context();
for (i = 0; i < num_devices; ++i) {
sprintf(device_name, "Generic mouse (%d)", i);
sprintf(device_name, "litest Generic mouse (%d)", i);
devices[i] = litest_add_device_with_overrides(libinput,
LITEST_MOUSE,
device_name,

View file

@ -72,15 +72,15 @@ START_TEST(touch_abs_transform)
bool tested = false;
struct input_absinfo abs[] = {
{ ABS_X, 0, 32767, 75, 0, 0 },
{ ABS_Y, 0, 32767, 129, 0, 0 },
{ ABS_X, 0, 32767, 75, 0, 10 },
{ ABS_Y, 0, 32767, 129, 0, 9 },
{ ABS_MT_POSITION_X, 0, 32767, 0, 0, 10 },
{ ABS_MT_POSITION_Y, 0, 32767, 0, 0, 9 },
{ .value = -1 },
};
dev = litest_create_device_with_overrides(LITEST_WACOM_TOUCH,
"Highres touch device",
"litest Highres touch device",
NULL, abs, NULL);
libinput = dev->libinput;
@ -129,7 +129,7 @@ START_TEST(touch_many_slots)
};
dev = litest_create_device_with_overrides(LITEST_WACOM_TOUCH,
"Multi-touch device",
"litest Multi-touch device",
NULL, abs, NULL);
libinput = dev->libinput;

View file

@ -90,7 +90,7 @@ START_TEST(touchpad_2fg_no_motion)
END_TEST
static void
assert_button_event(struct libinput *li, int button,
assert_button_event(struct libinput *li, unsigned int button,
enum libinput_button_state state)
{
struct libinput_event *event;
@ -116,6 +116,8 @@ START_TEST(touchpad_1fg_tap)
struct libinput *li = dev->libinput;
struct libinput_event *event;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
@ -141,6 +143,8 @@ START_TEST(touchpad_1fg_tap_n_drag)
struct libinput *li = dev->libinput;
struct libinput_event *event;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
@ -191,6 +195,8 @@ START_TEST(touchpad_2fg_tap)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
litest_touch_down(dev, 0, 50, 50);
@ -215,6 +221,8 @@ START_TEST(touchpad_2fg_tap_inverted)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
litest_touch_down(dev, 0, 50, 50);
@ -239,6 +247,8 @@ START_TEST(touchpad_1fg_tap_click)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
/* finger down, button click, finger up
@ -266,6 +276,8 @@ START_TEST(touchpad_2fg_tap_click)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
/* two fingers down, button click, fingers up
@ -295,6 +307,8 @@ START_TEST(touchpad_2fg_tap_click_apple)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
/* two fingers down, button click, fingers up
@ -320,11 +334,89 @@ START_TEST(touchpad_2fg_tap_click_apple)
}
END_TEST
START_TEST(touchpad_no_2fg_tap_after_move)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
litest_drain_events(dev->libinput);
/* one finger down, move past threshold,
second finger down, first finger up
-> no event
*/
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10);
litest_drain_events(dev->libinput);
litest_touch_down(dev, 1, 70, 50);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_no_2fg_tap_after_timeout)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
litest_drain_events(dev->libinput);
/* one finger down, wait past tap timeout,
second finger down, first finger up
-> no event
*/
litest_touch_down(dev, 0, 50, 50);
libinput_dispatch(dev->libinput);
msleep(300);
libinput_dispatch(dev->libinput);
litest_drain_events(dev->libinput);
litest_touch_down(dev, 1, 70, 50);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_no_first_fg_tap_after_move)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
litest_drain_events(dev->libinput);
/* one finger down, second finger down,
second finger moves beyond threshold,
first finger up
-> no event
*/
litest_touch_down(dev, 0, 50, 50);
litest_touch_down(dev, 1, 70, 50);
libinput_dispatch(dev->libinput);
litest_touch_move_to(dev, 1, 70, 50, 90, 90, 10);
libinput_dispatch(dev->libinput);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
libinput_dispatch(dev->libinput);
while ((event = libinput_get_event(li))) {
ck_assert_int_ne(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_BUTTON);
libinput_event_destroy(event);
}
}
END_TEST
START_TEST(touchpad_1fg_double_tap_click)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
/* one finger down, up, down, button click, finger up
@ -359,6 +451,8 @@ START_TEST(touchpad_1fg_tap_n_drag_click)
struct libinput *li = dev->libinput;
struct libinput_event *event;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(dev->libinput);
/* one finger down, up, down, move, button click, finger up
@ -599,6 +693,8 @@ START_TEST(clickpad_softbutton_left_tap_n_drag)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(li);
/* Tap in left button area, then finger down, button click
@ -639,6 +735,8 @@ START_TEST(clickpad_softbutton_right_tap_n_drag)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_tap_set_enabled(dev->libinput_device, 1);
litest_drain_events(li);
/* Tap in right button area, then finger down, button click
@ -827,6 +925,8 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
event = libinput_get_event(li);
}
litest_touch_up(dev, 1);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
@ -1027,7 +1127,7 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore)
END_TEST
static void
test_2fg_scroll(struct litest_device *dev, int dx, int dy, int sleep)
test_2fg_scroll(struct litest_device *dev, double dx, double dy, int sleep)
{
struct libinput *li = dev->libinput;
@ -1051,7 +1151,7 @@ test_2fg_scroll(struct litest_device *dev, int dx, int dy, int sleep)
}
static void
check_2fg_scroll(struct litest_device *dev, int axis, int dir)
check_2fg_scroll(struct litest_device *dev, unsigned int axis, int dir)
{
struct libinput *li = dev->libinput;
struct libinput_event *event, *next_event;
@ -1098,19 +1198,212 @@ START_TEST(touchpad_2fg_scroll)
litest_drain_events(li);
/* Note this mixes in a tiny amount of movement in the wrong direction,
which should be ignored */
test_2fg_scroll(dev, 1, 40, 0);
test_2fg_scroll(dev, 0.1, 40, 0);
check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 10);
test_2fg_scroll(dev, 1, -40, 0);
test_2fg_scroll(dev, 0.1, -40, 0);
check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -10);
test_2fg_scroll(dev, 40, 1, 0);
test_2fg_scroll(dev, 40, 0.1, 0);
check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 10);
test_2fg_scroll(dev, -40, 1, 0);
test_2fg_scroll(dev, -40, 0.1, 0);
check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -10);
/* 2fg scroll smaller than the threshold should not generate events */
test_2fg_scroll(dev, 1, 1, 200);
test_2fg_scroll(dev, 0.1, 0.1, 200);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_tap_is_available)
{
struct litest_device *dev = litest_current_device();
ck_assert_int_ge(libinput_device_config_tap_get_finger_count(dev->libinput_device), 1);
ck_assert_int_eq(libinput_device_config_tap_get_enabled(dev->libinput_device), 0);
}
END_TEST
START_TEST(touchpad_tap_is_not_available)
{
struct litest_device *dev = litest_current_device();
ck_assert_int_eq(libinput_device_config_tap_get_finger_count(dev->libinput_device), 0);
ck_assert_int_eq(libinput_device_config_tap_get_enabled(dev->libinput_device), 0);
ck_assert_int_eq(libinput_device_config_tap_set_enabled(dev->libinput_device, 1),
LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST
START_TEST(touchpad_tap_default)
{
struct litest_device *dev = litest_current_device();
ck_assert_int_eq(libinput_device_config_tap_get_default_enabled(dev->libinput_device), 0);
}
END_TEST
static int
touchpad_has_palm_detect_size(struct litest_device *dev)
{
double width, height;
libinput_device_get_size(dev->libinput_device, &width, &height);
return width >= 80;
}
START_TEST(touchpad_palm_detect_at_edge)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev))
return;
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 50);
litest_touch_move_to(dev, 0, 99, 50, 99, 70, 5);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 5, 50);
litest_touch_move_to(dev, 0, 5, 50, 5, 70, 5);
litest_touch_up(dev, 0);
}
END_TEST
START_TEST(touchpad_palm_detect_at_bottom_corners)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev))
return;
/* Run for non-clickpads only: make sure the bottom corners trigger
palm detection too */
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 95);
litest_touch_move_to(dev, 0, 99, 95, 99, 99, 10);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 5, 95);
litest_touch_move_to(dev, 0, 5, 95, 5, 99, 5);
litest_touch_up(dev, 0);
}
END_TEST
START_TEST(touchpad_palm_detect_at_top_corners)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev))
return;
/* Run for non-clickpads only: make sure the bottom corners trigger
palm detection too */
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 5);
litest_touch_move_to(dev, 0, 99, 5, 99, 9, 10);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 5, 5);
litest_touch_move_to(dev, 0, 5, 5, 5, 9, 5);
litest_touch_up(dev, 0);
}
END_TEST
START_TEST(touchpad_palm_detect_palm_stays_palm)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev))
return;
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 20);
litest_touch_move_to(dev, 0, 99, 20, 75, 99, 5);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_palm_detect_palm_becomes_pointer)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *ev;
enum libinput_event_type type;
if (!touchpad_has_palm_detect_size(dev))
return;
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 50);
litest_touch_move_to(dev, 0, 99, 70, 0, 70, 5);
litest_touch_up(dev, 0);
libinput_dispatch(li);
ev = libinput_get_event(li);
ck_assert_notnull(ev);
do {
type = libinput_event_get_type(ev);
ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(ev);
ev = libinput_get_event(li);
} while (ev);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_palm_detect_no_palm_moving_into_edges)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *ev;
enum libinput_event_type type;
if (!touchpad_has_palm_detect_size(dev))
return;
/* moving non-palm into the edge does not label it as palm */
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 99, 50, 5);
litest_drain_events(li);
litest_touch_move_to(dev, 0, 99, 50, 99, 90, 5);
libinput_dispatch(li);
type = libinput_next_event_type(li);
do {
ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_MOTION);
ev = libinput_get_event(li);
libinput_event_destroy(ev);
type = libinput_next_event_type(li);
libinput_dispatch(li);
} while (type != LIBINPUT_EVENT_NONE);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_empty_queue(li);
}
END_TEST
@ -1127,11 +1420,20 @@ int main(int argc, char **argv) {
litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD);
litest_add("touchpad:tap", touchpad_2fg_tap_click_apple, LITEST_APPLE_CLICKPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_no_2fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_no_2fg_tap_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
/* Real buttons don't interfere with tapping, so don't run those for
pads with buttons */
litest_add("touchpad:tap", touchpad_1fg_double_tap_click, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_tap_default, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_tap_is_available, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_tap_is_not_available, LITEST_ANY, LITEST_TOUCHPAD);
litest_add_no_device("touchpad:clickfinger", touchpad_1fg_clickfinger);
litest_add_no_device("touchpad:clickfinger", touchpad_2fg_clickfinger);
@ -1155,5 +1457,12 @@ int main(int argc, char **argv) {
litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:palm", touchpad_palm_detect_at_top_corners, LITEST_TOUCHPAD, LITEST_TOPBUTTONPAD);
litest_add("touchpad:palm", touchpad_palm_detect_palm_becomes_pointer, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY);
return litest_run(argc, argv);
}

View file

@ -199,7 +199,7 @@ static void
print_event_header(struct libinput_event *ev)
{
struct libinput_device *dev = libinput_event_get_device(ev);
const char *type;
const char *type = NULL;
switch(libinput_event_get_type(ev)) {
case LIBINPUT_EVENT_NONE:
@ -561,7 +561,7 @@ handle_and_print_events(struct libinput *li)
return rc;
}
void
static void
mainloop(struct libinput *li)
{
struct pollfd fds[2];

View file

@ -142,8 +142,7 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data)
cairo_set_source_rgb(cr, .2, .4, .8);
cairo_save(cr);
cairo_move_to(cr, w->absx, w->absy);
cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI);
cairo_arc(cr, w->absx, w->absy, 10, 0, 2 * M_PI);
cairo_fill(cr);
cairo_restore(cr);
@ -243,11 +242,11 @@ static void
handle_event_absmotion(struct libinput_event *ev, struct window *w)
{
struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
double x = libinput_event_pointer_get_absolute_x(p),
y = libinput_event_pointer_get_absolute_y(p);
double x = libinput_event_pointer_get_absolute_x_transformed(p, w->width),
y = libinput_event_pointer_get_absolute_y_transformed(p, w->height);
w->absx = clip((int)x, 0, w->width);
w->absy = clip((int)y, 0, w->height);
w->absx = x;
w->absy = y;
}
static void
@ -258,7 +257,7 @@ handle_event_touch(struct libinput_event *ev, struct window *w)
struct touch *touch;
double x, y;
if (slot == -1 || slot >= ARRAY_LENGTH(w->touches))
if (slot == -1 || slot >= (int) ARRAY_LENGTH(w->touches))
return;
touch = &w->touches[slot];
@ -268,8 +267,8 @@ handle_event_touch(struct libinput_event *ev, struct window *w)
return;
}
x = libinput_event_touch_get_x(t),
y = libinput_event_touch_get_y(t);
x = libinput_event_touch_get_x_transformed(t, w->width),
y = libinput_event_touch_get_y_transformed(t, w->height);
touch->active = 1;
touch->x = (int)x;
@ -442,7 +441,7 @@ close_restricted(int fd, void *user_data)
close(fd);
}
const static struct libinput_interface interface = {
static const struct libinput_interface interface = {
.open_restricted = open_restricted,
.close_restricted = close_restricted,
};