-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iEYEABECAAYFAlSBMWUACgkQ4jt+cLRn8L/4JQCgt0u/hImDVk9GLPXpUfFZinRc
 pIgAn1bZ91n/o4nEhq6zOXSsKRoZvxHL
 =oj19
 -----END PGP SIGNATURE-----

Merge tag '0.7.0' into tablet-support

0.7.0

Conflicts:
	src/libinput-private.h
	test/device.c
	test/litest.h
This commit is contained in:
Peter Hutterer 2014-12-08 11:14:11 +10:00
commit 83f97991a0
42 changed files with 7051 additions and 1659 deletions

View file

@ -1,7 +1,7 @@
AC_PREREQ([2.64])
m4_define([libinput_major_version], [0])
m4_define([libinput_minor_version], [6])
m4_define([libinput_minor_version], [7])
m4_define([libinput_micro_version], [0])
m4_define([libinput_version],
[libinput_major_version.libinput_minor_version.libinput_micro_version])
@ -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 subdir-objects])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
# Before making a release, the LIBINPUT_LT_VERSION string should be
# modified.
@ -30,7 +30,7 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
# - If binary compatibility has been broken (eg removed or changed interfaces)
# change to C+1:0:0
# - If the interface is the same as the previous version, change to C:R+1:A
LIBINPUT_LT_VERSION=5:0:0
LIBINPUT_LT_VERSION=6:0:1
AC_SUBST(LIBINPUT_LT_VERSION)
AM_SILENT_RULES([yes])

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,262 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1490px" height="1399px" version="1.1">
<defs/>
<g transform="translate(0.5,0.5)">
<ellipse cx="261" cy="143" rx="63" ry="45.5" fill="#ccccff" stroke="#000000" stroke-width="2" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="261" y="126">NONE</text>
<text x="261" y="140">on-entry:</text>
<text x="261" y="154">edge = none</text>
<text x="261" y="168">threshold = def</text>
</g>
<rect x="30" y="386" 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="105" y="419">EDGE_NEW</text>
<text x="105" y="433">on-entry:</text>
<text x="105" y="447">edge = get_edge()</text>
<text x="105" y="461">set_timer()</text>
</g>
<rect x="348" y="386" 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="413" y="419">AREA</text>
<text x="413" y="433">on-entry:</text>
<text x="413" y="447">edge = none</text>
<text x="413" y="461">set_pointer()</text>
</g>
<path d="M 237 7 C 239 4 243 2 246 2 L 275 2 C 278 2 282 4 284 7 L 301 30 C 301 31 301 33 301 34 L 284 57 C 282 60 278 62 275 62 L 246 62 C 243 62 239 60 237 57 L 220 34 C 220 33 220 31 220 30 L 237 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="261" y="36">release</text>
</g>
<path d="M 237 222 C 239 219 243 217 246 217 L 276 217 C 279 217 283 219 285 222 L 303 245 C 303 246 303 248 303 249 L 285 272 C 283 275 279 277 276 277 L 246 277 C 243 277 239 275 237 272 L 219 249 C 219 248 219 246 219 245 L 237 222 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="261" y="251">touch</text>
</g>
<path d="M 261 188 L 261 211" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 261 216 L 258 209 L 261 211 L 265 209 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 218 535 C 223 531 229 528 235 528 L 285 528 C 291 528 297 531 302 535 L 331 570 C 332 571 332 574 331 575 L 302 610 C 297 614 291 617 285 617 L 235 617 C 229 617 223 614 218 610 L 189 575 C 188 574 188 571 189 570 L 218 535 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="260" y="563">touch,</text>
<text x="260" y="577">edge &amp;= get_edge()</text>
</g>
<path d="M 220 526 L 158 487" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 224 529 L 217 528 L 220 526 L 220 522 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 105 617 L 105 650" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 105 656 L 101 649 L 105 650 L 108 649 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 478 436 L 498 436 Q 508 436 508 426 L 508 42 Q 508 32 498 32 L 307 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 302 32 L 309 29 L 307 32 L 309 36 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 261 62 L 261 71 Q 261 80 261 85 L 261 91" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 261 96 L 257 89 L 261 91 L 264 89 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<ellipse cx="1133" cy="67" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<path d="M 1133 82 L 1133 110 Q 1133 120 1133 130 L 1133 155" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 147 L 1133 156 L 1138 147" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="1083" y="12" 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="1133" y="36">tp_edge_scroll_post_events()</text>
</g>
<path d="M 1133 212 L 1193 242 L 1133 272 L 1073 242 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="1133" y="246">dirty?</text>
</g>
<path d="M 1193 242 L 1278 242 Q 1288 242 1298 242 L 1456 242" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1448 247 L 1457 242 L 1448 238" 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="1225" y="223" width="18" height="18" stroke-width="0"/>
<text x="1226" y="236">no</text>
</g>
<path d="M 1133 272 L 1133 285 Q 1133 295 1133 305 L 1133 316" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 308 L 1133 317 L 1138 308" 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="1150" y="292" width="24" height="18" stroke-width="0"/>
<text x="1150" y="302">yes</text>
</g>
<ellipse cx="1473" cy="242" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1473" cy="242" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<rect x="1033" y="97" width="200" height="70" rx="28" ry="28" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1133" y="115">current = buttons.state &amp; 0x01</text>
<text x="1133" y="129">old = buttons.old_state &amp; 0x01</text>
<text x="1133" y="143">button = 0</text>
<text x="1133" y="157">is_top = 0</text>
</g>
<path d="M 1133 167 L 1133 180 Q 1133 190 1133 200 L 1133 210" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 202 L 1133 211 L 1138 202" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="1237" y="436" width="188" height="50" rx="20" ry="20" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1331" y="458">notify_axis(last_axis, 0.0)</text>
<text x="1331" y="472">last_axis = -1</text>
</g>
<path d="M 1134 516 L 1194 552 L 1134 587 L 1073 552 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="1134" y="556">edge == right</text>
</g>
<path d="M 1194 552 L 1268 552 Q 1278 552 1278 553 L 1278 554 Q 1278 554 1268 554 L 1250 554" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1258 550 L 1249 554 L 1258 559" 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="1202" y="559" width="24" height="18" stroke-width="0"/>
<text x="1203" y="569">yes</text>
</g>
<rect x="1248" y="534" 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="1328" y="551">axis = scroll_vertical</text>
<text x="1328" y="565">delta = dy</text>
</g>
<path d="M 1408 554 L 1468 554 Q 1478 554 1478 564 L 1478 952 Q 1478 962 1468 962 L 1233 962" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1241 958 L 1232 962 L 1241 967" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1133 318 L 1196 352 L 1133 387 L 1071 352 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="1133" y="356">edge == none</text>
</g>
<path d="M 1134 386 L 1134 441 Q 1134 451 1134 461 L 1134 514" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 506 L 1134 515 L 1138 506" 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="1135" y="449" width="18" height="18" stroke-width="0"/>
<text x="1136" y="458">no</text>
</g>
<path d="M 1133 657 L 1194 692 L 1133 727 L 1072 692 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="1133" y="696">edge == bottom</text>
</g>
<path d="M 1194 692 L 1208 692 Q 1218 692 1228 692 L 1249 692" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1241 697 L 1250 692 L 1241 688" 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="1213" y="700" width="24" height="18" stroke-width="0"/>
<text x="1214" y="709">yes</text>
</g>
<path d="M 1134 587 L 1133 587 Q 1133 587 1133 597 L 1133 647 Q 1133 657 1133 656 L 1133 655" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 647 L 1133 656 L 1138 647" 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="1135" y="607" width="18" height="18" stroke-width="0"/>
<text x="1135" y="621">no</text>
</g>
<rect x="1251" y="672" 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="1331" y="689">axis = scroll_horizontal</text>
<text x="1331" y="703">delta = dx</text>
</g>
<path d="M 1133 727 L 1133 727 Q 1134 727 1134 737 L 1134 807 Q 1134 817 1134 816 L 1134 815" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 807 L 1134 816 L 1138 807" 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="1135" y="756" width="18" height="18" stroke-width="0"/>
<text x="1136" y="770">no</text>
</g>
<rect x="1036" y="917" width="195" height="90" rx="36" ry="36" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1134" y="966">get_delta()</text>
</g>
<path d="M 1134 1007 L 1134 1037 Q 1134 1047 1134 1057 L 1134 1070" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 1062 L 1134 1071 L 1138 1062" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1411 692 L 1468 692 Q 1478 692 1478 702 L 1478 952 Q 1478 962 1468 962 L 1233 962" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1241 958 L 1232 962 L 1241 967" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<rect x="1031" y="1197" width="205" height="90" rx="36" ry="36" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="1134" y="1232">notify_axis(axis, delta)</text>
<text x="1134" y="1246">last_axis = axis</text>
<text x="1134" y="1260">emit(scroll_event_posted)</text>
</g>
<path d="M 1134 1072 L 1200 1107 L 1134 1142 L 1067 1107 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="1134" y="1111">delta &lt; threshold</text>
</g>
<path d="M 1200 1107 L 1318 1107 Q 1328 1107 1338 1107 L 1456 1107" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1448 1112 L 1457 1107 L 1448 1103" 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="1259" y="1118" width="24" height="18" stroke-width="0"/>
<text x="1260" y="1131">yes</text>
</g>
<path d="M 1134 1142 L 1134 1160 Q 1134 1170 1134 1180 L 1134 1195" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1129 1187 L 1134 1196 L 1138 1187" 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="1135" y="1150" width="18" height="18" stroke-width="0"/>
<text x="1136" y="1159">no</text>
</g>
<ellipse cx="1473" cy="1107" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1473" cy="1107" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1473" cy="352" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1473" cy="352" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<path d="M 1331 318 L 1394 352 L 1331 387 L 1269 352 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="1331" y="356">last_axis != -1</text>
</g>
<rect x="30" y="657" 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="105" y="697">EDGE</text>
<text x="105" y="711">on-entry:</text>
<text x="105" y="725">threshold = 0.01</text>
</g>
<path d="M 30 707 L 18 707 Q 8 707 8 697 L 8 42 Q 8 32 18 32 L 214 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 219 32 L 212 36 L 214 32 L 212 29 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 30 436 L 18 436 Q 8 436 8 426 L 8 42 Q 8 32 18 32 L 214 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 219 32 L 212 36 L 214 32 L 212 29 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 64 535 C 68 531 74 528 80 528 L 130 528 C 136 528 142 531 146 535 L 175 570 C 176 571 176 574 175 575 L 146 610 C 142 614 136 617 130 617 L 80 617 C 74 617 68 614 64 610 L 35 575 C 34 574 34 571 35 570 L 64 535 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="105" y="563">timeout ||</text>
<text x="105" y="577">scroll_event_posted</text>
</g>
<path d="M 105 487 L 105 522" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 105 527 L 102 520 L 105 522 L 109 520 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 260 528 L 261 472" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 261 467 L 264 474 L 261 472 L 257 474 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1196 352 L 1222 352 Q 1232 352 1242 352 L 1266 352" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1258 357 L 1267 352 L 1258 348" 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="1224" y="360" width="24" height="18" stroke-width="0"/>
<text x="1224" y="369">yes</text>
</g>
<path d="M 1331 387 L 1331 401 Q 1331 411 1331 421 L 1331 434" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1327 426 L 1331 435 L 1336 426" 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="1333" y="394" width="24" height="18" stroke-width="0"/>
<text x="1333" y="403">yes</text>
</g>
<path d="M 1394 352 L 1408 352 Q 1418 352 1428 352 L 1456 352" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1448 357 L 1457 352 L 1448 348" 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="1417" y="360" width="18" height="18" stroke-width="0"/>
<text x="1418" y="369">no</text>
</g>
<ellipse cx="1473" cy="461" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1473" cy="461" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<path d="M 1425 461 L 1438 461 Q 1448 461 1452 461 L 1456 461" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1448 466 L 1457 461 L 1448 457" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<ellipse cx="1134" cy="832" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1134" cy="832" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1134" cy="1382" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
<ellipse cx="1134" cy="1382" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
<path d="M 1134 1287 L 1134 1365" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 1130 1359 L 1134 1366 L 1137 1359" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 261 277 L 261 299" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 261 304 L 258 297 L 261 299 L 265 297 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 208 337 L 115 337 Q 105 337 105 347 L 105 376 Q 105 386 105 382 L 105 378" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 105 385 L 100 376 L 105 378 L 109 376 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="174" y="345" width="24" height="18" stroke-width="0"/>
<text x="175" y="354">yes</text>
</g>
<path d="M 314 337 L 403 337 Q 413 337 413 347 L 413 376 Q 413 386 413 382 L 413 378" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 413 385 L 408 376 L 413 378 L 417 376 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="350" y="345" width="18" height="18" stroke-width="0"/>
<text x="350" y="354">no</text>
</g>
<path d="M 261 305 L 314 337 L 261 369 L 208 337 Z" fill="#ffd966" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="261" y="341">get_edge()</text>
</g>
<path d="M 261 406 L 309 436 L 261 466 L 213 436 Z" fill="#ffd966" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
<text x="261" y="440">edge</text>
</g>
<path d="M 309 436 L 319 436 Q 328 436 334 436 L 340 436" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 347 436 L 338 441 L 340 436 L 338 432 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="311" y="444" width="18" height="18" stroke-width="0"/>
<text x="311" y="453">no</text>
</g>
<path d="M 213 436 L 211 436 Q 208 436 198 436 L 188 436" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<path d="M 181 436 L 190 432 L 188 436 L 190 441 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g fill="#000000" font-family="Helvetica" font-size="11px">
<rect fill="#ffffff" stroke="none" x="189" y="444" width="24" height="18" stroke-width="0"/>
<text x="190" y="453">yes</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -1,4 +1,5 @@
lib_LTLIBRARIES = libinput.la
noinst_LTLIBRARIES = libinput-util.la
include_HEADERS = \
libinput.h
@ -7,8 +8,6 @@ libinput_la_SOURCES = \
libinput.c \
libinput.h \
libinput-private.h \
libinput-util.c \
libinput-util.h \
evdev.c \
evdev.h \
evdev-tablet.c \
@ -17,8 +16,10 @@ libinput_la_SOURCES = \
evdev-mt-touchpad.h \
evdev-mt-touchpad-tap.c \
evdev-mt-touchpad-buttons.c \
evdev-mt-touchpad-edge-scroll.c \
filter.c \
filter.h \
filter-private.h \
path.h \
path.c \
udev-seat.c \
@ -29,13 +30,24 @@ libinput_la_SOURCES = \
libinput_la_LIBADD = $(MTDEV_LIBS) \
$(LIBUDEV_LIBS) \
$(LIBEVDEV_LIBS)
$(LIBEVDEV_LIBS) \
libinput-util.la
libinput_la_CFLAGS = -I$(top_srcdir)/include \
$(MTDEV_CFLAGS) \
$(LIBUDEV_CFLAGS) \
$(LIBEVDEV_CFLAGS) \
$(GCC_CFLAGS)
libinput_util_la_SOURCES = \
libinput-util.c \
libinput-util.h
libinput_util_la_LIBADD =
libinput_util_la_CFLAGS = -I$(top_srcdir)/include \
$(LIBUDEV_CFLAGS) \
$(GCC_CFLAGS)
libinput_la_LDFLAGS = -version-info $(LIBINPUT_LT_VERSION) -shared
pkgconfigdir = $(libdir)/pkgconfig

View file

@ -565,12 +565,12 @@ tp_init_buttons(struct tp_dispatch *tp,
if (tp->buttons.is_clickpad)
log_bug_kernel(libinput,
"%s: clickpad advertising right button\n",
device->sysname);
device->devname);
} else {
if (!tp->buttons.is_clickpad)
log_bug_kernel(libinput,
"%s: non clickpad without right button?\n",
device->sysname);
device->devname);
}
absinfo_x = device->abs.absinfo_x;
@ -661,14 +661,17 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
enum libinput_button_state state;
if ((current & 0x1) ^ (old & 0x1)) {
uint32_t b;
if (!!(current & 0x1))
state = LIBINPUT_BUTTON_STATE_PRESSED;
else
state = LIBINPUT_BUTTON_STATE_RELEASED;
b = evdev_to_left_handed(tp->device, button);
evdev_pointer_notify_button(tp->device,
time,
button,
b,
state);
}
@ -758,10 +761,12 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
}
if ((button & MIDDLE) || ((button & LEFT) && (button & RIGHT)))
button = BTN_MIDDLE;
button = evdev_to_left_handed(tp->device, BTN_MIDDLE);
else if (button & RIGHT)
button = BTN_RIGHT;
else
button = evdev_to_left_handed(tp->device, BTN_RIGHT);
else if (button & LEFT)
button = evdev_to_left_handed(tp->device, BTN_LEFT);
else /* main area is always BTN_LEFT */
button = BTN_LEFT;
tp->buttons.active = button;

View file

@ -0,0 +1,374 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include "linux/input.h"
#include "evdev-mt-touchpad.h"
#define DEFAULT_SCROLL_LOCK_TIMEOUT 300 /* ms */
/* Use a reasonably large threshold until locked into scrolling mode, to
avoid accidentally locking in scrolling mode when trying to use the entire
touchpad to move the pointer. The user can wait for the timeout to trigger
to do a small scroll. */
/* In mm for touchpads with valid resolution, see tp_init_accel() */
#define DEFAULT_SCROLL_THRESHOLD 10.0
enum scroll_event {
SCROLL_EVENT_TOUCH,
SCROLL_EVENT_MOTION,
SCROLL_EVENT_RELEASE,
SCROLL_EVENT_TIMEOUT,
SCROLL_EVENT_POSTED,
};
static uint32_t
tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *touch)
{
uint32_t edge = EDGE_NONE;
if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE)
return EDGE_NONE;
if (touch->x > tp->scroll.right_edge)
edge |= EDGE_RIGHT;
if (touch->y > tp->scroll.bottom_edge)
edge |= EDGE_BOTTOM;
return edge;
}
static void
tp_edge_scroll_set_state(struct tp_dispatch *tp,
struct tp_touch *t,
enum tp_edge_scroll_touch_state state)
{
libinput_timer_cancel(&t->scroll.timer);
t->scroll.state = state;
switch (state) {
case EDGE_SCROLL_TOUCH_STATE_NONE:
t->scroll.edge = EDGE_NONE;
t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD;
break;
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
t->scroll.edge = tp_touch_get_edge(tp, t);
libinput_timer_set(&t->scroll.timer,
t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
break;
case EDGE_SCROLL_TOUCH_STATE_EDGE:
t->scroll.threshold = 0.01; /* Do not allow 0.0 events */
break;
case EDGE_SCROLL_TOUCH_STATE_AREA:
t->scroll.edge = EDGE_NONE;
tp_set_pointer(tp, t);
break;
}
}
static void
tp_edge_scroll_handle_none(struct tp_dispatch *tp,
struct tp_touch *t,
enum scroll_event event)
{
struct libinput *libinput = tp->device->base.seat->libinput;
switch (event) {
case SCROLL_EVENT_TOUCH:
if (tp_touch_get_edge(tp, t)) {
tp_edge_scroll_set_state(tp, t,
EDGE_SCROLL_TOUCH_STATE_EDGE_NEW);
} else {
tp_edge_scroll_set_state(tp, t,
EDGE_SCROLL_TOUCH_STATE_AREA);
}
break;
case SCROLL_EVENT_MOTION:
case SCROLL_EVENT_RELEASE:
case SCROLL_EVENT_TIMEOUT:
case SCROLL_EVENT_POSTED:
log_bug_libinput(libinput,
"unexpect scroll event in none state\n");
break;
}
}
static void
tp_edge_scroll_handle_edge_new(struct tp_dispatch *tp,
struct tp_touch *t,
enum scroll_event event)
{
struct libinput *libinput = tp->device->base.seat->libinput;
switch (event) {
case SCROLL_EVENT_TOUCH:
log_bug_libinput(libinput,
"unexpect scroll event in edge new state\n");
break;
case SCROLL_EVENT_MOTION:
t->scroll.edge &= tp_touch_get_edge(tp, t);
if (!t->scroll.edge)
tp_edge_scroll_set_state(tp, t,
EDGE_SCROLL_TOUCH_STATE_AREA);
break;
case SCROLL_EVENT_RELEASE:
tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
break;
case SCROLL_EVENT_TIMEOUT:
case SCROLL_EVENT_POSTED:
tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_EDGE);
break;
}
}
static void
tp_edge_scroll_handle_edge(struct tp_dispatch *tp,
struct tp_touch *t,
enum scroll_event event)
{
struct libinput *libinput = tp->device->base.seat->libinput;
switch (event) {
case SCROLL_EVENT_TOUCH:
case SCROLL_EVENT_TIMEOUT:
log_bug_libinput(libinput,
"unexpect scroll event in edge state\n");
break;
case SCROLL_EVENT_MOTION:
/* If started at the bottom right, decide in which dir to scroll */
if (t->scroll.edge == (EDGE_RIGHT | EDGE_BOTTOM)) {
t->scroll.edge &= tp_touch_get_edge(tp, t);
if (!t->scroll.edge)
tp_edge_scroll_set_state(tp, t,
EDGE_SCROLL_TOUCH_STATE_AREA);
}
break;
case SCROLL_EVENT_RELEASE:
tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
break;
case SCROLL_EVENT_POSTED:
break;
}
}
static void
tp_edge_scroll_handle_area(struct tp_dispatch *tp,
struct tp_touch *t,
enum scroll_event event)
{
struct libinput *libinput = tp->device->base.seat->libinput;
switch (event) {
case SCROLL_EVENT_TOUCH:
case SCROLL_EVENT_TIMEOUT:
case SCROLL_EVENT_POSTED:
log_bug_libinput(libinput,
"unexpect scroll event in area state\n");
break;
case SCROLL_EVENT_MOTION:
break;
case SCROLL_EVENT_RELEASE:
tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
break;
}
}
static void
tp_edge_scroll_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
enum scroll_event event)
{
switch (t->scroll.state) {
case EDGE_SCROLL_TOUCH_STATE_NONE:
tp_edge_scroll_handle_none(tp, t, event);
break;
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
tp_edge_scroll_handle_edge_new(tp, t, event);
break;
case EDGE_SCROLL_TOUCH_STATE_EDGE:
tp_edge_scroll_handle_edge(tp, t, event);
break;
case EDGE_SCROLL_TOUCH_STATE_AREA:
tp_edge_scroll_handle_area(tp, t, event);
break;
}
}
static void
tp_edge_scroll_handle_timeout(uint64_t now, void *data)
{
struct tp_touch *t = data;
tp_edge_scroll_handle_event(t->tp, t, SCROLL_EVENT_TIMEOUT);
}
int
tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
{
struct tp_touch *t;
int width, height;
int edge_width, edge_height;
width = device->abs.absinfo_x->maximum - device->abs.absinfo_x->minimum;
height = device->abs.absinfo_y->maximum - device->abs.absinfo_y->minimum;
switch (tp->model) {
case MODEL_ALPS:
edge_width = width * .15;
edge_height = height * .15;
break;
case MODEL_APPLETOUCH: /* unibody are all clickpads, so N/A */
edge_width = width * .085;
edge_height = height * .085;
break;
default:
/* For elantech and synaptics, note for lenovo #40 series,
* e.g. the T440s min/max are the absolute edges, not the
* recommended ones as usual with synaptics. But these are
* clickpads, so N/A.
*/
edge_width = width * .04;
edge_height = height * .054;
}
tp->scroll.right_edge = device->abs.absinfo_x->maximum - edge_width;
tp->scroll.bottom_edge = device->abs.absinfo_y->maximum - edge_height;
tp_for_each_touch(tp, t) {
t->scroll.direction = -1;
t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD;
libinput_timer_init(&t->scroll.timer,
device->base.seat->libinput,
tp_edge_scroll_handle_timeout, t);
}
return 0;
}
void
tp_destroy_edge_scroll(struct tp_dispatch *tp)
{
struct tp_touch *t;
tp_for_each_touch(tp, t)
libinput_timer_cancel(&t->scroll.timer);
}
void
tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
tp_for_each_touch(tp, t) {
if (!t->dirty)
continue;
switch (t->state) {
case TOUCH_NONE:
break;
case TOUCH_BEGIN:
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_TOUCH);
break;
case TOUCH_UPDATE:
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_MOTION);
break;
case TOUCH_END:
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_RELEASE);
break;
}
}
}
int
tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
{
struct libinput_device *device = &tp->device->base;
struct tp_touch *t;
enum libinput_pointer_axis axis;
double dx, dy, *delta;
tp_for_each_touch(tp, t) {
if (!t->dirty)
continue;
switch (t->scroll.edge) {
case EDGE_NONE:
if (t->scroll.direction != -1) {
/* Send stop scroll event */
pointer_notify_axis(device, time,
t->scroll.direction, 0.0);
t->scroll.direction = -1;
}
continue;
case EDGE_RIGHT:
axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
delta = &dy;
break;
case EDGE_BOTTOM:
axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
delta = &dx;
break;
default: /* EDGE_RIGHT | EDGE_BOTTOM */
continue; /* Don't know direction yet, skip */
}
tp_get_delta(t, &dx, &dy);
tp_filter_motion(tp, &dx, &dy, NULL, NULL, time);
if (fabs(*delta) < t->scroll.threshold)
continue;
pointer_notify_axis(device, time, axis, *delta);
t->scroll.direction = axis;
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED);
}
return 0; /* Edge touches are suppressed by edge_scroll_touch_active */
}
void
tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time)
{
struct libinput_device *device = &tp->device->base;
struct tp_touch *t;
tp_for_each_touch(tp, t) {
if (t->scroll.direction != -1) {
pointer_notify_axis(device, time,
t->scroll.direction, 0.0);
t->scroll.direction = -1;
}
}
}
int
tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return t->scroll.state == EDGE_SCROLL_TOUCH_STATE_AREA;
}

View file

@ -95,16 +95,12 @@ 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;
@ -113,6 +109,11 @@ tp_tap_notify(struct tp_dispatch *tp,
return;
}
if (state == LIBINPUT_BUTTON_STATE_PRESSED)
tp->tap.buttons_pressed |= (1 << nfingers);
else
tp->tap.buttons_pressed &= ~(1 << nfingers);
evdev_pointer_notify_button(tp->device,
time,
button,
@ -169,7 +170,7 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_TAPPED;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_set_timer(tp, time);
break;
case TAP_EVENT_TIMEOUT:
@ -224,11 +225,11 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_TIMEOUT:
tp->tap.state = TAP_STATE_IDLE;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
@ -246,8 +247,10 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_HOLD;
tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_RELEASED);
if (t->tap.state == TAP_TOUCH_STATE_TOUCH) {
tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED);
}
tp_tap_clear_timer(tp);
break;
case TAP_EVENT_MOTION:
@ -304,8 +307,10 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_RELEASED);
if (t->tap.state == TAP_TOUCH_STATE_TOUCH) {
tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_PRESSED);
tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_RELEASED);
}
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
@ -347,9 +352,9 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_RELEASE:
tp->tap.state = TAP_STATE_IDLE;
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_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_clear_timer(tp);
break;
case TAP_EVENT_MOTION:
@ -358,7 +363,7 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
@ -383,7 +388,7 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
@ -404,11 +409,11 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_TIMEOUT:
tp->tap.state = TAP_STATE_IDLE;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
@ -425,7 +430,7 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_TOUCH:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
case TAP_EVENT_MOTION:
case TAP_EVENT_TIMEOUT:
@ -433,7 +438,7 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp,
break;
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
}
}
@ -471,9 +476,6 @@ tp_tap_handle_event(struct tp_dispatch *tp,
switch(tp->tap.state) {
case TAP_STATE_IDLE:
if (!tp->tap.enabled)
break;
tp_tap_idle_handle_event(tp, t, event, time);
break;
case TAP_STATE_TOUCH:
@ -535,12 +537,21 @@ tp_tap_exceeds_motion_threshold(struct tp_dispatch *tp, struct tp_touch *t)
return dx * dx + dy * dy > threshold * threshold;
}
static bool
tp_tap_enabled(struct tp_dispatch *tp)
{
return tp->tap.enabled && !tp->tap.suspended;
}
int
tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
int filter_motion = 0;
if (!tp_tap_enabled(tp))
return 0;
/* Handle queued button pressed events from clickpads. For touchpads
* with separate physical buttons, ignore button pressed events so they
* don't interfere with tapping. */
@ -551,7 +562,8 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
if (!t->dirty || t->state == TOUCH_NONE)
continue;
if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
if (tp->buttons.is_clickpad &&
tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
t->tap.state = TAP_TOUCH_STATE_DEAD;
if (t->state == TOUCH_BEGIN) {
@ -559,7 +571,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
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;
t->tap.state = TAP_TOUCH_STATE_IDLE;
} else if (tp->tap.state != TAP_STATE_IDLE &&
tp_tap_exceeds_motion_threshold(tp, t)) {
struct tp_touch *tmp;
@ -615,6 +627,26 @@ tp_tap_handle_timeout(uint64_t time, void *data)
}
}
static void
tp_tap_enabled_update(struct tp_dispatch *tp, bool suspended, bool enabled, uint64_t time)
{
bool was_enabled = tp_tap_enabled(tp);
tp->tap.suspended = suspended;
tp->tap.enabled = enabled;
if (tp_tap_enabled(tp) == was_enabled)
return;
if (tp_tap_enabled(tp)) {
/* Must restart in DEAD if fingers are down atm */
tp->tap.state =
tp->nfingers_down ? TAP_STATE_DEAD : TAP_STATE_IDLE;
} else {
tp_release_all_taps(tp, time);
}
}
static int
tp_tap_config_count(struct libinput_device *device)
{
@ -631,13 +663,12 @@ static enum libinput_config_status
tp_tap_config_set_enabled(struct libinput_device *device,
enum libinput_config_tap_state enabled)
{
struct evdev_dispatch *dispatch;
struct tp_dispatch *tp = NULL;
struct evdev_dispatch *dispatch = ((struct evdev_device *) device)->dispatch;
struct tp_dispatch *tp = container_of(dispatch, tp, base);
dispatch = ((struct evdev_device *) device)->dispatch;
tp = container_of(dispatch, tp, base);
tp->tap.enabled = (enabled == LIBINPUT_CONFIG_TAP_ENABLED);
tp_tap_enabled_update(tp, tp->tap.suspended,
(enabled == LIBINPUT_CONFIG_TAP_ENABLED),
libinput_now(device->seat->libinput));
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
@ -697,5 +728,37 @@ tp_destroy_tap(struct tp_dispatch *tp)
void
tp_release_all_taps(struct tp_dispatch *tp, uint64_t now)
{
tp_tap_handle_timeout(now, tp);
int i;
for (i = 1; i <= 3; i++) {
if (tp->tap.buttons_pressed & (1 << i))
tp_tap_notify(tp, now, i, LIBINPUT_BUTTON_STATE_RELEASED);
}
tp->tap.state = tp->nfingers_down ? TAP_STATE_DEAD : TAP_STATE_IDLE;
}
void
tp_tap_suspend(struct tp_dispatch *tp, uint64_t time)
{
tp_tap_enabled_update(tp, true, tp->tap.enabled, time);
}
void
tp_tap_resume(struct tp_dispatch *tp, uint64_t time)
{
tp_tap_enabled_update(tp, false, tp->tap.enabled, time);
}
bool
tp_tap_dragging(struct tp_dispatch *tp)
{
switch (tp->tap.state) {
case TAP_STATE_DRAGGING:
case TAP_STATE_DRAGGING_2:
case TAP_STATE_DRAGGING_WAIT:
return true;
default:
return false;
}
}

View file

@ -31,6 +31,7 @@
#define DEFAULT_ACCEL_NUMERATOR 1200.0
#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT 500 /* ms */
static inline int
tp_hysteresis(int in, int center, int margin)
@ -55,17 +56,24 @@ tp_motion_history_offset(struct tp_touch *t, int offset)
return &t->history.samples[offset_index];
}
static void
void
tp_filter_motion(struct tp_dispatch *tp,
double *dx, double *dy, uint64_t time)
double *dx, double *dy,
double *dx_unaccel, double *dy_unaccel,
uint64_t time)
{
struct motion_params motion;
motion.dx = *dx * tp->accel.x_scale_coeff;
motion.dy = *dy * tp->accel.y_scale_coeff;
if (dx_unaccel)
*dx_unaccel = motion.dx;
if (dy_unaccel)
*dy_unaccel = motion.dy;
if (motion.dx != 0.0 || motion.dy != 0.0)
filter_dispatch(tp->filter, &motion, tp, time);
filter_dispatch(tp->device->pointer.filter, &motion, tp, time);
*dx = motion.dx;
*dy = motion.dy;
@ -338,7 +346,9 @@ 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);
!t->pinned.is_pinned &&
tp_button_touch_active(tp, t) &&
tp_edge_scroll_touch_active(tp, t);
}
void
@ -397,6 +407,116 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
t->palm.y = t->y;
}
static void
tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
int nchanged = 0;
double dx = 0, dy =0;
double tmpx, tmpy;
tp_for_each_touch(tp, t) {
if (tp_touch_active(tp, t) && t->dirty) {
nchanged++;
tp_get_delta(t, &tmpx, &tmpy);
dx += tmpx;
dy += tmpy;
}
/* Stop spurious MOTION events at the end of scrolling */
t->is_pointer = false;
}
if (nchanged == 0)
return;
dx /= nchanged;
dy /= nchanged;
tp_filter_motion(tp, &dx, &dy, NULL, NULL, time);
evdev_post_scroll(tp->device, time, dx, dy);
}
static int
tp_twofinger_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
int nfingers_down = 0;
/* No 2fg scrolling during tap-n-drag */
if (tp_tap_dragging(tp))
return 0;
/* Only count active touches for 2 finger scrolling */
tp_for_each_touch(tp, t) {
if (tp_touch_active(tp, t))
nfingers_down++;
}
if (nfingers_down != 2) {
evdev_stop_scroll(tp->device, time);
return 0;
}
tp_post_twofinger_scroll(tp, time);
return 1;
}
static void
tp_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
{
/* Note this must be always called, so that it knows the state of
* touches when the scroll-mode changes.
*/
tp_edge_scroll_handle_state(tp, time);
}
static int
tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
{
struct libinput *libinput = tp->device->base.seat->libinput;
switch (tp->scroll.method) {
case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
break;
case LIBINPUT_CONFIG_SCROLL_2FG:
return tp_twofinger_scroll_post_events(tp, time);
case LIBINPUT_CONFIG_SCROLL_EDGE:
return tp_edge_scroll_post_events(tp, time);
case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
log_bug_libinput(libinput, "Unexpected scroll mode\n");
break;
}
return 0;
}
static void
tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
{
struct libinput *libinput = tp->device->base.seat->libinput;
switch (tp->scroll.method) {
case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
break;
case LIBINPUT_CONFIG_SCROLL_2FG:
evdev_stop_scroll(tp->device, time);
break;
case LIBINPUT_CONFIG_SCROLL_EDGE:
tp_edge_scroll_stop_events(tp, time);
break;
case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
log_bug_libinput(libinput, "Unexpected scroll mode\n");
break;
}
}
static void
tp_destroy_scroll(struct tp_dispatch *tp)
{
tp_destroy_edge_scroll(tp);
}
static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
@ -430,6 +550,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
}
tp_button_handle_state(tp, time);
tp_scroll_handle_state(tp, time);
/*
* We have a physical button down event on a clickpad. To avoid
@ -465,63 +586,14 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
tp->queued = TOUCHPAD_EVENT_NONE;
}
static void
tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
int nchanged = 0;
double dx = 0, dy =0;
double tmpx, tmpy;
tp_for_each_touch(tp, t) {
if (tp_touch_active(tp, t) && t->dirty) {
nchanged++;
tp_get_delta(t, &tmpx, &tmpy);
dx += tmpx;
dy += tmpy;
}
/* Stop spurious MOTION events at the end of scrolling */
t->is_pointer = false;
}
if (nchanged == 0)
return;
dx /= nchanged;
dy /= nchanged;
tp_filter_motion(tp, &dx, &dy, time);
evdev_post_scroll(tp->device, time, dx, dy);
}
static int
tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
int nfingers_down = 0;
/* Only count active touches for 2 finger scrolling */
tp_for_each_touch(tp, t) {
if (tp_touch_active(tp, t))
nfingers_down++;
}
if (nfingers_down != 2) {
evdev_stop_scroll(tp->device, time);
return 0;
}
tp_post_twofinger_scroll(tp, time);
return 1;
}
static void
tp_post_events(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t = tp_current_touch(tp);
double dx, dy;
int consumed = 0;
int filter_motion = 0;
double dx_unaccel, dy_unaccel;
/* Only post (top) button events while suspended */
if (tp->device->suspended) {
@ -529,11 +601,11 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
return;
}
consumed |= tp_tap_handle_state(tp, time);
consumed |= tp_post_button_events(tp, time);
filter_motion |= tp_tap_handle_state(tp, time);
filter_motion |= tp_post_button_events(tp, time);
if (consumed) {
evdev_stop_scroll(tp->device, time);
if (filter_motion || tp->sendevents.trackpoint_active) {
tp_stop_scroll_events(tp, time);
return;
}
@ -553,10 +625,12 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
return;
tp_get_delta(t, &dx, &dy);
tp_filter_motion(tp, &dx, &dy, time);
tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time);
if (dx != 0.0 || dy != 0.0)
pointer_notify_motion(&tp->device->base, time, dx, dy);
if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) {
pointer_notify_motion(&tp->device->base, time,
dx, dy, dx_unaccel, dy_unaccel);
}
}
static void
@ -593,6 +667,16 @@ tp_process(struct evdev_dispatch *dispatch,
}
}
static void
tp_destroy_sendevents(struct tp_dispatch *tp)
{
libinput_timer_cancel(&tp->sendevents.trackpoint_timer);
if (tp->buttons.trackpoint)
libinput_device_remove_event_listener(
&tp->sendevents.trackpoint_listener);
}
static void
tp_destroy(struct evdev_dispatch *dispatch)
{
@ -601,14 +685,15 @@ tp_destroy(struct evdev_dispatch *dispatch)
tp_destroy_tap(tp);
tp_destroy_buttons(tp);
tp_destroy_sendevents(tp);
tp_destroy_scroll(tp);
filter_destroy(tp->filter);
free(tp->touches);
free(tp);
}
static void
tp_clear_state(struct tp_dispatch *tp, struct evdev_device *device)
tp_clear_state(struct tp_dispatch *tp)
{
uint64_t now = libinput_now(tp->device->base.seat->libinput);
struct tp_touch *t;
@ -637,7 +722,7 @@ tp_clear_state(struct tp_dispatch *tp, struct evdev_device *device)
static void
tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
{
tp_clear_state(tp, device);
tp_clear_state(tp);
/* On devices with top softwarebuttons we don't actually suspend the
* device, to keep the "trackpoint" buttons working. tp_post_events()
@ -657,7 +742,7 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
{
if (tp->buttons.has_topbuttons) {
/* tap state-machine is offline while suspended, reset state */
tp_clear_state(tp, device);
tp_clear_state(tp);
/* restore original topbutton area size */
tp_init_softbuttons(tp, device, 1.0);
evdev_notify_resumed_device(device);
@ -666,6 +751,35 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
}
}
static void
tp_trackpoint_timeout(uint64_t now, void *data)
{
struct tp_dispatch *tp = data;
tp_tap_resume(tp, now);
tp->sendevents.trackpoint_active = false;
}
static void
tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data)
{
struct tp_dispatch *tp = data;
/* Buttons do not count as trackpad activity, as people may use
the trackpoint buttons in combination with the touchpad. */
if (event->type == LIBINPUT_EVENT_POINTER_BUTTON)
return;
if (!tp->sendevents.trackpoint_active) {
evdev_stop_scroll(tp->device, time);
tp_tap_suspend(tp, time);
tp->sendevents.trackpoint_active = true;
}
libinput_timer_set(&tp->sendevents.trackpoint_timer,
time + DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT);
}
static void
tp_device_added(struct evdev_device *device,
struct evdev_device *added_device)
@ -677,6 +791,9 @@ tp_device_added(struct evdev_device *device,
/* Don't send any pending releases to the new trackpoint */
tp->buttons.active_is_topbutton = false;
tp->buttons.trackpoint = added_device;
libinput_device_add_event_listener(&added_device->base,
&tp->sendevents.trackpoint_listener,
tp_trackpoint_event, tp);
}
if (tp->sendevents.current_mode !=
@ -700,6 +817,8 @@ tp_device_removed(struct evdev_device *device,
tp->buttons.active = 0;
tp->buttons.active_is_topbutton = false;
}
libinput_device_remove_event_listener(
&tp->sendevents.trackpoint_listener);
tp->buttons.trackpoint = NULL;
}
@ -807,7 +926,6 @@ tp_init_slots(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) {
@ -824,17 +942,27 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
/*
* 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
* Normalize motion events to the default mouse 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;
tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
/* FIXME: once normalized, touchpads see the same
acceleration as mice. that is technically correct but
subjectively wrong, we expect a touchpad to be a lot
slower than a mouse.
For now, apply a magic factor here until this is
fixed in the actual filter code.
*/
{
const double MAGIC = 0.4;
tp->accel.x_scale_coeff *= MAGIC;
tp->accel.y_scale_coeff *= MAGIC;
}
} else {
/*
* For touchpads where the driver does not provide resolution, fall
@ -844,12 +972,88 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
}
accel = create_pointer_accelator_filter(
pointer_accel_profile_smooth_simple);
if (accel == NULL)
if (evdev_device_init_pointer_acceleration(tp->device) == -1)
return -1;
tp->filter = accel;
return 0;
}
static uint32_t
tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
uint32_t methods = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
if (tp->ntouches >= 2)
methods |= LIBINPUT_CONFIG_SCROLL_2FG;
if (!tp->buttons.is_clickpad)
methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
return methods;
}
static enum libinput_config_status
tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
enum libinput_config_scroll_method method)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
if (method == tp->scroll.method)
return LIBINPUT_CONFIG_STATUS_SUCCESS;
tp_stop_scroll_events(tp, libinput_now(device->seat->libinput));
tp->scroll.method = method;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
static enum libinput_config_scroll_method
tp_scroll_config_scroll_method_get_method(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp->scroll.method;
}
static enum libinput_config_scroll_method
tp_scroll_get_default_method(struct tp_dispatch *tp)
{
if (tp->ntouches >= 2)
return LIBINPUT_CONFIG_SCROLL_2FG;
else
return LIBINPUT_CONFIG_SCROLL_EDGE;
}
static enum libinput_config_scroll_method
tp_scroll_config_scroll_method_get_default_method(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp_scroll_get_default_method(tp);
}
static int
tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
{
if (tp_edge_scroll_init(tp, device) != 0)
return -1;
evdev_init_natural_scroll(device);
tp->scroll.config_method.get_methods = tp_scroll_config_scroll_method_get_methods;
tp->scroll.config_method.set_method = tp_scroll_config_scroll_method_set_method;
tp->scroll.config_method.get_method = tp_scroll_config_scroll_method_get_method;
tp->scroll.config_method.get_default_method = tp_scroll_config_scroll_method_get_default_method;
tp->scroll.method = tp_scroll_get_default_method(tp);
tp->device->base.config.scroll_method = &tp->scroll.config_method;
/* In mm for touchpads with valid resolution, see tp_init_accel() */
tp->device->scroll.threshold = 5.0;
return 0;
}
@ -885,6 +1089,16 @@ tp_init_palmdetect(struct tp_dispatch *tp,
return 0;
}
static int
tp_init_sendevents(struct tp_dispatch *tp,
struct evdev_device *device)
{
libinput_timer_init(&tp->sendevents.trackpoint_timer,
tp->device->base.seat->libinput,
tp_trackpoint_timeout, tp);
return 0;
}
static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
@ -921,6 +1135,12 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_palmdetect(tp, device) != 0)
return -1;
if (tp_init_sendevents(tp, device) != 0)
return -1;
if (tp_init_scroll(tp, device) != 0)
return -1;
device->seat_caps |= EVDEV_DEVICE_POINTER;
return 0;
@ -930,8 +1150,7 @@ static uint32_t
tp_sendevents_get_modes(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED |
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
@ -961,6 +1180,11 @@ tp_sendevents_set_mode(struct libinput_device *device,
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
/* DISABLED overrides any DISABLED_ON_ */
if ((mode & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED) &&
(mode & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE))
mode &= ~LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
if (mode == tp->sendevents.current_mode)
return LIBINPUT_CONFIG_STATUS_SUCCESS;
@ -998,6 +1222,57 @@ tp_sendevents_get_default_mode(struct libinput_device *device)
return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}
static void
tp_change_to_left_handed(struct evdev_device *device)
{
struct tp_dispatch *tp = (struct tp_dispatch *)device->dispatch;
if (device->buttons.want_left_handed == device->buttons.left_handed)
return;
if (tp->buttons.state & 0x3) /* BTN_LEFT|BTN_RIGHT */
return;
/* tapping and clickfinger aren't affected by left-handed config,
* so checking physical buttons is enough */
device->buttons.left_handed = device->buttons.want_left_handed;
}
struct model_lookup_t {
uint16_t vendor;
uint16_t product_start;
uint16_t product_end;
enum touchpad_model model;
};
static struct model_lookup_t model_lookup_table[] = {
{ 0x0002, 0x0007, 0x0007, MODEL_SYNAPTICS },
{ 0x0002, 0x0008, 0x0008, MODEL_ALPS },
{ 0x0002, 0x000e, 0x000e, MODEL_ELANTECH },
{ 0x05ac, 0, 0x0222, MODEL_APPLETOUCH },
{ 0x05ac, 0x0223, 0x0228, MODEL_UNIBODY_MACBOOK },
{ 0x05ac, 0x0229, 0x022b, MODEL_APPLETOUCH },
{ 0x05ac, 0x022c, 0xffff, MODEL_UNIBODY_MACBOOK },
{ 0, 0, 0, 0 }
};
static enum touchpad_model
tp_get_model(struct evdev_device *device)
{
struct model_lookup_t *lookup;
uint16_t vendor = libevdev_get_id_vendor(device->evdev);
uint16_t product = libevdev_get_id_product(device->evdev);
for (lookup = model_lookup_table; lookup->vendor; lookup++) {
if (lookup->vendor == vendor &&
lookup->product_start <= product &&
product <= lookup->product_end)
return lookup->model;
}
return MODEL_UNKNOWN;
}
struct evdev_dispatch *
evdev_mt_touchpad_create(struct evdev_device *device)
{
@ -1007,6 +1282,8 @@ evdev_mt_touchpad_create(struct evdev_device *device)
if (!tp)
return NULL;
tp->model = tp_get_model(device);
if (tp_init(tp, device) != 0) {
tp_destroy(&tp->base);
return NULL;
@ -1020,5 +1297,7 @@ evdev_mt_touchpad_create(struct evdev_device *device)
tp->sendevents.config.get_mode = tp_sendevents_get_mode;
tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;
evdev_init_left_handed(device, tp_change_to_left_handed);
return &tp->base;
}

View file

@ -42,6 +42,15 @@ enum touchpad_event {
TOUCHPAD_EVENT_BUTTON_RELEASE = (1 << 2),
};
enum touchpad_model {
MODEL_UNKNOWN = 0,
MODEL_SYNAPTICS,
MODEL_ALPS,
MODEL_APPLETOUCH,
MODEL_ELANTECH,
MODEL_UNIBODY_MACBOOK
};
enum touch_state {
TOUCH_NONE = 0,
TOUCH_BEGIN,
@ -94,6 +103,20 @@ enum tp_tap_touch_state {
TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */
};
/* For edge scrolling, so we only care about right and bottom */
enum tp_edge {
EDGE_NONE = 0,
EDGE_RIGHT = (1 << 0),
EDGE_BOTTOM = (1 << 1),
};
enum tp_edge_scroll_touch_state {
EDGE_SCROLL_TOUCH_STATE_NONE,
EDGE_SCROLL_TOUCH_STATE_EDGE_NEW,
EDGE_SCROLL_TOUCH_STATE_EDGE,
EDGE_SCROLL_TOUCH_STATE_AREA,
};
struct tp_motion {
int32_t x;
int32_t y;
@ -141,6 +164,14 @@ struct tp_touch {
enum tp_tap_touch_state state;
} tap;
struct {
enum tp_edge_scroll_touch_state state;
uint32_t edge;
int direction;
double threshold;
struct libinput_timer timer;
} scroll;
struct {
bool is_palm;
int32_t x, y; /* first coordinates if is_palm == true */
@ -156,6 +187,7 @@ struct tp_dispatch {
unsigned int slot; /* current slot */
bool has_mt;
bool semi_mt;
enum touchpad_model model;
unsigned int real_touches; /* number of slots */
unsigned int ntouches; /* no slots inc. fakes */
@ -167,8 +199,6 @@ struct tp_dispatch {
int32_t margin_y;
} hysteresis;
struct motion_filter *filter;
struct {
double x_scale_coeff;
double y_scale_coeff;
@ -203,13 +233,22 @@ struct tp_dispatch {
struct evdev_device *trackpoint;
} buttons; /* physical buttons */
struct {
struct libinput_device_config_scroll_method config_method;
enum libinput_config_scroll_method method;
int32_t right_edge;
int32_t bottom_edge;
} scroll;
enum touchpad_event queued;
struct {
struct libinput_device_config_tap config;
bool enabled;
bool suspended;
struct libinput_timer timer;
enum tp_tap_state state;
uint32_t buttons_pressed;
} tap;
struct {
@ -220,6 +259,9 @@ struct tp_dispatch {
struct {
struct libinput_device_config_send_events config;
enum libinput_config_send_events_mode current_mode;
bool trackpoint_active;
struct libinput_event_listener trackpoint_listener;
struct libinput_timer trackpoint_timer;
} sendevents;
};
@ -232,6 +274,12 @@ tp_get_delta(struct tp_touch *t, double *dx, double *dy);
void
tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t);
void
tp_filter_motion(struct tp_dispatch *tp,
double *dx, double *dy,
double *dx_unaccel, double *dy_unaccel,
uint64_t time);
int
tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
@ -277,4 +325,31 @@ void
tp_release_all_taps(struct tp_dispatch *tp,
uint64_t time);
void
tp_tap_suspend(struct tp_dispatch *tp, uint64_t time);
void
tp_tap_resume(struct tp_dispatch *tp, uint64_t time);
bool
tp_tap_dragging(struct tp_dispatch *tp);
int
tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device);
void
tp_destroy_edge_scroll(struct tp_dispatch *tp);
void
tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time);
int
tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time);
void
tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time);
int
tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
#endif

File diff suppressed because it is too large Load diff

View file

@ -69,11 +69,10 @@ struct evdev_device {
struct evdev_dispatch *dispatch;
struct libevdev *evdev;
struct udev_device *udev_device;
char *output_name;
char *devnode;
char *sysname;
char *syspath;
const char *devname;
bool was_removed;
int fd;
struct {
const struct input_absinfo *absinfo_x, *absinfo_y;
@ -101,10 +100,26 @@ struct evdev_device {
struct {
struct libinput_timer timer;
bool has_middle_button_scroll;
bool middle_button_scroll_active;
struct libinput_device_config_scroll_method config;
/* Currently enabled method, button */
enum libinput_config_scroll_method method;
uint32_t button;
/* set during device init, used at runtime to delay changes
* until all buttons are up */
enum libinput_config_scroll_method want_method;
uint32_t want_button;
/* Checks if buttons are down and commits the setting */
void (*change_scroll_method)(struct evdev_device *device);
bool button_scroll_active;
double threshold;
uint32_t direction;
double buildup_vertical;
double buildup_horizontal;
struct libinput_device_config_natural_scroll config_natural;
/* set during device init if we want natural scrolling,
* used at runtime to enable/disable the feature */
bool natural_scrolling_enabled;
} scroll;
enum evdev_event_type pending_event;
@ -115,6 +130,7 @@ struct evdev_device {
int suspended;
struct {
struct libinput_device_config_accel config;
struct motion_filter *filter;
} pointer;
@ -124,6 +140,20 @@ struct evdev_device {
/* Key counter used for multiplexing button events internally in
* libinput. */
uint8_t key_count[KEY_CNT];
struct {
struct libinput_device_config_left_handed config_left_handed;
/* left-handed currently enabled */
bool left_handed;
/* set during device init if we want left_handed config,
* used at runtime to delay the effect until buttons are up */
bool want_left_handed;
/* Checks if buttons are down and commits the setting */
void (*change_to_left_handed)(struct evdev_device *device);
} buttons;
int dpi; /* HW resolution */
struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
};
#define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
@ -173,9 +203,10 @@ struct evdev_dispatch {
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
const char *devnode,
const char *sysname,
const char *syspath);
struct udev_device *device);
int
evdev_device_init_pointer_acceleration(struct evdev_device *device);
struct evdev_dispatch *
evdev_touchpad_create(struct evdev_device *device);
@ -207,6 +238,9 @@ evdev_device_get_id_product(struct evdev_device *device);
unsigned int
evdev_device_get_id_vendor(struct evdev_device *device);
struct udev_device *
evdev_device_get_udev_device(struct evdev_device *device);
void
evdev_device_set_default_calibration(struct evdev_device *device,
const float calibration[6]);
@ -223,6 +257,9 @@ evdev_device_get_size(struct evdev_device *device,
double *w,
double *h);
int
evdev_device_has_button(struct evdev_device *device, uint32_t code);
double
evdev_device_transform_x(struct evdev_device *device,
double x,
@ -256,6 +293,9 @@ evdev_pointer_notify_button(struct evdev_device *device,
int button,
enum libinput_button_state state);
void
evdev_init_natural_scroll(struct evdev_device *device);
void
evdev_post_scroll(struct evdev_device *device,
uint64_t time,
@ -279,4 +319,21 @@ evdev_convert_to_mm(const struct input_absinfo *absinfo, double v)
return value/absinfo->resolution;
}
int
evdev_init_left_handed(struct evdev_device *device,
void (*change_to_left_handed)(struct evdev_device *));
static inline uint32_t
evdev_to_left_handed(struct evdev_device *device,
uint32_t button)
{
if (device->buttons.left_handed) {
if (button == BTN_LEFT)
return BTN_RIGHT;
else if (button == BTN_RIGHT)
return BTN_LEFT;
}
return button;
}
#endif /* EVDEV_H */

45
src/filter-private.h Normal file
View file

@ -0,0 +1,45 @@
/*
* Copyright © 2012 Jonas Ådahl
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef FILTER_PRIVATE_H
#define FILTER_PRIVATE_H
#include "config.h"
#include "filter.h"
struct motion_filter_interface {
void (*filter)(struct motion_filter *filter,
struct motion_params *motion,
void *data, uint64_t time);
void (*destroy)(struct motion_filter *filter);
bool (*set_speed)(struct motion_filter *filter,
double speed);
};
struct motion_filter {
double speed; /* normalized [-1, 1] */
struct motion_filter_interface *interface;
};
#endif

View file

@ -22,6 +22,7 @@
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -30,6 +31,7 @@
#include "filter.h"
#include "libinput-util.h"
#include "filter-private.h"
void
filter_dispatch(struct motion_filter *filter,
@ -48,12 +50,26 @@ filter_destroy(struct motion_filter *filter)
filter->interface->destroy(filter);
}
bool
filter_set_speed(struct motion_filter *filter,
double speed)
{
return filter->interface->set_speed(filter, speed);
}
double
filter_get_speed(struct motion_filter *filter)
{
return filter->speed;
}
/*
* Default parameters for pointer acceleration profiles.
*/
#define DEFAULT_THRESHOLD 0.4 /* in units/ms */
#define DEFAULT_ACCELERATION 2.0 /* unitless factor */
#define DEFAULT_INCLINE 1.1 /* unitless factor */
/*
* Pointer acceleration filter constants
@ -83,6 +99,10 @@ struct pointer_accelerator {
struct pointer_tracker *trackers;
int cur_tracker;
double threshold; /* units/ms */
double accel; /* unitless factor */
double incline; /* incline of the function */
};
static void
@ -119,8 +139,8 @@ tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset)
static double
calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time)
{
int dx;
int dy;
double dx;
double dy;
double distance;
dx = tracker->dx;
@ -233,13 +253,36 @@ accelerator_destroy(struct motion_filter *filter)
free(accel);
}
static bool
accelerator_set_speed(struct motion_filter *filter,
double speed)
{
struct pointer_accelerator *accel_filter =
(struct pointer_accelerator *)filter;
assert(speed >= -1.0 && speed <= 1.0);
/* delay when accel kicks in */
accel_filter->threshold = DEFAULT_THRESHOLD - speed/6.0;
/* adjust max accel factor */
accel_filter->accel = DEFAULT_ACCELERATION + speed;
/* higher speed -> faster to reach max */
accel_filter->incline = DEFAULT_INCLINE + speed/2.0;
filter->speed = speed;
return true;
}
struct motion_filter_interface accelerator_interface = {
accelerator_filter,
accelerator_destroy
accelerator_destroy,
accelerator_set_speed,
};
struct motion_filter *
create_pointer_accelator_filter(accel_profile_func_t profile)
create_pointer_accelerator_filter(accel_profile_func_t profile)
{
struct pointer_accelerator *filter;
@ -258,6 +301,10 @@ create_pointer_accelator_filter(accel_profile_func_t profile)
calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
filter->cur_tracker = 0;
filter->threshold = DEFAULT_THRESHOLD;
filter->accel = DEFAULT_ACCELERATION;
filter->incline = DEFAULT_INCLINE;
return &filter->base;
}
@ -270,41 +317,21 @@ calc_penumbral_gradient(double x)
}
double
pointer_accel_profile_smooth_simple(struct motion_filter *filter,
void *data,
double velocity, /* units/ms */
uint64_t time)
pointer_accel_profile_linear(struct motion_filter *filter,
void *data,
double speed_in,
uint64_t time)
{
double threshold = DEFAULT_THRESHOLD; /* units/ms */
double accel = DEFAULT_ACCELERATION; /* unitless factor */
double smooth_accel_coefficient; /* unitless factor */
double factor; /* unitless factor */
struct pointer_accelerator *accel_filter =
(struct pointer_accelerator *)filter;
if (threshold < 0.1)
threshold = 0.1;
if (accel < 1.0)
accel = 1.0;
double s1, s2;
const double max_accel = accel_filter->accel; /* unitless factor */
const double threshold = accel_filter->threshold; /* units/ms */
const double incline = accel_filter->incline;
/* 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;
s1 = min(1, speed_in * 5);
s2 = 1 + (speed_in - threshold) * incline;
if (velocity <= threshold)
return 1.0;
factor = velocity/threshold;
if (factor >= accel)
return accel;
/* 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));
return min(max_accel, s2 > 1 ? s2 : s1);
}

View file

@ -25,10 +25,14 @@
#include "config.h"
#include <stdbool.h>
#include <stdint.h>
/* The HW DPI rate we normalize to before calculating pointer acceleration */
#define DEFAULT_MOUSE_DPI 1000
struct motion_params {
double dx, dy; /* in units/ms @ 400dpi */
double dx, dy; /* in units/ms @ DEFAULT_MOUSE_DPI resolution */
};
struct motion_filter;
@ -40,17 +44,11 @@ filter_dispatch(struct motion_filter *filter,
void
filter_destroy(struct motion_filter *filter);
struct motion_filter_interface {
void (*filter)(struct motion_filter *filter,
struct motion_params *motion,
void *data, uint64_t time);
void (*destroy)(struct motion_filter *filter);
};
struct motion_filter {
struct motion_filter_interface *interface;
};
bool
filter_set_speed(struct motion_filter *filter,
double speed);
double
filter_get_speed(struct motion_filter *filter);
typedef double (*accel_profile_func_t)(struct motion_filter *filter,
void *data,
@ -58,21 +56,16 @@ typedef double (*accel_profile_func_t)(struct motion_filter *filter,
uint64_t time);
struct motion_filter *
create_pointer_accelator_filter(accel_profile_func_t filter);
create_pointer_accelerator_filter(accel_profile_func_t filter);
/*
* Pointer acceleration profiles.
*/
/*
* Profile similar which is similar to nonaccelerated but with a smooth
* transition between accelerated and non-accelerated.
*/
double
pointer_accel_profile_smooth_simple(struct motion_filter *filter,
void *data,
double velocity,
uint64_t time);
pointer_accel_profile_linear(struct motion_filter *filter,
void *data,
double speed_in,
uint64_t time);
#endif /* FILTER_H */

View file

@ -36,6 +36,8 @@ struct libinput_interface_backend {
int (*resume)(struct libinput *libinput);
void (*suspend)(struct libinput *libinput);
void (*destroy)(struct libinput *libinput);
int (*device_change_seat)(struct libinput_device *device,
const char *seat_name);
};
struct libinput {
@ -111,17 +113,56 @@ struct libinput_device_config_send_events {
enum libinput_config_send_events_mode (*get_default_mode)(struct libinput_device *device);
};
struct libinput_device_config_accel {
int (*available)(struct libinput_device *device);
enum libinput_config_status (*set_speed)(struct libinput_device *device,
double speed);
double (*get_speed)(struct libinput_device *device);
double (*get_default_speed)(struct libinput_device *device);
};
struct libinput_device_config_natural_scroll {
int (*has)(struct libinput_device *device);
enum libinput_config_status (*set_enabled)(struct libinput_device *device,
int enabled);
int (*get_enabled)(struct libinput_device *device);
int (*get_default_enabled)(struct libinput_device *device);
};
struct libinput_device_config_left_handed {
int (*has)(struct libinput_device *device);
enum libinput_config_status (*set)(struct libinput_device *device, int left_handed);
int (*get)(struct libinput_device *device);
int (*get_default)(struct libinput_device *device);
};
struct libinput_device_config_scroll_method {
uint32_t (*get_methods)(struct libinput_device *device);
enum libinput_config_status (*set_method)(struct libinput_device *device,
enum libinput_config_scroll_method method);
enum libinput_config_scroll_method (*get_method)(struct libinput_device *device);
enum libinput_config_scroll_method (*get_default_method)(struct libinput_device *device);
enum libinput_config_status (*set_button)(struct libinput_device *device,
uint32_t button);
uint32_t (*get_button)(struct libinput_device *device);
uint32_t (*get_default_button)(struct libinput_device *device);
};
struct libinput_device_config {
struct libinput_device_config_tap *tap;
struct libinput_device_config_calibration *calibration;
struct libinput_device_config_send_events *sendevents;
struct libinput_device_config_accel *accel;
struct libinput_device_config_natural_scroll *natural_scroll;
struct libinput_device_config_left_handed *left_handed;
struct libinput_device_config_scroll_method *scroll_method;
};
struct libinput_device {
struct libinput_seat *seat;
struct list link;
struct list event_listeners;
void *user_data;
int terminated;
int refcount;
struct libinput_device_config config;
};
@ -135,6 +176,17 @@ struct libinput_tool {
void *user_data;
};
struct libinput_event {
enum libinput_event_type type;
struct libinput_device *device;
};
struct libinput_event_listener {
struct list link;
void (*notify_func)(uint64_t time, struct libinput_event *ev, void *notify_func_data);
void *notify_func_data;
};
typedef void (*libinput_source_dispatch_t)(void *data);
@ -190,6 +242,18 @@ void
libinput_device_init(struct libinput_device *device,
struct libinput_seat *seat);
void
libinput_device_add_event_listener(struct libinput_device *device,
struct libinput_event_listener *listener,
void (*notify_func)(
uint64_t time,
struct libinput_event *event,
void *notify_func_data),
void *notify_func_data);
void
libinput_device_remove_event_listener(struct libinput_event_listener *listener);
void
notify_added_device(struct libinput_device *device);
@ -198,37 +262,39 @@ notify_removed_device(struct libinput_device *device);
void
keyboard_notify_key(struct libinput_device *device,
uint32_t time,
uint64_t time,
uint32_t key,
enum libinput_key_state state);
void
pointer_notify_motion(struct libinput_device *device,
uint32_t time,
uint64_t time,
double dx,
double dy);
double dy,
double dx_noaccel,
double dy_noaccel);
void
pointer_notify_motion_absolute(struct libinput_device *device,
uint32_t time,
uint64_t time,
double x,
double y);
void
pointer_notify_button(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t button,
enum libinput_button_state state);
void
pointer_notify_axis(struct libinput_device *device,
uint32_t time,
uint64_t time,
enum libinput_pointer_axis axis,
double value);
void
touch_notify_touch_down(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t slot,
int32_t seat_slot,
double x,
@ -236,7 +302,7 @@ touch_notify_touch_down(struct libinput_device *device,
void
touch_notify_touch_motion(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t slot,
int32_t seat_slot,
double x,
@ -244,7 +310,7 @@ touch_notify_touch_motion(struct libinput_device *device,
void
touch_notify_touch_up(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t slot,
int32_t seat_slot);
@ -276,7 +342,7 @@ tablet_notify_button(struct libinput_device *device,
enum libinput_button_state state);
void
touch_notify_frame(struct libinput_device *device,
uint32_t time);
uint64_t time);
static inline uint64_t
libinput_now(struct libinput *libinput)

View file

@ -28,7 +28,9 @@
#include "config.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -65,3 +67,104 @@ list_empty(const struct list *list)
{
return list->next == list;
}
void
ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst)
{
r->interval = ival_ms;
r->begin = 0;
r->burst = burst;
r->num = 0;
}
/*
* Perform rate-limit test. Returns RATELIMIT_PASS if the rate-limited action
* is still allowed, RATELIMIT_THRESHOLD if the limit has been reached with
* this call, and RATELIMIT_EXCEEDED if you're beyond the threshold.
* It's safe to treat the return-value as boolean, if you're not interested in
* the exact state. It evaluates to "true" if the threshold hasn't been
* exceeded, yet.
*
* The ratelimit object must be initialized via ratelimit_init().
*
* Modelled after Linux' lib/ratelimit.c by Dave Young
* <hidave.darkstar@gmail.com>, which is licensed GPLv2.
*/
enum ratelimit_state
ratelimit_test(struct ratelimit *r)
{
struct timespec ts;
uint64_t mtime;
if (r->interval <= 0 || r->burst <= 0)
return RATELIMIT_PASS;
clock_gettime(CLOCK_MONOTONIC, &ts);
mtime = ts.tv_sec * 1000 + ts.tv_nsec / 1000 / 1000;
if (r->begin <= 0 || r->begin + r->interval < mtime) {
/* reset counter */
r->begin = mtime;
r->num = 1;
return RATELIMIT_PASS;
} else if (r->num < r->burst) {
/* continue burst */
return (++r->num == r->burst) ? RATELIMIT_THRESHOLD
: RATELIMIT_PASS;
}
return RATELIMIT_EXCEEDED;
}
/* Helper function to parse the mouse DPI tag from udev.
* The tag is of the form:
* MOUSE_DPI=400 *1000 2000
* or
* MOUSE_DPI=400@125 *1000@125 2000@125
* Where the * indicates the default value and @number indicates device poll
* rate.
* Numbers should be in ascending order, and if rates are present they should
* be present for all entries.
*
* When parsing the mouse DPI property, if we find an error we just return 0
* since it's obviously invalid, the caller will treat that as an error and
* use a reasonable default instead. If the property contains multiple DPI
* settings but none flagged as default, we return the last because we're
* lazy and that's a silly way to set the property anyway.
*/
int
parse_mouse_dpi_property(const char *prop)
{
bool is_default = false;
int nread, dpi = 0, rate;
while (*prop != 0) {
if (*prop == ' ') {
prop++;
continue;
}
if (*prop == '*') {
prop++;
is_default = true;
if (!isdigit(prop[0]))
return 0;
}
/* While we don't do anything with the rate right now we
* will validate that, if it's present, it is non-zero and
* positive
*/
rate = 1;
nread = 0;
sscanf(prop, "%d@%d%n", &dpi, &rate, &nread);
if (!nread)
sscanf(prop, "%d%n", &dpi, &nread);
if (!nread || dpi <= 0 || rate <= 0 || prop[nread] == '@')
return 0;
if (is_default)
break;
prop += nread;
}
return dpi;
}

View file

@ -304,4 +304,22 @@ matrix_to_farray6(const struct matrix *m, float out[6])
out[5] = m->val[1][2];
}
enum ratelimit_state {
RATELIMIT_EXCEEDED,
RATELIMIT_THRESHOLD,
RATELIMIT_PASS,
};
struct ratelimit {
uint64_t interval;
uint64_t begin;
unsigned int burst;
unsigned int num;
};
void ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst);
enum ratelimit_state ratelimit_test(struct ratelimit *r);
int parse_mouse_dpi_property(const char *prop);
#endif /* LIBINPUT_UTIL_H */

View file

@ -42,11 +42,6 @@ struct libinput_source {
struct list link;
};
struct libinput_event {
enum libinput_event_type type;
struct libinput_device *device;
};
struct libinput_event_device_notify {
struct libinput_event base;
};
@ -64,6 +59,8 @@ struct libinput_event_pointer {
uint32_t time;
double x;
double y;
double dx_unaccel;
double dy_unaccel;
uint32_t button;
uint32_t seat_button_count;
enum libinput_button_state state;
@ -365,6 +362,20 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event)
return event->y;
}
LIBINPUT_EXPORT double
libinput_event_pointer_get_dx_unaccelerated(
struct libinput_event_pointer *event)
{
return event->dx_unaccel;
}
LIBINPUT_EXPORT double
libinput_event_pointer_get_dy_unaccelerated(
struct libinput_event_pointer *event)
{
return event->dy_unaccel;
}
LIBINPUT_EXPORT double
libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event)
{
@ -867,6 +878,12 @@ libinput_seat_get_user_data(struct libinput_seat *seat)
return seat->user_data;
}
LIBINPUT_EXPORT struct libinput *
libinput_seat_get_context(struct libinput_seat *seat)
{
return seat->libinput;
}
LIBINPUT_EXPORT const char *
libinput_seat_get_physical_name(struct libinput_seat *seat)
{
@ -885,6 +902,7 @@ libinput_device_init(struct libinput_device *device,
{
device->seat = seat;
device->refcount = 1;
list_init(&device->event_listeners);
}
LIBINPUT_EXPORT struct libinput_device *
@ -897,6 +915,7 @@ libinput_device_ref(struct libinput_device *device)
static void
libinput_device_destroy(struct libinput_device *device)
{
assert(list_empty(&device->event_listeners));
evdev_device_destroy((struct evdev_device *) device);
}
@ -943,6 +962,26 @@ libinput_dispatch(struct libinput *libinput)
return 0;
}
void
libinput_device_add_event_listener(struct libinput_device *device,
struct libinput_event_listener *listener,
void (*notify_func)(
uint64_t time,
struct libinput_event *event,
void *notify_func_data),
void *notify_func_data)
{
listener->notify_func = notify_func;
listener->notify_func_data = notify_func_data;
list_insert(&device->event_listeners, &listener->link);
}
void
libinput_device_remove_event_listener(struct libinput_event_listener *listener)
{
list_remove(&listener->link);
}
static uint32_t
update_seat_key_count(struct libinput_seat *seat,
int32_t key,
@ -1006,10 +1045,17 @@ post_base_event(struct libinput_device *device,
static void
post_device_event(struct libinput_device *device,
uint64_t time,
enum libinput_event_type type,
struct libinput_event *event)
{
struct libinput_event_listener *listener, *tmp;
init_event_base(event, device, type);
list_for_each_safe(listener, tmp, &device->event_listeners, link)
listener->notify_func(time, event, listener->notify_func_data);
libinput_post_event(device->seat->libinput, event);
}
@ -1043,7 +1089,7 @@ notify_removed_device(struct libinput_device *device)
void
keyboard_notify_key(struct libinput_device *device,
uint32_t time,
uint64_t time,
uint32_t key,
enum libinput_key_state state)
{
@ -1063,16 +1109,18 @@ keyboard_notify_key(struct libinput_device *device,
.seat_key_count = seat_key_count,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_KEYBOARD_KEY,
&key_event->base);
}
void
pointer_notify_motion(struct libinput_device *device,
uint32_t time,
uint64_t time,
double dx,
double dy)
double dy,
double dx_unaccel,
double dy_unaccel)
{
struct libinput_event_pointer *motion_event;
@ -1084,16 +1132,18 @@ pointer_notify_motion(struct libinput_device *device,
.time = time,
.x = dx,
.y = dy,
.dx_unaccel = dx_unaccel,
.dy_unaccel = dy_unaccel,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_POINTER_MOTION,
&motion_event->base);
}
void
pointer_notify_motion_absolute(struct libinput_device *device,
uint32_t time,
uint64_t time,
double x,
double y)
{
@ -1109,14 +1159,14 @@ pointer_notify_motion_absolute(struct libinput_device *device,
.y = y,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
&motion_absolute_event->base);
}
void
pointer_notify_button(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t button,
enum libinput_button_state state)
{
@ -1138,14 +1188,14 @@ pointer_notify_button(struct libinput_device *device,
.seat_button_count = seat_button_count,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_POINTER_BUTTON,
&button_event->base);
}
void
pointer_notify_axis(struct libinput_device *device,
uint32_t time,
uint64_t time,
enum libinput_pointer_axis axis,
double value)
{
@ -1161,14 +1211,14 @@ pointer_notify_axis(struct libinput_device *device,
.value = value,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_POINTER_AXIS,
&axis_event->base);
}
void
touch_notify_touch_down(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t slot,
int32_t seat_slot,
double x,
@ -1188,14 +1238,14 @@ touch_notify_touch_down(struct libinput_device *device,
.y = y,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_TOUCH_DOWN,
&touch_event->base);
}
void
touch_notify_touch_motion(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t slot,
int32_t seat_slot,
double x,
@ -1215,14 +1265,14 @@ touch_notify_touch_motion(struct libinput_device *device,
.y = y,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_TOUCH_MOTION,
&touch_event->base);
}
void
touch_notify_touch_up(struct libinput_device *device,
uint32_t time,
uint64_t time,
int32_t slot,
int32_t seat_slot)
{
@ -1238,14 +1288,14 @@ touch_notify_touch_up(struct libinput_device *device,
.seat_slot = seat_slot,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_TOUCH_UP,
&touch_event->base);
}
void
touch_notify_frame(struct libinput_device *device,
uint32_t time)
uint64_t time)
{
struct libinput_event_touch *touch_event;
@ -1257,7 +1307,7 @@ touch_notify_frame(struct libinput_device *device,
.time = time,
};
post_device_event(device,
post_device_event(device, time,
LIBINPUT_EVENT_TOUCH_FRAME,
&touch_event->base);
}
@ -1286,6 +1336,7 @@ tablet_notify_axis(struct libinput_device *device,
memcpy(axis_event->axes, axes, sizeof(axis_event->axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_AXIS,
&axis_event->base);
}
@ -1311,6 +1362,7 @@ tablet_notify_proximity_in(struct libinput_device *device,
sizeof(proximity_in_event->axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_PROXIMITY_IN,
&proximity_in_event->base);
}
@ -1336,6 +1388,7 @@ tablet_notify_proximity_out(struct libinput_device *device,
sizeof(proximity_out_update_event->axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_PROXIMITY_OUT,
&proximity_out_update_event->base);
}
@ -1369,6 +1422,7 @@ tablet_notify_button(struct libinput_device *device,
memcpy(button_event->axes, axes, sizeof(button_event->axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_BUTTON,
&button_event->base);
}
@ -1475,6 +1529,12 @@ libinput_device_get_user_data(struct libinput_device *device)
return device->user_data;
}
LIBINPUT_EXPORT struct libinput *
libinput_device_get_context(struct libinput_device *device)
{
return libinput_seat_get_context(device->seat);
}
LIBINPUT_EXPORT const char *
libinput_device_get_sysname(struct libinput_device *device)
{
@ -1511,6 +1571,25 @@ libinput_device_get_seat(struct libinput_device *device)
return device->seat;
}
LIBINPUT_EXPORT int
libinput_device_set_seat_logical_name(struct libinput_device *device,
const char *name)
{
struct libinput *libinput = device->seat->libinput;
if (name == NULL)
return -1;
return libinput->interface_backend->device_change_seat(device,
name);
}
LIBINPUT_EXPORT struct udev_device *
libinput_device_get_udev_device(struct libinput_device *device)
{
return evdev_device_get_udev_device((struct evdev_device *)device);
}
LIBINPUT_EXPORT void
libinput_device_led_update(struct libinput_device *device,
enum libinput_led leds)
@ -1552,6 +1631,12 @@ libinput_device_get_size(struct libinput_device *device,
height);
}
LIBINPUT_EXPORT int
libinput_device_has_button(struct libinput_device *device, uint32_t code)
{
return evdev_device_has_button((struct evdev_device *)device, code);
}
LIBINPUT_EXPORT struct libinput_event *
libinput_event_device_notify_get_base_event(struct libinput_event_device_notify *event)
{
@ -1685,9 +1770,9 @@ libinput_device_config_send_events_get_modes(struct libinput_device *device)
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_send_events_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode)
uint32_t mode)
{
if ((libinput_device_config_send_events_get_modes(device) & mode) == 0)
if ((libinput_device_config_send_events_get_modes(device) & mode) != mode)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
if (device->config.sendevents)
@ -1696,7 +1781,7 @@ libinput_device_config_send_events_set_mode(struct libinput_device *device,
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
LIBINPUT_EXPORT enum libinput_config_send_events_mode
LIBINPUT_EXPORT uint32_t
libinput_device_config_send_events_get_mode(struct libinput_device *device)
{
if (device->config.sendevents)
@ -1705,8 +1790,206 @@ libinput_device_config_send_events_get_mode(struct libinput_device *device)
return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}
LIBINPUT_EXPORT enum libinput_config_send_events_mode
LIBINPUT_EXPORT uint32_t
libinput_device_config_send_events_get_default_mode(struct libinput_device *device)
{
return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}
LIBINPUT_EXPORT int
libinput_device_config_accel_is_available(struct libinput_device *device)
{
return device->config.accel ?
device->config.accel->available(device) : 0;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_accel_set_speed(struct libinput_device *device,
double speed)
{
if (speed < -1.0 || speed > 1.0)
return LIBINPUT_CONFIG_STATUS_INVALID;
if (!libinput_device_config_accel_is_available(device))
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.accel->set_speed(device, speed);
}
LIBINPUT_EXPORT double
libinput_device_config_accel_get_speed(struct libinput_device *device)
{
if (!libinput_device_config_accel_is_available(device))
return 0;
return device->config.accel->get_speed(device);
}
LIBINPUT_EXPORT double
libinput_device_config_accel_get_default_speed(struct libinput_device *device)
{
if (!libinput_device_config_accel_is_available(device))
return 0;
return device->config.accel->get_default_speed(device);
}
LIBINPUT_EXPORT int
libinput_device_config_scroll_has_natural_scroll(struct libinput_device *device)
{
if (!device->config.natural_scroll)
return 0;
return device->config.natural_scroll->has(device);
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_scroll_set_natural_scroll_enabled(struct libinput_device *device,
int enabled)
{
if (!libinput_device_config_scroll_has_natural_scroll(device))
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.natural_scroll->set_enabled(device, enabled);
}
LIBINPUT_EXPORT int
libinput_device_config_scroll_get_natural_scroll_enabled(struct libinput_device *device)
{
if (!device->config.natural_scroll)
return 0;
return device->config.natural_scroll->get_enabled(device);
}
LIBINPUT_EXPORT int
libinput_device_config_scroll_get_default_natural_scroll_enabled(struct libinput_device *device)
{
if (!device->config.natural_scroll)
return 0;
return device->config.natural_scroll->get_default_enabled(device);
}
LIBINPUT_EXPORT int
libinput_device_config_buttons_has_left_handed(struct libinput_device *device)
{
if (!device->config.left_handed)
return 0;
return device->config.left_handed->has(device);
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_buttons_set_left_handed(struct libinput_device *device,
int left_handed)
{
if (!libinput_device_config_buttons_has_left_handed(device))
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.left_handed->set(device, left_handed);
}
LIBINPUT_EXPORT int
libinput_device_config_buttons_get_left_handed(struct libinput_device *device)
{
if (!libinput_device_config_buttons_has_left_handed(device))
return 0;
return device->config.left_handed->get(device);
}
LIBINPUT_EXPORT int
libinput_device_config_buttons_get_default_left_handed(struct libinput_device *device)
{
if (!libinput_device_config_buttons_has_left_handed(device))
return 0;
return device->config.left_handed->get_default(device);
}
LIBINPUT_EXPORT uint32_t
libinput_device_config_scroll_get_methods(struct libinput_device *device)
{
if (device->config.scroll_method)
return device->config.scroll_method->get_methods(device);
else
return 0;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_scroll_set_method(struct libinput_device *device,
enum libinput_config_scroll_method method)
{
/* Check method is a single valid method */
switch (method) {
case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
case LIBINPUT_CONFIG_SCROLL_2FG:
case LIBINPUT_CONFIG_SCROLL_EDGE:
case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
break;
default:
return LIBINPUT_CONFIG_STATUS_INVALID;
}
if ((libinput_device_config_scroll_get_methods(device) & method) != method)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
if (device->config.scroll_method)
return device->config.scroll_method->set_method(device, method);
else /* method must be _NO_SCROLL to get here */
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
LIBINPUT_EXPORT enum libinput_config_scroll_method
libinput_device_config_scroll_get_method(struct libinput_device *device)
{
if (device->config.scroll_method)
return device->config.scroll_method->get_method(device);
else
return LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
}
LIBINPUT_EXPORT enum libinput_config_scroll_method
libinput_device_config_scroll_get_default_method(struct libinput_device *device)
{
if (device->config.scroll_method)
return device->config.scroll_method->get_default_method(device);
else
return LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_scroll_set_button(struct libinput_device *device,
uint32_t button)
{
if (button && !libinput_device_has_button(device, button))
return LIBINPUT_CONFIG_STATUS_INVALID;
if ((libinput_device_config_scroll_get_methods(device) &
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.scroll_method->set_button(device, button);
}
LIBINPUT_EXPORT uint32_t
libinput_device_config_scroll_get_button(struct libinput_device *device)
{
if ((libinput_device_config_scroll_get_methods(device) &
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0)
return 0;
return device->config.scroll_method->get_button(device);
}
LIBINPUT_EXPORT uint32_t
libinput_device_config_scroll_get_default_button(struct libinput_device *device)
{
if ((libinput_device_config_scroll_get_methods(device) &
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0)
return 0;
return device->config.scroll_method->get_default_button(device);
}

File diff suppressed because it is too large Load diff

View file

@ -109,63 +109,34 @@ path_seat_get_named(struct path_input *input,
return NULL;
}
static int
path_get_udev_properties(const char *path,
char **sysname,
char **syspath,
char **seat_name,
char **seat_logical_name)
{
struct udev *udev = NULL;
struct udev_device *device = NULL;
struct stat st;
const char *seat;
int rc = -1;
udev = udev_new();
if (!udev)
goto out;
if (stat(path, &st) < 0)
goto out;
device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
if (!device)
goto out;
*sysname = strdup(udev_device_get_sysname(device));
*syspath = strdup(udev_device_get_syspath(device));
seat = udev_device_get_property_value(device, "ID_SEAT");
*seat_name = strdup(seat ? seat : default_seat);
seat = udev_device_get_property_value(device, "WL_SEAT");
*seat_logical_name = strdup(seat ? seat : default_seat_name);
rc = 0;
out:
if (device)
udev_device_unref(device);
if (udev)
udev_unref(udev);
return rc;
}
static struct libinput_device *
path_device_enable(struct path_input *input, const char *devnode)
path_device_enable(struct path_input *input,
struct udev_device *udev_device,
const char *seat_logical_name_override)
{
struct path_seat *seat;
struct evdev_device *device = NULL;
char *sysname = NULL, *syspath = NULL;
char *seat_name = NULL, *seat_logical_name = NULL;
const char *seat_prop;
const char *devnode;
if (path_get_udev_properties(devnode, &sysname, &syspath,
&seat_name, &seat_logical_name) == -1) {
log_info(&input->base,
"failed to obtain sysname for device '%s'.\n",
devnode);
return NULL;
devnode = udev_device_get_devnode(udev_device);
seat_prop = udev_device_get_property_value(udev_device, "ID_SEAT");
seat_name = strdup(seat_prop ? seat_prop : default_seat);
if (seat_logical_name_override) {
seat_logical_name = strdup(seat_logical_name_override);
} else {
seat_prop = udev_device_get_property_value(udev_device, "WL_SEAT");
seat_logical_name = strdup(seat_prop ? seat_prop : default_seat_name);
}
if (!seat_logical_name) {
log_error(&input->base,
"failed to create seat name for device '%s'.\n",
devnode);
goto out;
}
seat = path_seat_get_named(input, seat_name, seat_logical_name);
@ -182,7 +153,7 @@ path_device_enable(struct path_input *input, const char *devnode)
}
}
device = evdev_device_create(&seat->base, devnode, sysname, syspath);
device = evdev_device_create(&seat->base, udev_device);
libinput_seat_unref(&seat->base);
if (device == EVDEV_UNHANDLED_DEVICE) {
@ -199,8 +170,6 @@ path_device_enable(struct path_input *input, const char *devnode)
}
out:
free(sysname);
free(syspath);
free(seat_name);
free(seat_logical_name);
@ -214,7 +183,7 @@ path_input_enable(struct libinput *libinput)
struct path_device *dev;
list_for_each(dev, &input->path_list, link) {
if (path_device_enable(input, dev->path) == NULL) {
if (path_device_enable(input, dev->udev_device, NULL) == NULL) {
path_input_disable(libinput);
return -1;
}
@ -229,17 +198,67 @@ path_input_destroy(struct libinput *input)
struct path_input *path_input = (struct path_input*)input;
struct path_device *dev, *tmp;
udev_unref(path_input->udev);
list_for_each_safe(dev, tmp, &path_input->path_list, link) {
free(dev->path);
udev_device_unref(dev->udev_device);
free(dev);
}
}
static struct libinput_device *
path_create_device(struct libinput *libinput,
struct udev_device *udev_device,
const char *seat_name)
{
struct path_input *input = (struct path_input*)libinput;
struct path_device *dev;
struct libinput_device *device;
dev = zalloc(sizeof *dev);
if (!dev)
return NULL;
dev->udev_device = udev_device_ref(udev_device);
list_insert(&input->path_list, &dev->link);
device = path_device_enable(input, udev_device, seat_name);
if (!device) {
udev_device_unref(dev->udev_device);
list_remove(&dev->link);
free(dev);
}
return device;
}
static int
path_device_change_seat(struct libinput_device *device,
const char *seat_name)
{
struct libinput *libinput = device->seat->libinput;
struct evdev_device *evdev_device = (struct evdev_device *)device;
struct udev_device *udev_device = NULL;
int rc = -1;
udev_device = evdev_device->udev_device;
udev_device_ref(udev_device);
libinput_path_remove_device(device);
if (path_create_device(libinput, udev_device, seat_name) != NULL)
rc = 0;
udev_device_unref(udev_device);
return rc;
}
static const struct libinput_interface_backend interface_backend = {
.resume = path_input_enable,
.suspend = path_input_disable,
.destroy = path_input_destroy,
.device_change_seat = path_device_change_seat,
};
LIBINPUT_EXPORT struct libinput *
@ -247,31 +266,48 @@ libinput_path_create_context(const struct libinput_interface *interface,
void *user_data)
{
struct path_input *input;
struct udev *udev;
if (!interface)
return NULL;
input = zalloc(sizeof *input);
if (!input)
udev = udev_new();
if (!udev)
return NULL;
if (libinput_init(&input->base, interface,
input = zalloc(sizeof *input);
if (!input ||
libinput_init(&input->base, interface,
&interface_backend, user_data) != 0) {
udev_unref(udev);
free(input);
return NULL;
}
input->udev = udev;
list_init(&input->path_list);
return &input->base;
}
static inline struct udev_device *
udev_device_from_devnode(struct udev *udev, const char *devnode)
{
struct stat st;
if (stat(devnode, &st) < 0)
return NULL;
return udev_device_new_from_devnum(udev, 'c', st.st_rdev);
}
LIBINPUT_EXPORT struct libinput_device *
libinput_path_add_device(struct libinput *libinput,
const char *path)
{
struct path_input *input = (struct path_input*)libinput;
struct path_device *dev;
struct path_input *input = (struct path_input *)libinput;
struct udev *udev = input->udev;
struct udev_device *udev_device;
struct libinput_device *device;
if (libinput->interface_backend != &interface_backend) {
@ -279,26 +315,14 @@ libinput_path_add_device(struct libinput *libinput,
return NULL;
}
dev = zalloc(sizeof *dev);
if (!dev)
return NULL;
dev->path = strdup(path);
if (!dev->path) {
free(dev);
udev_device = udev_device_from_devnode(udev, path);
if (!udev_device) {
log_bug_client(libinput, "Invalid path %s\n", path);
return NULL;
}
list_insert(&input->path_list, &dev->link);
device = path_device_enable(input, dev->path);
if (!device) {
list_remove(&dev->link);
free(dev->path);
free(dev);
}
device = path_create_device(libinput, udev_device, NULL);
udev_device_unref(udev_device);
return device;
}
@ -317,9 +341,9 @@ libinput_path_remove_device(struct libinput_device *device)
}
list_for_each(dev, &input->path_list, link) {
if (strcmp(evdev->devnode, dev->path) == 0) {
if (dev->udev_device == evdev->udev_device) {
list_remove(&dev->link);
free(dev->path);
udev_device_unref(dev->udev_device);
free(dev);
break;
}

View file

@ -28,12 +28,13 @@
struct path_input {
struct libinput base;
struct udev *udev;
struct list path_list;
};
struct path_device {
struct list link;
char *path;
struct udev_device *udev_device;
};
struct path_seat {

View file

@ -42,13 +42,13 @@ static struct udev_seat *
udev_seat_get_named(struct udev_input *input, const char *seat_name);
static int
device_added(struct udev_device *udev_device, struct udev_input *input)
device_added(struct udev_device *udev_device,
struct udev_input *input,
const char *seat_name)
{
struct evdev_device *device;
const char *devnode;
const char *sysname;
const char *syspath;
const char *device_seat, *seat_name, *output_name;
const char *device_seat, *output_name;
const char *calibration_values;
float calibration[6];
struct udev_seat *seat;
@ -61,11 +61,10 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
return 0;
devnode = udev_device_get_devnode(udev_device);
sysname = udev_device_get_sysname(udev_device);
syspath = udev_device_get_syspath(udev_device);
/* Search for matching logical seat */
seat_name = udev_device_get_property_value(udev_device, "WL_SEAT");
if (!seat_name)
seat_name = udev_device_get_property_value(udev_device, "WL_SEAT");
if (!seat_name)
seat_name = default_seat_name;
@ -79,7 +78,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
return -1;
}
device = evdev_device_create(&seat->base, devnode, sysname, syspath);
device = evdev_device_create(&seat->base, udev_device);
libinput_seat_unref(&seat->base);
if (device == EVDEV_UNHANDLED_DEVICE) {
@ -94,7 +93,8 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
udev_device_get_property_value(udev_device,
"LIBINPUT_CALIBRATION_MATRIX");
if (calibration_values && sscanf(calibration_values,
if (device->abs.absinfo_x && device->abs.absinfo_y &&
calibration_values && sscanf(calibration_values,
"%f %f %f %f %f %f",
&calibration[0],
&calibration[1],
@ -123,18 +123,20 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
static void
device_removed(struct udev_device *udev_device, struct udev_input *input)
{
const char *devnode;
struct evdev_device *device, *next;
struct udev_seat *seat;
const char *syspath;
devnode = udev_device_get_devnode(udev_device);
syspath = udev_device_get_syspath(udev_device);
list_for_each(seat, &input->base.seat_list, base.link) {
list_for_each_safe(device, next,
&seat->base.devices_list, base.link) {
if (!strcmp(device->devnode, devnode)) {
if (!strcmp(syspath,
udev_device_get_syspath(device->udev_device))) {
log_info(&input->base,
"input device %s, %s removed\n",
device->devname, device->devnode);
device->devname,
udev_device_get_devnode(device->udev_device));
evdev_device_remove(device);
break;
}
@ -163,7 +165,7 @@ udev_input_add_devices(struct udev_input *input, struct udev *udev)
continue;
}
if (device_added(device, input) < 0) {
if (device_added(device, input, NULL) < 0) {
udev_device_unref(device);
udev_enumerate_unref(e);
return -1;
@ -195,7 +197,7 @@ evdev_udev_handler(void *data)
goto out;
if (!strcmp(action, "add"))
device_added(udev_device, input);
device_added(udev_device, input, NULL);
else if (!strcmp(action, "remove"))
device_removed(udev_device, input);
@ -331,10 +333,29 @@ udev_seat_get_named(struct udev_input *input, const char *seat_name)
return NULL;
}
static int
udev_device_change_seat(struct libinput_device *device,
const char *seat_name)
{
struct libinput *libinput = device->seat->libinput;
struct udev_input *input = (struct udev_input *)libinput;
struct evdev_device *evdev_device = (struct evdev_device *)device;
struct udev_device *udev_device = evdev_device->udev_device;
int rc;
udev_device_ref(udev_device);
device_removed(udev_device, input);
rc = device_added(udev_device, input, seat_name);
udev_device_unref(udev_device);
return rc;
}
static const struct libinput_interface_backend interface_backend = {
.resume = udev_input_enable,
.suspend = udev_input_disable,
.destroy = udev_input_destroy,
.device_change_seat = udev_device_change_seat,
};
LIBINPUT_EXPORT struct libinput *

View file

@ -11,8 +11,6 @@ AM_CXXFLAGS = $(GCC_CXXFLAGS)
TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la
noinst_LTLIBRARIES = liblitest.la
liblitest_la_SOURCES = \
../src/libinput-util.h \
../src/libinput-util.c \
litest.h \
litest-int.h \
litest-alps-semi-mt.c \
@ -20,6 +18,8 @@ liblitest_la_SOURCES = \
litest-generic-singletouch.c \
litest-keyboard.c \
litest-mouse.c \
litest-ms-surface-cover.c \
litest-qemu-usb-tablet.c \
litest-synaptics.c \
litest-synaptics-st.c \
litest-synaptics-t440.c \
@ -29,7 +29,10 @@ liblitest_la_SOURCES = \
litest-wacom-intuos-tablet.c \
litest-wacom-isdv4-tablet.c \
litest-wacom-touch.c \
litest-xen-virtual-pointer.c \
litest-vmware-virtual-usb-mouse.c \
litest.c
liblitest_la_LIBADD = $(top_builddir)/src/libinput-util.la
run_tests = \
test-udev \
@ -109,7 +112,7 @@ test_build_std_gnuc90_CFLAGS = -std=gnu90 -Werror
# test for linking with the minimal linker flags
test_build_linker_SOURCES = build-pedantic.c
test_build_linker_CFLAGS = -I$(top_srcdir)/src
test_build_linker_LDADD = $(top_builddir)/src/libinput.la
test_build_linker_LDADD = $(top_builddir)/src/libinput.la $(top_builddir)/src/libinput-util.la
# test including from C++
test_build_cxx_SOURCES = build-cxx.cc

View file

@ -42,11 +42,24 @@ START_TEST(device_sendevents_config)
modes = libinput_device_config_send_events_get_modes(device);
ck_assert_int_eq(modes,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
}
END_TEST
START_TEST(device_sendevents_config_invalid)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device;
enum libinput_config_status status;
device = dev->libinput_device;
status = libinput_device_config_send_events_set_mode(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED | (1 << 4));
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST
START_TEST(device_sendevents_config_touchpad)
{
struct litest_device *dev = litest_current_device();
@ -57,12 +70,33 @@ START_TEST(device_sendevents_config_touchpad)
modes = libinput_device_config_send_events_get_modes(device);
ck_assert_int_eq(modes,
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
}
END_TEST
START_TEST(device_sendevents_config_touchpad_superset)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device;
enum libinput_config_status status;
uint32_t modes;
device = dev->libinput_device;
modes = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED |
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
status = libinput_device_config_send_events_set_mode(device,
modes);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* DISABLED supersedes the rest, expect the rest to be dropped */
modes = libinput_device_config_send_events_get_mode(device);
ck_assert_int_eq(modes, LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
}
END_TEST
START_TEST(device_sendevents_config_default)
{
struct litest_device *dev = litest_current_device();
@ -131,7 +165,7 @@ START_TEST(device_disable_touchpad)
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10);
litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10, 0);
litest_touch_up(dev, 0);
@ -404,7 +438,7 @@ START_TEST(device_disable_release_tap)
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* tap happened before suspending, so we still expect the event */
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li,
BTN_LEFT,
@ -443,7 +477,7 @@ START_TEST(device_disable_release_tap_n_drag)
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
libinput_dispatch(li);
msleep(400); /* tap-n-drag timeout */
litest_timeout_tap();
libinput_dispatch(li);
status = libinput_device_config_send_events_set_mode(device,
@ -565,16 +599,60 @@ START_TEST(device_disable_topsoftbutton)
}
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(device_get_udev_handle)
{
struct litest_device *dev = litest_current_device();
struct udev_device *udev_device;
udev_device = libinput_device_get_udev_device(dev->libinput_device);
ck_assert_notnull(udev_device);
udev_device_unref(udev_device);
}
END_TEST
START_TEST(device_context)
{
struct litest_device *dev = litest_current_device();
struct libinput_seat *seat;
ck_assert(dev->libinput == libinput_device_get_context(dev->libinput_device));
seat = libinput_device_get_seat(dev->libinput_device);
ck_assert(dev->libinput == libinput_seat_get_context(seat));
}
END_TEST
int main (int argc, char **argv)
{
litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_invalid, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_touchpad, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_touchpad_superset, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_sendevents_config_default, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_disable, LITEST_POINTER, LITEST_TABLET);
litest_add("device:sendevents", device_disable, LITEST_RELATIVE, LITEST_TABLET);
litest_add("device:sendevents", device_disable_touchpad, LITEST_TOUCHPAD, LITEST_TABLET);
litest_add("device:sendevents", device_disable_events_pending, LITEST_POINTER, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_disable_events_pending, LITEST_RELATIVE, LITEST_TOUCHPAD|LITEST_TABLET);
litest_add("device:sendevents", device_double_disable, LITEST_ANY, LITEST_TABLET);
litest_add("device:sendevents", device_double_enable, LITEST_ANY, LITEST_TABLET);
litest_add_no_device("device:sendevents", device_reenable_syspath_changed);
litest_add_no_device("device:sendevents", device_reenable_device_removed);
litest_add_for_device("device:sendevents", device_disable_release_buttons, LITEST_MOUSE);
@ -582,8 +660,11 @@ int main (int argc, char **argv)
litest_add("device:sendevents", device_disable_release_tap, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_disable_release_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:sendevents", device_disable_release_softbutton, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
litest_add("device:sendevents", device_disable_topsoftbutton, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("device:id", device_ids, LITEST_ANY, LITEST_ANY);
litest_add_for_device("device:context", device_context, LITEST_SYNAPTICS_CLICKPAD);
litest_add("device:udev", device_get_udev_handle, LITEST_ANY, LITEST_ANY);
return litest_run(argc, argv);
}

View file

@ -55,7 +55,7 @@ static int events[] = {
struct litest_test_device litest_mouse_device = {
.type = LITEST_MOUSE,
.features = LITEST_POINTER | LITEST_BUTTON | LITEST_WHEEL,
.features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL,
.shortname = "mouse",
.setup = litest_mouse_setup,
.interface = &interface,

View file

@ -0,0 +1,386 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "litest.h"
#include "litest-int.h"
static void
litest_ms_surface_cover_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_MS_SURFACE_COVER);
litest_set_current_device(d);
}
static struct input_event down[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
/* We define down/move so that we can emulate fake touches on this device,
to make sure nothing crashes. */
static struct litest_device_interface interface = {
.touch_down_events = down,
.touch_move_events = move,
};
static struct input_absinfo absinfo[] = {
{ ABS_VOLUME, 0, 1023, 0, 0, 0 },
{ ABS_MISC, 0, 255, 0, 0, 0 },
{ 41, 0, 255, 0, 0, 0 },
{ 42, -127, 127, 0, 0, 0 },
{ 43, -127, 127, 0, 0, 0 },
{ 44, -127, 127, 0, 0, 0 },
{ 45, -127, 127, 0, 0, 0 },
{ 46, -127, 127, 0, 0, 0 },
{ 47, -127, 127, 0, 0, 0 },
/* ABS_MT range overlap starts here */
{ 48, -127, 127, 0, 0, 0 }, /* ABS_MT_SLOT */
{ 49, -127, 127, 0, 0, 0 },
{ 50, -127, 127, 0, 0, 0 },
{ 51, -127, 127, 0, 0, 0 },
{ 52, -127, 127, 0, 0, 0 },
{ 53, -127, 127, 0, 0, 0 },
{ 54, -127, 127, 0, 0, 0 },
{ 55, -127, 127, 0, 0, 0 },
{ 56, -127, 127, 0, 0, 0 },
{ 57, -127, 127, 0, 0, 0 },
{ 58, -127, 127, 0, 0, 0 },
{ 59, -127, 127, 0, 0, 0 },
{ 60, -127, 127, 0, 0, 0 },
{ 61, -127, 127, 0, 0, 0 }, /* ABS_MT_TOOL_Y */
{ 62, -127, 127, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x3,
.vendor = 0x45e,
.product = 0x7a9,
};
static int events[] = {
EV_REL, REL_X,
EV_REL, REL_Y,
EV_REL, REL_HWHEEL,
EV_REL, REL_DIAL,
EV_REL, REL_WHEEL,
EV_KEY, KEY_ESC,
EV_KEY, KEY_1,
EV_KEY, KEY_2,
EV_KEY, KEY_3,
EV_KEY, KEY_4,
EV_KEY, KEY_5,
EV_KEY, KEY_6,
EV_KEY, KEY_7,
EV_KEY, KEY_8,
EV_KEY, KEY_9,
EV_KEY, KEY_0,
EV_KEY, KEY_MINUS,
EV_KEY, KEY_EQUAL,
EV_KEY, KEY_BACKSPACE,
EV_KEY, KEY_TAB,
EV_KEY, KEY_Q,
EV_KEY, KEY_W,
EV_KEY, KEY_E,
EV_KEY, KEY_R,
EV_KEY, KEY_T,
EV_KEY, KEY_Y,
EV_KEY, KEY_U,
EV_KEY, KEY_I,
EV_KEY, KEY_O,
EV_KEY, KEY_P,
EV_KEY, KEY_LEFTBRACE,
EV_KEY, KEY_RIGHTBRACE,
EV_KEY, KEY_ENTER,
EV_KEY, KEY_LEFTCTRL,
EV_KEY, KEY_A,
EV_KEY, KEY_S,
EV_KEY, KEY_D,
EV_KEY, KEY_F,
EV_KEY, KEY_G,
EV_KEY, KEY_H,
EV_KEY, KEY_J,
EV_KEY, KEY_K,
EV_KEY, KEY_L,
EV_KEY, KEY_SEMICOLON,
EV_KEY, KEY_APOSTROPHE,
EV_KEY, KEY_GRAVE,
EV_KEY, KEY_LEFTSHIFT,
EV_KEY, KEY_BACKSLASH,
EV_KEY, KEY_Z,
EV_KEY, KEY_X,
EV_KEY, KEY_C,
EV_KEY, KEY_V,
EV_KEY, KEY_B,
EV_KEY, KEY_N,
EV_KEY, KEY_M,
EV_KEY, KEY_COMMA,
EV_KEY, KEY_DOT,
EV_KEY, KEY_SLASH,
EV_KEY, KEY_RIGHTSHIFT,
EV_KEY, KEY_KPASTERISK,
EV_KEY, KEY_LEFTALT,
EV_KEY, KEY_SPACE,
EV_KEY, KEY_CAPSLOCK,
EV_KEY, KEY_F1,
EV_KEY, KEY_F2,
EV_KEY, KEY_F3,
EV_KEY, KEY_F4,
EV_KEY, KEY_F5,
EV_KEY, KEY_F6,
EV_KEY, KEY_F7,
EV_KEY, KEY_F8,
EV_KEY, KEY_F9,
EV_KEY, KEY_F10,
EV_KEY, KEY_NUMLOCK,
EV_KEY, KEY_SCROLLLOCK,
EV_KEY, KEY_KP7,
EV_KEY, KEY_KP8,
EV_KEY, KEY_KP9,
EV_KEY, KEY_KPMINUS,
EV_KEY, KEY_KP4,
EV_KEY, KEY_KP5,
EV_KEY, KEY_KP6,
EV_KEY, KEY_KPPLUS,
EV_KEY, KEY_KP1,
EV_KEY, KEY_KP2,
EV_KEY, KEY_KP3,
EV_KEY, KEY_KP0,
EV_KEY, KEY_KPDOT,
EV_KEY, KEY_102ND,
EV_KEY, KEY_F11,
EV_KEY, KEY_F12,
EV_KEY, KEY_RO,
EV_KEY, KEY_HENKAN,
EV_KEY, KEY_KATAKANAHIRAGANA,
EV_KEY, KEY_MUHENKAN,
EV_KEY, KEY_KPJPCOMMA,
EV_KEY, KEY_KPENTER,
EV_KEY, KEY_RIGHTCTRL,
EV_KEY, KEY_KPSLASH,
EV_KEY, KEY_SYSRQ,
EV_KEY, KEY_RIGHTALT,
EV_KEY, KEY_HOME,
EV_KEY, KEY_UP,
EV_KEY, KEY_PAGEUP,
EV_KEY, KEY_LEFT,
EV_KEY, KEY_RIGHT,
EV_KEY, KEY_END,
EV_KEY, KEY_DOWN,
EV_KEY, KEY_PAGEDOWN,
EV_KEY, KEY_INSERT,
EV_KEY, KEY_DELETE,
EV_KEY, KEY_MUTE,
EV_KEY, KEY_VOLUMEDOWN,
EV_KEY, KEY_VOLUMEUP,
EV_KEY, KEY_POWER,
EV_KEY, KEY_KPEQUAL,
EV_KEY, KEY_PAUSE,
EV_KEY, KEY_KPCOMMA,
EV_KEY, KEY_HANGEUL,
EV_KEY, KEY_HANJA,
EV_KEY, KEY_YEN,
EV_KEY, KEY_LEFTMETA,
EV_KEY, KEY_RIGHTMETA,
EV_KEY, KEY_COMPOSE,
EV_KEY, KEY_STOP,
EV_KEY, KEY_AGAIN,
EV_KEY, KEY_PROPS,
EV_KEY, KEY_UNDO,
EV_KEY, KEY_FRONT,
EV_KEY, KEY_COPY,
EV_KEY, KEY_OPEN,
EV_KEY, KEY_PASTE,
EV_KEY, KEY_FIND,
EV_KEY, KEY_CUT,
EV_KEY, KEY_HELP,
EV_KEY, KEY_MENU,
EV_KEY, KEY_CALC,
EV_KEY, KEY_SLEEP,
EV_KEY, KEY_FILE,
EV_KEY, KEY_WWW,
EV_KEY, KEY_COFFEE,
EV_KEY, KEY_MAIL,
EV_KEY, KEY_BOOKMARKS,
EV_KEY, KEY_BACK,
EV_KEY, KEY_FORWARD,
EV_KEY, KEY_EJECTCD,
EV_KEY, KEY_NEXTSONG,
EV_KEY, KEY_PLAYPAUSE,
EV_KEY, KEY_PREVIOUSSONG,
EV_KEY, KEY_STOPCD,
EV_KEY, KEY_RECORD,
EV_KEY, KEY_REWIND,
EV_KEY, KEY_PHONE,
EV_KEY, KEY_CONFIG,
EV_KEY, KEY_HOMEPAGE,
EV_KEY, KEY_REFRESH,
EV_KEY, KEY_EXIT,
EV_KEY, KEY_EDIT,
EV_KEY, KEY_SCROLLUP,
EV_KEY, KEY_SCROLLDOWN,
EV_KEY, KEY_NEW,
EV_KEY, KEY_REDO,
EV_KEY, KEY_F13,
EV_KEY, KEY_F14,
EV_KEY, KEY_F15,
EV_KEY, KEY_F16,
EV_KEY, KEY_F17,
EV_KEY, KEY_F18,
EV_KEY, KEY_F19,
EV_KEY, KEY_F20,
EV_KEY, KEY_F21,
EV_KEY, KEY_F22,
EV_KEY, KEY_F23,
EV_KEY, KEY_F24,
EV_KEY, KEY_CLOSE,
EV_KEY, KEY_PLAY,
EV_KEY, KEY_FASTFORWARD,
EV_KEY, KEY_BASSBOOST,
EV_KEY, KEY_PRINT,
EV_KEY, KEY_CAMERA,
EV_KEY, KEY_CHAT,
EV_KEY, KEY_SEARCH,
EV_KEY, KEY_FINANCE,
EV_KEY, KEY_CANCEL,
EV_KEY, KEY_BRIGHTNESSDOWN,
EV_KEY, KEY_BRIGHTNESSUP,
EV_KEY, KEY_KBDILLUMTOGGLE,
EV_KEY, KEY_SEND,
EV_KEY, KEY_REPLY,
EV_KEY, KEY_FORWARDMAIL,
EV_KEY, KEY_SAVE,
EV_KEY, KEY_DOCUMENTS,
EV_KEY, KEY_UNKNOWN,
EV_KEY, KEY_VIDEO_NEXT,
EV_KEY, KEY_BRIGHTNESS_ZERO,
EV_KEY, BTN_0,
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_KEY, BTN_SIDE,
EV_KEY, BTN_EXTRA,
EV_KEY, KEY_SELECT,
EV_KEY, KEY_GOTO,
EV_KEY, KEY_INFO,
EV_KEY, KEY_PROGRAM,
EV_KEY, KEY_PVR,
EV_KEY, KEY_SUBTITLE,
EV_KEY, KEY_ZOOM,
EV_KEY, KEY_KEYBOARD,
EV_KEY, KEY_PC,
EV_KEY, KEY_TV,
EV_KEY, KEY_TV2,
EV_KEY, KEY_VCR,
EV_KEY, KEY_VCR2,
EV_KEY, KEY_SAT,
EV_KEY, KEY_CD,
EV_KEY, KEY_TAPE,
EV_KEY, KEY_TUNER,
EV_KEY, KEY_PLAYER,
EV_KEY, KEY_DVD,
EV_KEY, KEY_AUDIO,
EV_KEY, KEY_VIDEO,
EV_KEY, KEY_MEMO,
EV_KEY, KEY_CALENDAR,
EV_KEY, KEY_RED,
EV_KEY, KEY_GREEN,
EV_KEY, KEY_YELLOW,
EV_KEY, KEY_BLUE,
EV_KEY, KEY_CHANNELUP,
EV_KEY, KEY_CHANNELDOWN,
EV_KEY, KEY_LAST,
EV_KEY, KEY_NEXT,
EV_KEY, KEY_RESTART,
EV_KEY, KEY_SLOW,
EV_KEY, KEY_SHUFFLE,
EV_KEY, KEY_PREVIOUS,
EV_KEY, KEY_VIDEOPHONE,
EV_KEY, KEY_GAMES,
EV_KEY, KEY_ZOOMIN,
EV_KEY, KEY_ZOOMOUT,
EV_KEY, KEY_ZOOMRESET,
EV_KEY, KEY_WORDPROCESSOR,
EV_KEY, KEY_EDITOR,
EV_KEY, KEY_SPREADSHEET,
EV_KEY, KEY_GRAPHICSEDITOR,
EV_KEY, KEY_PRESENTATION,
EV_KEY, KEY_DATABASE,
EV_KEY, KEY_NEWS,
EV_KEY, KEY_VOICEMAIL,
EV_KEY, KEY_ADDRESSBOOK,
EV_KEY, KEY_MESSENGER,
EV_KEY, KEY_DISPLAYTOGGLE,
EV_KEY, KEY_SPELLCHECK,
EV_KEY, KEY_LOGOFF,
EV_KEY, KEY_MEDIA_REPEAT,
EV_KEY, KEY_IMAGES,
EV_KEY, 576,
EV_KEY, 577,
EV_KEY, 578,
EV_KEY, 579,
EV_KEY, 580,
EV_KEY, 581,
EV_KEY, 582,
EV_KEY, 592,
EV_KEY, 593,
EV_KEY, 608,
EV_KEY, 609,
EV_KEY, 610,
EV_KEY, 611,
EV_KEY, 612,
EV_KEY, 613,
EV_LED, LED_NUML,
EV_LED, LED_CAPSL,
EV_LED, LED_SCROLLL,
EV_REP, REP_DELAY,
-1, -1,
};
struct litest_test_device litest_ms_surface_cover_device = {
.type = LITEST_MS_SURFACE_COVER,
.features = LITEST_KEYBOARD | LITEST_RELATIVE | LITEST_FAKE_MT,
.shortname = "MS surface cover",
.setup = litest_ms_surface_cover_setup,
.interface = &interface,
.name = "MICROSOFT SAM",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,101 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "litest.h"
#include "litest-int.h"
#include <assert.h>
static void
litest_qemu_tablet_touch_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_QEMU_TABLET);
litest_set_current_device(d);
}
static void touch_down(struct litest_device *d, unsigned int slot,
double x, double y)
{
assert(slot == 0);
litest_event(d, EV_ABS, ABS_X, litest_scale(d, ABS_X, x));
litest_event(d, EV_ABS, ABS_Y, litest_scale(d, ABS_Y, y));
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static void touch_move(struct litest_device *d, unsigned int slot,
double x, double y)
{
assert(slot == 0);
litest_event(d, EV_ABS, ABS_X, litest_scale(d, ABS_X, x));
litest_event(d, EV_ABS, ABS_Y, litest_scale(d, ABS_Y, y));
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static void touch_up(struct litest_device *d, unsigned int slot)
{
assert(slot == 0);
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static struct litest_device_interface interface = {
.touch_down = touch_down,
.touch_move = touch_move,
.touch_up = touch_up,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 32767, 0, 0, 0 },
{ ABS_Y, 0, 32767, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x03,
.vendor = 0x627,
.product = 0x01,
};
static int events[] = {
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_REL, REL_WHEEL,
-1, -1,
};
struct litest_test_device litest_qemu_tablet_device = {
.type = LITEST_QEMU_TABLET,
.features = LITEST_WHEEL | LITEST_BUTTON | LITEST_ABSOLUTE,
.shortname = "qemu tablet",
.setup = litest_qemu_tablet_touch_setup,
.interface = &interface,
.name = "QEMU 0.12.1 QEMU USB Tablet",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -56,7 +56,7 @@ static int events[] = {
struct litest_test_device litest_trackpoint_device = {
.type = LITEST_TRACKPOINT,
.features = LITEST_POINTER | LITEST_BUTTON | LITEST_POINTINGSTICK,
.features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_POINTINGSTICK,
.shortname = "trackpoint",
.setup = litest_trackpoint_setup,
.interface = &interface,

View file

@ -0,0 +1,115 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "litest.h"
#include "litest-int.h"
#include <assert.h>
static void
litest_vmware_virtmouse_touch_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_VMWARE_VIRTMOUSE);
litest_set_current_device(d);
}
static void touch_down(struct litest_device *d, unsigned int slot,
double x, double y)
{
assert(slot == 0);
litest_event(d, EV_ABS, ABS_X, litest_scale(d, ABS_X, x));
litest_event(d, EV_ABS, ABS_Y, litest_scale(d, ABS_Y, y));
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static void touch_move(struct litest_device *d, unsigned int slot,
double x, double y)
{
assert(slot == 0);
litest_event(d, EV_ABS, ABS_X, litest_scale(d, ABS_X, x));
litest_event(d, EV_ABS, ABS_Y, litest_scale(d, ABS_Y, y));
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static void touch_up(struct litest_device *d, unsigned int slot)
{
assert(slot == 0);
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static struct litest_device_interface interface = {
.touch_down = touch_down,
.touch_move = touch_move,
.touch_up = touch_up,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 32767, 0, 0, 0 },
{ ABS_Y, 0, 32767, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x03,
.vendor = 0xe0f,
.product = 0x03,
};
static int events[] = {
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_KEY, BTN_SIDE,
EV_KEY, BTN_EXTRA,
EV_KEY, BTN_FORWARD,
EV_KEY, BTN_BACK,
EV_KEY, BTN_TASK,
EV_KEY, 280,
EV_KEY, 281,
EV_KEY, 282,
EV_KEY, 283,
EV_KEY, 284,
EV_KEY, 285,
EV_KEY, 286,
EV_KEY, 287,
EV_REL, REL_WHEEL,
EV_REL, REL_HWHEEL,
-1, -1,
};
struct litest_test_device litest_vmware_virtmouse_device = {
.type = LITEST_VMWARE_VIRTMOUSE,
.features = LITEST_WHEEL | LITEST_BUTTON | LITEST_ABSOLUTE,
.shortname = "vmware virtmouse",
.setup = litest_vmware_virtmouse_touch_setup,
.interface = &interface,
.name = "VMware VMware Virtual USB Mouse",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -0,0 +1,106 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "litest.h"
#include "litest-int.h"
#include <assert.h>
static void
litest_xen_virtual_pointer_touch_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_XEN_VIRTUAL_POINTER);
litest_set_current_device(d);
}
static void touch_down(struct litest_device *d, unsigned int slot,
double x, double y)
{
assert(slot == 0);
litest_event(d, EV_ABS, ABS_X, litest_scale(d, ABS_X, x));
litest_event(d, EV_ABS, ABS_Y, litest_scale(d, ABS_Y, y));
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static void touch_move(struct litest_device *d, unsigned int slot,
double x, double y)
{
assert(slot == 0);
litest_event(d, EV_ABS, ABS_X, litest_scale(d, ABS_X, x));
litest_event(d, EV_ABS, ABS_Y, litest_scale(d, ABS_Y, y));
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static void touch_up(struct litest_device *d, unsigned int slot)
{
assert(slot == 0);
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
static struct litest_device_interface interface = {
.touch_down = touch_down,
.touch_move = touch_move,
.touch_up = touch_up,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 0, 800, 0, 0, 0 },
{ ABS_Y, 0, 800, 0, 0, 0 },
{ .value = -1 },
};
static struct input_id input_id = {
.bustype = 0x01,
.vendor = 0x5853,
.product = 0xfffe,
};
static int events[] = {
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_MIDDLE,
EV_KEY, BTN_SIDE,
EV_KEY, BTN_EXTRA,
EV_KEY, BTN_FORWARD,
EV_KEY, BTN_BACK,
EV_KEY, BTN_TASK,
EV_REL, REL_WHEEL,
-1, -1,
};
struct litest_test_device litest_xen_virtual_pointer_device = {
.type = LITEST_XEN_VIRTUAL_POINTER,
.features = LITEST_WHEEL | LITEST_BUTTON | LITEST_ABSOLUTE,
.shortname = "xen pointer",
.setup = litest_xen_virtual_pointer_touch_setup,
.interface = &interface,
.name = "Xen Virtual Pointer",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};

View file

@ -91,6 +91,9 @@ extern struct litest_test_device litest_wacom_intuos_tablet_device;
extern struct litest_test_device litest_wacom_isdv4_tablet_device;
extern struct litest_test_device litest_alps_device;
extern struct litest_test_device litest_generic_singletouch_device;
extern struct litest_test_device litest_qemu_tablet_device;
extern struct litest_test_device litest_xen_virtual_pointer_device;
extern struct litest_test_device litest_vmware_virtmouse_device;
struct litest_test_device* devices[] = {
&litest_synaptics_clickpad_device,
@ -107,6 +110,9 @@ struct litest_test_device* devices[] = {
&litest_wacom_isdv4_tablet_device,
&litest_alps_device,
&litest_generic_singletouch_device,
&litest_qemu_tablet_device,
&litest_xen_virtual_pointer_device,
&litest_vmware_virtmouse_device,
NULL,
};
@ -642,7 +648,12 @@ void
litest_event(struct litest_device *d, unsigned int type,
unsigned int code, int value)
{
int ret = libevdev_uinput_write_event(d->uinput, type, code, value);
int ret;
if (d->skip_ev_syn && type == EV_SYN && code == SYN_REPORT)
return;
ret = libevdev_uinput_write_event(d->uinput, type, code, value);
ck_assert_int_eq(ret, 0);
}
@ -765,12 +776,18 @@ litest_touch_move_to(struct litest_device *d,
unsigned int slot,
double x_from, double y_from,
double x_to, double y_to,
int steps)
int steps, int sleep_ms)
{
for (int i = 0; i < steps - 1; i++)
for (int i = 0; i < steps - 1; i++) {
litest_touch_move(d, slot,
x_from + (x_to - x_from)/steps * i,
y_from + (y_to - y_from)/steps * i);
if (sleep_ms) {
libinput_dispatch(d->libinput);
msleep(sleep_ms);
libinput_dispatch(d->libinput);
}
}
litest_touch_move(d, slot, x_to, y_to);
}
@ -877,6 +894,28 @@ litest_button_click(struct litest_device *d, unsigned int button, bool is_press)
litest_event(d, ev->type, ev->code, ev->value);
}
void
litest_button_scroll(struct litest_device *dev,
unsigned int button,
double dx, double dy)
{
struct libinput *li = dev->libinput;
litest_button_click(dev, button, 1);
libinput_dispatch(li);
litest_timeout_buttonscroll();
libinput_dispatch(li);
litest_event(dev, EV_REL, REL_X, dx);
litest_event(dev, EV_REL, REL_Y, dy);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_button_click(dev, button, 0);
libinput_dispatch(li);
}
void
litest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press)
{
@ -1182,7 +1221,10 @@ litest_assert_button_event(struct libinput *li, unsigned int button,
libinput_event_destroy(event);
}
void litest_assert_scroll(struct libinput *li, unsigned int axis, int dir)
void
litest_assert_scroll(struct libinput *li,
enum libinput_pointer_axis axis,
int minimum_movement)
{
struct libinput_event *event, *next_event;
struct libinput_event_pointer *ptrev;
@ -1200,14 +1242,14 @@ void litest_assert_scroll(struct libinput *li, unsigned int axis, int dir)
if (next_event) {
/* Normal scroll event, check dir */
if (dir > 0) {
if (minimum_movement > 0) {
ck_assert_int_ge(
libinput_event_pointer_get_axis_value(ptrev),
dir);
minimum_movement);
} else {
ck_assert_int_le(
libinput_event_pointer_get_axis_value(ptrev),
dir);
minimum_movement);
}
} else {
/* Last scroll event, must be 0 */
@ -1220,3 +1262,36 @@ void litest_assert_scroll(struct libinput *li, unsigned int axis, int dir)
next_event = libinput_get_event(li);
}
}
void
litest_timeout_tap(void)
{
msleep(200);
}
void
litest_timeout_softbuttons(void)
{
msleep(300);
}
void
litest_timeout_buttonscroll(void)
{
msleep(300);
}
void
litest_push_event_frame(struct litest_device *dev)
{
assert(!dev->skip_ev_syn);
dev->skip_ev_syn = true;
}
void
litest_pop_event_frame(struct litest_device *dev)
{
assert(dev->skip_ev_syn);
dev->skip_ev_syn = false;
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}

View file

@ -45,10 +45,14 @@ enum litest_device_type {
LITEST_WACOM_TOUCH = -9,
LITEST_ALPS_SEMI_MT = -10,
LITEST_GENERIC_SINGLETOUCH = -11,
LITEST_WACOM_BAMBOO = -12,
LITEST_WACOM_CINTIQ = -13,
LITEST_WACOM_INTUOS = -14,
LITEST_WACOM_ISDV4 = -15,
LITEST_MS_SURFACE_COVER = -12,
LITEST_QEMU_TABLET = -13,
LITEST_XEN_VIRTUAL_POINTER = -14,
LITEST_VMWARE_VIRTMOUSE = -15,
LITEST_WACOM_BAMBOO = -16,
LITEST_WACOM_CINTIQ = -17,
LITEST_WACOM_INTUOS = -18,
LITEST_WACOM_ISDV4 = -19,
};
enum litest_device_feature {
@ -58,7 +62,7 @@ enum litest_device_feature {
LITEST_CLICKPAD = 1 << 1,
LITEST_BUTTON = 1 << 2,
LITEST_KEYS = 1 << 3,
LITEST_POINTER = 1 << 4,
LITEST_RELATIVE = 1 << 4,
LITEST_WHEEL = 1 << 5,
LITEST_TOUCH = 1 << 6,
LITEST_SINGLE_TOUCH = 1 << 7,
@ -66,9 +70,11 @@ enum litest_device_feature {
LITEST_TOPBUTTONPAD = 1 << 9,
LITEST_SEMI_MT = 1 << 10,
LITEST_POINTINGSTICK = 1 << 11,
LITEST_TABLET = 1 << 12,
LITEST_DISTANCE = 1 << 13,
LITEST_TOOL_SERIAL = 1 << 14,
LITEST_FAKE_MT = 1 << 12,
LITEST_ABSOLUTE = 1 << 13,
LITEST_TABLET = 1 << 14,
LITEST_DISTANCE = 1 << 15,
LITEST_TOOL_SERIAL = 1 << 16,
};
struct litest_device {
@ -80,6 +86,8 @@ struct litest_device {
struct litest_device_interface *interface;
int ntouches_down;
bool skip_ev_syn;
void *private; /* device-specific data */
};
@ -145,7 +153,7 @@ void litest_touch_move_to(struct litest_device *d,
unsigned int slot,
double x_from, double y_from,
double x_to, double y_to,
int steps);
int steps, int sleep_ms);
void litest_tablet_proximity_in(struct litest_device *d,
int x, int y,
struct axis_replacement *axes);
@ -156,6 +164,9 @@ void litest_tablet_motion(struct litest_device *d,
void litest_button_click(struct litest_device *d,
unsigned int button,
bool is_press);
void litest_button_scroll(struct litest_device *d,
unsigned int button,
double dx, double dy);
void litest_keyboard_key(struct litest_device *d,
unsigned int key,
bool is_press);
@ -166,7 +177,9 @@ void litest_assert_empty_queue(struct libinput *li);
void litest_assert_button_event(struct libinput *li,
unsigned int button,
enum libinput_button_state state);
void litest_assert_scroll(struct libinput *li, unsigned int axis, int dir);
void litest_assert_scroll(struct libinput *li,
enum libinput_pointer_axis axis,
int minimum_movement);
struct libevdev_uinput * litest_create_uinput_device(const char *name,
struct input_id *id,
@ -193,6 +206,13 @@ struct libevdev_uinput * litest_create_uinput_abs_device(const char *name,
#define litest_assert_double_ge(a_, b_)\
ck_assert_int_ge((int)(a_ * 256), (int)(b_ * 256))
void litest_timeout_tap(void);
void litest_timeout_softbuttons(void);
void litest_timeout_buttonscroll(void);
void litest_push_event_frame(struct litest_device *dev);
void litest_pop_event_frame(struct litest_device *dev);
#ifndef ck_assert_notnull
#define ck_assert_notnull(ptr) ck_assert_ptr_ne(ptr, NULL)
#endif

View file

@ -125,11 +125,13 @@ START_TEST(log_priority)
libinput_path_add_device(li, "/tmp");
ck_assert_int_eq(log_handler_called, 0);
ck_assert_int_eq(log_handler_called, 1);
libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
libinput_path_add_device(li, "/tmp");
ck_assert_int_gt(log_handler_called, 0);
/* event0 is usually Lid Switch which prints an info that
we don't handle it */
libinput_path_add_device(li, "/dev/input/event0");
ck_assert_int_gt(log_handler_called, 1);
log_handler_called = 0;

View file

@ -429,25 +429,6 @@ 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];
@ -546,6 +527,87 @@ START_TEST(matrix_helpers)
}
END_TEST
START_TEST(ratelimit_helpers)
{
struct ratelimit rl;
unsigned int i, j;
/* 10 attempts every 100ms */
ratelimit_init(&rl, 100, 10);
for (j = 0; j < 3; ++j) {
/* a burst of 9 attempts must succeed */
for (i = 0; i < 9; ++i) {
ck_assert_int_eq(ratelimit_test(&rl),
RATELIMIT_PASS);
}
/* the 10th attempt reaches the threshold */
ck_assert_int_eq(ratelimit_test(&rl), RATELIMIT_THRESHOLD);
/* ..then further attempts must fail.. */
ck_assert_int_eq(ratelimit_test(&rl), RATELIMIT_EXCEEDED);
/* ..regardless of how often we try. */
for (i = 0; i < 100; ++i) {
ck_assert_int_eq(ratelimit_test(&rl),
RATELIMIT_EXCEEDED);
}
/* ..even after waiting 20ms */
msleep(20);
for (i = 0; i < 100; ++i) {
ck_assert_int_eq(ratelimit_test(&rl),
RATELIMIT_EXCEEDED);
}
/* but after 100ms the counter is reset */
msleep(90); /* +10ms to account for time drifts */
}
}
END_TEST
struct parser_test {
char *tag;
int expected_dpi;
};
START_TEST(dpi_parser)
{
struct parser_test tests[] = {
{ "450 *1800 3200", 1800 },
{ "*450 1800 3200", 450 },
{ "450 1800 *3200", 3200 },
{ "450 1800 3200", 3200 },
{ "450 1800 failboat", 0 },
{ "450 1800 *failboat", 0 },
{ "0 450 1800 *3200", 0 },
{ "450@37 1800@12 *3200@6", 3200 },
{ "450@125 1800@125 *3200@125 ", 3200 },
{ "450@125 *1800@125 3200@125", 1800 },
{ "*this @string fails", 0 },
{ "12@34 *45@", 0 },
{ "12@a *45@", 0 },
{ "12@a *45@25", 0 },
{ " * 12, 450, 800", 0 },
{ " *12, 450, 800", 12 },
{ "*12, *450, 800", 12 },
{ "*-23412, 450, 800", 0 },
{ "112@125, 450@125, 800@125, 900@-125", 0 },
{ "", 0 },
{ " ", 0 },
{ "* ", 0 },
{ NULL }
};
int i, dpi;
for (i = 0; tests[i].tag != NULL; i++) {
dpi = parse_mouse_dpi_property(tests[i].tag);
ck_assert_int_eq(dpi, tests[i].expected_dpi);
}
}
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);
@ -554,9 +616,11 @@ 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);
litest_add_no_device("misc:matrix", matrix_helpers);
litest_add_no_device("misc:ratelimit", ratelimit_helpers);
litest_add_no_device("misc:dpi parser", dpi_parser);
return litest_run(argc, argv);
}

View file

@ -162,6 +162,74 @@ START_TEST(path_added_seat)
}
END_TEST
START_TEST(path_seat_change)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_device *device;
struct libinput_seat *seat1, *seat2;
const char *seat1_name;
const char *seat2_name = "new seat";
int rc;
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_DEVICE_ADDED);
device = libinput_event_get_device(event);
libinput_device_ref(device);
seat1 = libinput_device_get_seat(device);
libinput_seat_ref(seat1);
seat1_name = libinput_seat_get_logical_name(seat1);
libinput_event_destroy(event);
litest_drain_events(li);
rc = libinput_device_set_seat_logical_name(device,
seat2_name);
ck_assert_int_eq(rc, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_DEVICE_REMOVED);
ck_assert(libinput_event_get_device(event) == device);
libinput_event_destroy(event);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_DEVICE_ADDED);
ck_assert(libinput_event_get_device(event) != device);
libinput_device_unref(device);
device = libinput_event_get_device(event);
seat2 = libinput_device_get_seat(device);
ck_assert_str_ne(libinput_seat_get_logical_name(seat2),
seat1_name);
ck_assert_str_eq(libinput_seat_get_logical_name(seat2),
seat2_name);
libinput_event_destroy(event);
libinput_seat_unref(seat1);
/* litest: swap the new device in, so cleanup works */
libinput_device_unref(dev->libinput_device);
libinput_device_ref(device);
dev->libinput_device = device;
}
END_TEST
START_TEST(path_added_device)
{
struct litest_device *dev = litest_current_device();
@ -805,7 +873,8 @@ main(int argc, char **argv)
litest_add_no_device("path:suspend", path_add_device_suspend_resume);
litest_add_no_device("path:suspend", path_add_device_suspend_resume_fail);
litest_add_no_device("path:suspend", path_add_device_suspend_resume_remove_device);
litest_add_for_device("path:seat events", path_added_seat, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("path:seat", path_added_seat, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("path:seat", path_seat_change, LITEST_SYNAPTICS_CLICKPAD);
litest_add("path:device events", path_added_device, LITEST_ANY, LITEST_ANY);
litest_add("path:device events", path_device_sysname, LITEST_ANY, LITEST_ANY);
litest_add_for_device("path:device events", path_add_device, LITEST_SYNAPTICS_CLICKPAD);

View file

@ -29,15 +29,43 @@
#include <libinput.h>
#include <math.h>
#include <unistd.h>
#include <values.h>
#include "libinput-util.h"
#include "litest.h"
static struct libinput_event_pointer *
get_accelerated_motion_event(struct libinput *li)
{
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
while (1) {
event = libinput_get_event(li);
ck_assert_notnull(event);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
ptrev = libinput_event_get_pointer_event(event);
ck_assert_notnull(ptrev);
if (fabs(libinput_event_pointer_get_dx(ptrev)) < DBL_MIN &&
fabs(libinput_event_pointer_get_dy(ptrev)) < DBL_MIN) {
libinput_event_destroy(event);
continue;
}
return ptrev;
}
ck_abort_msg("No accelerated pointer motion event found");
return NULL;
}
static void
test_relative_event(struct litest_device *dev, int dx, int dy)
{
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
double ev_dx, ev_dy;
double expected_dir;
@ -56,12 +84,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy)
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION);
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ptrev = get_accelerated_motion_event(li);
expected_length = sqrt(4 * dx*dx + 4 * dy*dy);
expected_dir = atan2(dx, dy);
@ -78,7 +101,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy)
* indifference). */
ck_assert(fabs(expected_dir - actual_dir) < M_PI_2);
libinput_event_destroy(event);
libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
litest_drain_events(dev->libinput);
}
@ -101,6 +124,95 @@ START_TEST(pointer_motion_relative)
}
END_TEST
static void
test_absolute_event(struct litest_device *dev, double x, double y)
{
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
double ex, ey;
litest_touch_down(dev, 0, x, y);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE);
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ex = libinput_event_pointer_get_absolute_x_transformed(ptrev, 100);
ey = libinput_event_pointer_get_absolute_y_transformed(ptrev, 100);
ck_assert_int_eq(ex + 0.5, x);
ck_assert_int_eq(ey + 0.5, y);
libinput_event_destroy(event);
}
START_TEST(pointer_motion_absolute)
{
struct litest_device *dev = litest_current_device();
litest_drain_events(dev->libinput);
test_absolute_event(dev, 0, 100);
test_absolute_event(dev, 100, 0);
test_absolute_event(dev, 50, 50);
}
END_TEST
static void
test_unaccel_event(struct litest_device *dev, int dx, int dy)
{
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
double ev_dx, ev_dy;
litest_event(dev, EV_REL, REL_X, dx);
litest_event(dev, EV_REL, REL_Y, dy);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert_notnull(event);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ev_dx = libinput_event_pointer_get_dx_unaccelerated(ptrev);
ev_dy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
ck_assert_int_eq(dx, ev_dx);
ck_assert_int_eq(dy, ev_dy);
libinput_event_destroy(event);
litest_drain_events(dev->libinput);
}
START_TEST(pointer_motion_unaccel)
{
struct litest_device *dev = litest_current_device();
litest_drain_events(dev->libinput);
test_unaccel_event(dev, 10, 0);
test_unaccel_event(dev, 10, 10);
test_unaccel_event(dev, 10, -10);
test_unaccel_event(dev, 0, 10);
test_unaccel_event(dev, -10, 0);
test_unaccel_event(dev, -10, 10);
test_unaccel_event(dev, -10, -10);
test_unaccel_event(dev, 0, -10);
}
END_TEST
static void
test_button_event(struct litest_device *dev, unsigned int button, int state)
{
@ -242,6 +354,9 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
const int scroll_step = 10;
int expected = amount * scroll_step;
if (libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device))
expected *= -1;
/* mouse scroll wheels are 'upside down' */
if (which == REL_WHEEL)
amount *= -1;
@ -287,6 +402,56 @@ START_TEST(pointer_scroll_wheel)
}
END_TEST
START_TEST(pointer_scroll_natural_defaults)
{
struct litest_device *dev = litest_current_device();
ck_assert_int_ge(libinput_device_config_scroll_has_natural_scroll(dev->libinput_device), 1);
ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 0);
ck_assert_int_eq(libinput_device_config_scroll_get_default_natural_scroll_enabled(dev->libinput_device), 0);
}
END_TEST
START_TEST(pointer_scroll_natural_enable_config)
{
struct litest_device *dev = litest_current_device();
enum libinput_config_status status;
status = libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 1);
status = libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 0);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 0);
}
END_TEST
START_TEST(pointer_scroll_natural_wheel)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
litest_drain_events(dev->libinput);
libinput_device_config_scroll_set_natural_scroll_enabled(device, 1);
test_wheel_event(dev, REL_WHEEL, -1);
test_wheel_event(dev, REL_WHEEL, 1);
test_wheel_event(dev, REL_WHEEL, -5);
test_wheel_event(dev, REL_WHEEL, 6);
if (libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL)) {
test_wheel_event(dev, REL_HWHEEL, -1);
test_wheel_event(dev, REL_HWHEEL, 1);
test_wheel_event(dev, REL_HWHEEL, -5);
test_wheel_event(dev, REL_HWHEEL, 6);
}
}
END_TEST
START_TEST(pointer_seat_button_count)
{
const int num_devices = 4;
@ -396,15 +561,188 @@ START_TEST(pointer_no_calibration)
}
END_TEST
START_TEST(pointer_left_handed_defaults)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
int rc;
rc = libinput_device_config_buttons_has_left_handed(d);
ck_assert_int_ne(rc, 0);
rc = libinput_device_config_buttons_get_left_handed(d);
ck_assert_int_eq(rc, 0);
rc = libinput_device_config_buttons_get_default_left_handed(d);
ck_assert_int_eq(rc, 0);
}
END_TEST
START_TEST(pointer_left_handed)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_button_click(dev, BTN_RIGHT, 1);
litest_button_click(dev, BTN_RIGHT, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
if (libevdev_has_event_code(dev->evdev,
EV_KEY,
BTN_MIDDLE)) {
litest_button_click(dev, BTN_MIDDLE, 1);
litest_button_click(dev, BTN_MIDDLE, 0);
litest_assert_button_event(li,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
}
}
END_TEST
START_TEST(pointer_left_handed_during_click)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
litest_drain_events(li);
litest_button_click(dev, BTN_LEFT, 1);
libinput_dispatch(li);
/* Change while button is down, expect correct release event */
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_button_click(dev, BTN_LEFT, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(pointer_left_handed_during_click_multiple_buttons)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
litest_drain_events(li);
litest_button_click(dev, BTN_LEFT, 1);
libinput_dispatch(li);
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
/* No left-handed until all buttons were down */
litest_button_click(dev, BTN_RIGHT, 1);
litest_button_click(dev, BTN_RIGHT, 0);
litest_button_click(dev, BTN_LEFT, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(pointer_scroll_button)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
/* Make left button switch to scrolling mode */
libinput_device_config_scroll_set_method(dev->libinput_device,
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN);
libinput_device_config_scroll_set_button(dev->libinput_device,
BTN_LEFT);
litest_drain_events(li);
litest_button_scroll(dev, BTN_LEFT, 1, 6);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 6);
litest_button_scroll(dev, BTN_LEFT, 1, -7);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -7);
litest_button_scroll(dev, BTN_LEFT, 8, 1);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 8);
litest_button_scroll(dev, BTN_LEFT, -9, 1);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
/* scroll smaller than the threshold should not generate events */
litest_button_scroll(dev, BTN_LEFT, 1, 1);
/* left press without movement should not generate events */
litest_button_scroll(dev, BTN_LEFT, 0, 0);
litest_assert_empty_queue(li);
/* Restore default scroll behavior */
libinput_device_config_scroll_set_method(dev->libinput_device,
libinput_device_config_scroll_get_default_method(
dev->libinput_device));
libinput_device_config_scroll_set_button(dev->libinput_device,
libinput_device_config_scroll_get_default_button(
dev->libinput_device));
}
END_TEST
int main (int argc, char **argv) {
litest_add("pointer:motion", pointer_motion_relative, LITEST_POINTER, LITEST_ANY);
litest_add("pointer:motion", pointer_motion_relative, LITEST_RELATIVE, LITEST_ANY);
litest_add("pointer:motion", pointer_motion_absolute, LITEST_ABSOLUTE, LITEST_ANY);
litest_add("pointer:motion", pointer_motion_unaccel, LITEST_RELATIVE, LITEST_ANY);
litest_add("pointer:button", pointer_button, LITEST_BUTTON, LITEST_CLICKPAD);
litest_add_no_device("pointer:button_auto_release", pointer_button_auto_release);
litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_natural_defaults, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_natural_enable_config, LITEST_WHEEL, LITEST_ANY);
litest_add("pointer:scroll", pointer_scroll_natural_wheel, LITEST_WHEEL, LITEST_ANY);
litest_add_no_device("pointer:seat button count", pointer_seat_button_count);
litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH);
litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE);
/* tests touchpads too */
litest_add("pointer:left-handed", pointer_left_handed_defaults, LITEST_BUTTON, LITEST_ANY);
litest_add("pointer:left-handed", pointer_left_handed, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
litest_add("pointer:left-handed", pointer_left_handed_during_click, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
litest_add("pointer:left-handed", pointer_left_handed_during_click_multiple_buttons, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
return litest_run(argc, argv);
}

View file

@ -401,6 +401,70 @@ START_TEST(touch_calibration_translation)
}
END_TEST
START_TEST(touch_no_left_handed)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
enum libinput_config_status status;
int rc;
rc = libinput_device_config_buttons_has_left_handed(d);
ck_assert_int_eq(rc, 0);
rc = libinput_device_config_buttons_get_left_handed(d);
ck_assert_int_eq(rc, 0);
rc = libinput_device_config_buttons_get_default_left_handed(d);
ck_assert_int_eq(rc, 0);
status = libinput_device_config_buttons_set_left_handed(d, 0);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST
START_TEST(fake_mt_exists)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_device *device;
litest_wait_for_event_of_type(li, LIBINPUT_EVENT_DEVICE_ADDED, -1);
event = libinput_get_event(li);
device = libinput_event_get_device(event);
ck_assert(!libinput_device_has_capability(device,
LIBINPUT_DEVICE_CAP_TOUCH));
/* This test may need fixing if we add other fake-mt devices that
* have different capabilities */
ck_assert(libinput_device_has_capability(device,
LIBINPUT_DEVICE_CAP_POINTER));
}
END_TEST
START_TEST(fake_mt_no_touch_events)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 70, 70, 5, 10);
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
litest_touch_down(dev, 1, 70, 70);
litest_touch_move_to(dev, 0, 50, 50, 90, 40, 10, 10);
litest_touch_move_to(dev, 0, 70, 70, 40, 50, 10, 10);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
litest_assert_empty_queue(li);
}
END_TEST
int
main(int argc, char **argv)
{
@ -415,5 +479,10 @@ main(int argc, char **argv)
litest_add("touch:calibration", touch_calibration_translation, LITEST_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:calibration", touch_calibration_translation, LITEST_SINGLE_TOUCH, LITEST_TOUCHPAD);
litest_add("touch:left-handed", touch_no_left_handed, LITEST_TOUCH, LITEST_ANY);
litest_add("touch:fake-mt", fake_mt_exists, LITEST_FAKE_MT, LITEST_ANY);
litest_add("touch:fake-mt", fake_mt_no_touch_events, LITEST_FAKE_MT, LITEST_ANY);
return litest_run(argc, argv);
}

View file

@ -41,7 +41,7 @@ START_TEST(touchpad_1fg_motion)
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 80, 50, 5);
litest_touch_move_to(dev, 0, 50, 50, 80, 50, 5, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
@ -72,8 +72,8 @@ START_TEST(touchpad_2fg_no_motion)
litest_touch_down(dev, 0, 20, 20);
litest_touch_down(dev, 1, 70, 20);
litest_touch_move_to(dev, 0, 20, 20, 80, 80, 5);
litest_touch_move_to(dev, 1, 70, 20, 80, 50, 5);
litest_touch_move_to(dev, 0, 20, 20, 80, 80, 5, 0);
litest_touch_move_to(dev, 1, 70, 20, 80, 50, 5, 0);
litest_touch_up(dev, 1);
litest_touch_up(dev, 0);
@ -107,7 +107,7 @@ START_TEST(touchpad_1fg_tap)
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -131,7 +131,7 @@ START_TEST(touchpad_1fg_tap_n_drag)
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5);
litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40);
litest_touch_up(dev, 0);
libinput_dispatch(li);
@ -150,7 +150,7 @@ START_TEST(touchpad_1fg_tap_n_drag)
/* lift finger, set down again, should continue dragging */
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5);
litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40);
litest_touch_up(dev, 0);
libinput_dispatch(li);
@ -162,7 +162,7 @@ START_TEST(touchpad_1fg_tap_n_drag)
ck_assert_int_eq(libinput_next_event_type(li), LIBINPUT_EVENT_NONE);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -185,7 +185,7 @@ START_TEST(touchpad_1fg_tap_n_drag_timeout)
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
libinput_dispatch(li);
msleep(300);
litest_timeout_tap();
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
@ -200,6 +200,93 @@ START_TEST(touchpad_1fg_tap_n_drag_timeout)
}
END_TEST
START_TEST(touchpad_2fg_tap_n_drag)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
libinput_device_config_tap_set_enabled(dev->libinput_device,
LIBINPUT_CONFIG_TAP_ENABLED);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
litest_touch_down(dev, 1, 60, 50);
litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
while (libinput_next_event_type(li) == LIBINPUT_EVENT_POINTER_MOTION) {
event = libinput_get_event(li);
libinput_event_destroy(event);
libinput_dispatch(li);
}
litest_assert_empty_queue(li);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
/* This will wait for the DRAGGING_WAIT timeout */
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_2fg_tap_n_drag_3fg_btntool)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
libinput_device_config_tap_set_enabled(dev->libinput_device,
LIBINPUT_CONFIG_TAP_ENABLED);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
litest_touch_down(dev, 1, 60, 50);
litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
while (libinput_next_event_type(li) == LIBINPUT_EVENT_POINTER_MOTION) {
event = libinput_get_event(li);
libinput_event_destroy(event);
libinput_dispatch(li);
}
litest_assert_empty_queue(li);
/* Putting down a third finger should end the drag */
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
/* Releasing the fingers should not cause any events */
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 1);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_2fg_tap)
{
struct litest_device *dev = litest_current_device();
@ -219,7 +306,7 @@ START_TEST(touchpad_2fg_tap)
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -246,7 +333,7 @@ START_TEST(touchpad_2fg_tap_inverted)
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -274,7 +361,7 @@ START_TEST(touchpad_1fg_tap_click)
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
msleep(200);
litest_timeout_tap();
libinput_dispatch(li);
@ -400,7 +487,7 @@ START_TEST(touchpad_no_2fg_tap_after_move)
-> no event
*/
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10);
litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10, 0);
litest_drain_events(dev->libinput);
litest_touch_down(dev, 1, 70, 50);
@ -423,7 +510,7 @@ START_TEST(touchpad_no_2fg_tap_after_timeout)
*/
litest_touch_down(dev, 0, 50, 50);
libinput_dispatch(dev->libinput);
msleep(300);
litest_timeout_tap();
libinput_dispatch(dev->libinput);
litest_drain_events(dev->libinput);
@ -450,7 +537,7 @@ START_TEST(touchpad_no_first_fg_tap_after_move)
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);
litest_touch_move_to(dev, 1, 70, 50, 90, 90, 10, 0);
libinput_dispatch(dev->libinput);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
@ -516,7 +603,7 @@ START_TEST(touchpad_1fg_tap_n_drag_click)
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 80, 50, 10);
litest_touch_move_to(dev, 0, 50, 50, 80, 50, 10, 0);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
@ -577,7 +664,7 @@ START_TEST(touchpad_3fg_tap)
litest_assert_button_event(li, BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -613,7 +700,7 @@ START_TEST(touchpad_3fg_tap_btntool)
litest_assert_button_event(li, BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -648,7 +735,7 @@ START_TEST(touchpad_3fg_tap_btntool_inverted)
litest_assert_button_event(li, BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
msleep(300); /* tap-n-drag timeout */
litest_timeout_tap();
litest_assert_button_event(li, BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
@ -750,7 +837,7 @@ START_TEST(clickpad_1fg_tap_click)
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
msleep(200);
litest_timeout_tap();
libinput_dispatch(li);
@ -803,7 +890,7 @@ START_TEST(clickpad_click_n_drag)
/* now put a second finger down */
litest_touch_down(dev, 1, 70, 70);
litest_touch_move_to(dev, 1, 70, 70, 80, 50, 5);
litest_touch_move_to(dev, 1, 70, 70, 80, 50, 5, 0);
litest_touch_up(dev, 1);
libinput_dispatch(li);
@ -997,14 +1084,14 @@ START_TEST(clickpad_softbutton_left_1st_fg_move)
litest_assert_empty_queue(li);
/* move out of the area, then wait for softbutton timer */
litest_touch_move_to(dev, 0, 20, 90, 90, 20, 10);
litest_touch_move_to(dev, 0, 20, 90, 90, 20, 10, 0);
libinput_dispatch(li);
msleep(400);
litest_timeout_softbuttons();
libinput_dispatch(li);
litest_drain_events(li);
/* move down left, expect motion */
litest_touch_move_to(dev, 0, 90, 20, 20, 90, 10);
litest_touch_move_to(dev, 0, 90, 20, 20, 90, 10, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
@ -1070,7 +1157,7 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
litest_assert_empty_queue(li);
litest_touch_down(dev, 1, 20, 20);
litest_touch_move_to(dev, 1, 20, 20, 80, 20, 10);
litest_touch_move_to(dev, 1, 20, 20, 80, 20, 10, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
@ -1086,8 +1173,12 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
x = libinput_event_pointer_get_dx(p);
y = libinput_event_pointer_get_dy(p);
ck_assert(x > 0);
ck_assert(y == 0);
/* Ignore events only containing an unaccelerated motion
* vector. */
if (x != 0 || y != 0) {
ck_assert(x > 0);
ck_assert(y == 0);
}
libinput_event_destroy(event);
libinput_dispatch(li);
@ -1097,7 +1188,7 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
/* second finger down */
litest_touch_down(dev, 1, 20, 20);
litest_touch_move_to(dev, 1, 20, 20, 20, 80, 10);
litest_touch_move_to(dev, 1, 20, 20, 20, 80, 10, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
@ -1148,7 +1239,7 @@ START_TEST(clickpad_softbutton_left_to_right)
*/
litest_touch_down(dev, 0, 20, 90);
litest_touch_move_to(dev, 0, 20, 90, 90, 90, 10);
litest_touch_move_to(dev, 0, 20, 90, 90, 90, 10, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
@ -1182,7 +1273,7 @@ START_TEST(clickpad_softbutton_right_to_left)
*/
litest_touch_down(dev, 0, 90, 90);
litest_touch_move_to(dev, 0, 90, 90, 20, 90, 10);
litest_touch_move_to(dev, 0, 90, 90, 20, 90, 10, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
@ -1302,13 +1393,13 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore)
litest_touch_down(dev, 0, 50, 5);
libinput_dispatch(li);
msleep(200);
litest_timeout_softbuttons();
libinput_dispatch(li);
litest_assert_empty_queue(li);
litest_touch_move_to(dev, 0, 50, 5, 80, 90, 20);
litest_touch_move_to(dev, 0, 50, 5, 80, 90, 20, 0);
libinput_dispatch(li);
msleep(400);
litest_timeout_softbuttons();
libinput_dispatch(li);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
@ -1323,20 +1414,20 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore)
END_TEST
static void
test_2fg_scroll(struct litest_device *dev, double dx, double dy, int sleep)
test_2fg_scroll(struct litest_device *dev, double dx, double dy, int want_sleep)
{
struct libinput *li = dev->libinput;
litest_touch_down(dev, 0, 47, 50);
litest_touch_down(dev, 1, 53, 50);
litest_touch_move_to(dev, 0, 47, 50, 47 + dx, 50 + dy, 5);
litest_touch_move_to(dev, 1, 53, 50, 53 + dx, 50 + dy, 5);
litest_touch_move_to(dev, 0, 47, 50, 47 + dx, 50 + dy, 5, 0);
litest_touch_move_to(dev, 1, 53, 50, 53 + dx, 50 + dy, 5, 0);
/* Avoid a small scroll being seen as a tap */
if (sleep) {
if (want_sleep) {
libinput_dispatch(li);
msleep(sleep);
litest_timeout_tap();
libinput_dispatch(li);
}
@ -1368,6 +1459,96 @@ START_TEST(touchpad_2fg_scroll)
}
END_TEST
START_TEST(touchpad_2fg_scroll_slow_distance)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
litest_drain_events(li);
litest_touch_down(dev, 0, 20, 30);
litest_touch_down(dev, 1, 40, 30);
litest_touch_move_to(dev, 0, 20, 30, 20, 50, 60, 10);
litest_touch_move_to(dev, 1, 40, 30, 40, 50, 60, 10);
litest_touch_up(dev, 1);
litest_touch_up(dev, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert_notnull(event);
/* last event is value 0, tested elsewhere */
while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_AXIS);
ptrev = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev),
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
ck_assert(libinput_event_pointer_get_axis_value(ptrev) > 0.0);
/* this is to verify we test the right thing, if the value
is greater than scroll.threshold we triggered the wrong
condition */
ck_assert(libinput_event_pointer_get_axis_value(ptrev) < 5.0);
libinput_event_destroy(event);
event = libinput_get_event(li);
}
litest_assert_empty_queue(li);
libinput_event_destroy(event);
}
END_TEST
START_TEST(touchpad_scroll_natural_defaults)
{
struct litest_device *dev = litest_current_device();
ck_assert_int_ge(libinput_device_config_scroll_has_natural_scroll(dev->libinput_device), 1);
ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 0);
ck_assert_int_eq(libinput_device_config_scroll_get_default_natural_scroll_enabled(dev->libinput_device), 0);
}
END_TEST
START_TEST(touchpad_scroll_natural_enable_config)
{
struct litest_device *dev = litest_current_device();
enum libinput_config_status status;
status = libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 1);
status = libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 0);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
ck_assert_int_eq(libinput_device_config_scroll_get_natural_scroll_enabled(dev->libinput_device), 0);
}
END_TEST
START_TEST(touchpad_scroll_natural)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
litest_drain_events(li);
libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);
test_2fg_scroll(dev, 0.1, 40, 0);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -10);
test_2fg_scroll(dev, 0.1, -40, 0);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 10);
test_2fg_scroll(dev, 40, 0.1, 0);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -10);
test_2fg_scroll(dev, -40, 0.1, 0);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 10);
}
END_TEST
START_TEST(touchpad_tap_is_available)
{
struct litest_device *dev = litest_current_device();
@ -1436,13 +1617,13 @@ START_TEST(touchpad_palm_detect_at_edge)
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 50);
litest_touch_move_to(dev, 0, 99, 50, 99, 70, 5);
litest_touch_move_to(dev, 0, 99, 50, 99, 70, 5, 0);
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_move_to(dev, 0, 5, 50, 5, 70, 5, 0);
litest_touch_up(dev, 0);
}
END_TEST
@ -1460,13 +1641,13 @@ START_TEST(touchpad_palm_detect_at_bottom_corners)
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 95);
litest_touch_move_to(dev, 0, 99, 95, 99, 99, 10);
litest_touch_move_to(dev, 0, 99, 95, 99, 99, 10, 0);
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_move_to(dev, 0, 5, 95, 5, 99, 5, 0);
litest_touch_up(dev, 0);
}
END_TEST
@ -1484,13 +1665,13 @@ START_TEST(touchpad_palm_detect_at_top_corners)
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 5);
litest_touch_move_to(dev, 0, 99, 5, 99, 9, 10);
litest_touch_move_to(dev, 0, 99, 5, 99, 9, 10, 0);
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_move_to(dev, 0, 5, 5, 5, 9, 5, 0);
litest_touch_up(dev, 0);
}
END_TEST
@ -1506,7 +1687,7 @@ START_TEST(touchpad_palm_detect_palm_stays_palm)
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 20);
litest_touch_move_to(dev, 0, 99, 20, 75, 99, 5);
litest_touch_move_to(dev, 0, 99, 20, 75, 99, 5, 0);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
}
@ -1525,7 +1706,7 @@ START_TEST(touchpad_palm_detect_palm_becomes_pointer)
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 50);
litest_touch_move_to(dev, 0, 99, 50, 0, 70, 5);
litest_touch_move_to(dev, 0, 99, 50, 0, 70, 5, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
@ -1558,11 +1739,11 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_edges)
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 99, 50, 5);
litest_touch_move_to(dev, 0, 50, 50, 99, 50, 5, 0);
litest_drain_events(li);
litest_touch_move_to(dev, 0, 99, 50, 99, 90, 5);
litest_touch_move_to(dev, 0, 99, 50, 99, 90, 5, 0);
libinput_dispatch(li);
type = libinput_next_event_type(li);
@ -1582,14 +1763,314 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_edges)
}
END_TEST
START_TEST(touchpad_left_handed)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_button_click(dev, BTN_RIGHT, 1);
litest_button_click(dev, BTN_RIGHT, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
if (libevdev_has_event_code(dev->evdev,
EV_KEY,
BTN_MIDDLE)) {
litest_button_click(dev, BTN_MIDDLE, 1);
litest_button_click(dev, BTN_MIDDLE, 0);
litest_assert_button_event(li,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
}
}
END_TEST
START_TEST(touchpad_left_handed_clickpad)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_touch_down(dev, 0, 10, 90);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 90);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_left_handed_clickfinger)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_touch_down(dev, 0, 10, 90);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
/* Clickfinger is unaffected by left-handed setting */
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_drain_events(li);
litest_touch_down(dev, 0, 10, 90);
litest_touch_down(dev, 1, 30, 90);
litest_button_click(dev, BTN_LEFT, 1);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_left_handed_tapping)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
libinput_device_config_tap_set_enabled(dev->libinput_device,
LIBINPUT_CONFIG_TAP_ENABLED);
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_timeout_tap();
libinput_dispatch(li);
/* Tapping is unaffected by left-handed setting */
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_left_handed_tapping_2fg)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
libinput_device_config_tap_set_enabled(dev->libinput_device,
LIBINPUT_CONFIG_TAP_ENABLED);
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
litest_touch_down(dev, 0, 50, 50);
litest_touch_down(dev, 1, 70, 50);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
libinput_dispatch(li);
litest_timeout_tap();
libinput_dispatch(li);
/* Tapping is unaffected by left-handed setting */
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_left_handed_delayed)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
litest_drain_events(li);
litest_button_click(dev, BTN_LEFT, 1);
libinput_dispatch(li);
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_button_click(dev, BTN_LEFT, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
/* left-handed takes effect now */
litest_button_click(dev, BTN_RIGHT, 1);
litest_button_click(dev, BTN_LEFT, 1);
libinput_dispatch(li);
status = libinput_device_config_buttons_set_left_handed(d, 0);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_button_click(dev, BTN_RIGHT, 0);
litest_button_click(dev, BTN_LEFT, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_left_handed_clickpad_delayed)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *d = dev->libinput_device;
struct libinput *li = dev->libinput;
enum libinput_config_status status;
litest_drain_events(li);
litest_touch_down(dev, 0, 10, 90);
litest_button_click(dev, BTN_LEFT, 1);
libinput_dispatch(li);
status = libinput_device_config_buttons_set_left_handed(d, 1);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
/* left-handed takes effect now */
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 90);
litest_button_click(dev, BTN_LEFT, 1);
libinput_dispatch(li);
status = libinput_device_config_buttons_set_left_handed(d, 0);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_button_click(dev, BTN_LEFT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
int main(int argc, char **argv) {
litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:motion", touchpad_2fg_no_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:tap", touchpad_2fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_2fg_tap_n_drag_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD);
litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_2fg_tap_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD, LITEST_CLICKPAD);
@ -1640,6 +2121,10 @@ int main(int argc, char **argv) {
litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:scroll", touchpad_2fg_scroll_slow_distance, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_scroll_natural, 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);
@ -1648,5 +2133,13 @@ int main(int argc, char **argv) {
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);
litest_add("touchpad:left-handed", touchpad_left_handed, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
litest_add("touchpad:left-handed", touchpad_left_handed_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY);
litest_add("touchpad:left-handed", touchpad_left_handed_tapping, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:left-handed", touchpad_left_handed_tapping_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:left-handed", touchpad_left_handed_delayed, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad_delayed, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
return litest_run(argc, argv);
}

View file

@ -49,26 +49,6 @@ START_TEST(trackpoint_middlebutton)
}
END_TEST
static void
test_2fg_scroll(struct litest_device *dev, double dx, double dy)
{
struct libinput *li = dev->libinput;
litest_button_click(dev, BTN_MIDDLE, 1);
libinput_dispatch(li);
msleep(300);
libinput_dispatch(li);
litest_event(dev, EV_REL, REL_X, dx);
litest_event(dev, EV_REL, REL_Y, dy);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_button_click(dev, BTN_MIDDLE, 0);
libinput_dispatch(li);
}
START_TEST(trackpoint_scroll)
{
struct litest_device *dev = litest_current_device();
@ -76,27 +56,61 @@ START_TEST(trackpoint_scroll)
litest_drain_events(li);
test_2fg_scroll(dev, 1, 6);
litest_button_scroll(dev, BTN_MIDDLE, 1, 6);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 6);
test_2fg_scroll(dev, 1, -7);
litest_button_scroll(dev, BTN_MIDDLE, 1, -7);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -7);
test_2fg_scroll(dev, 8, 1);
litest_button_scroll(dev, BTN_MIDDLE, 8, 1);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 8);
test_2fg_scroll(dev, -9, 1);
litest_button_scroll(dev, BTN_MIDDLE, -9, 1);
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
/* scroll smaller than the threshold should not generate events */
test_2fg_scroll(dev, 1, 1);
litest_button_scroll(dev, BTN_MIDDLE, 1, 1);
/* long middle press without movement should not generate events */
test_2fg_scroll(dev, 0, 0);
litest_button_scroll(dev, BTN_MIDDLE, 0, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(trackpoint_middlebutton_noscroll)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
/* Disable middle button scrolling */
libinput_device_config_scroll_set_method(dev->libinput_device,
LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
litest_drain_events(li);
/* A long middle button click + motion should get reported normally now */
litest_button_scroll(dev, BTN_MIDDLE, 0, 10);
litest_assert_button_event(li, BTN_MIDDLE, 1);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(event);
litest_assert_button_event(li, BTN_MIDDLE, 0);
litest_assert_empty_queue(li);
/* Restore default scroll behavior */
libinput_device_config_scroll_set_method(dev->libinput_device,
libinput_device_config_scroll_get_default_method(
dev->libinput_device));
}
END_TEST
int main(int argc, char **argv) {
litest_add("trackpoint:middlebutton", trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY);
litest_add("trackpoint:middlebutton", trackpoint_middlebutton_noscroll, LITEST_POINTINGSTICK, LITEST_ANY);
litest_add("trackpoint:scroll", trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY);
return litest_run(argc, argv);

View file

@ -175,6 +175,81 @@ START_TEST(udev_added_seat_default)
}
END_TEST
/**
* This test only works if there's at least one device in the system that is
* assigned the default seat. Should cover the 99% case.
*/
START_TEST(udev_change_seat)
{
struct libinput *li;
struct udev *udev;
struct libinput_event *event;
struct libinput_device *device;
struct libinput_seat *seat1, *seat2;
const char *seat1_name;
const char *seat2_name = "new seat";
int rc;
udev = udev_new();
ck_assert(udev != NULL);
li = libinput_udev_create_context(&simple_interface, NULL, udev);
ck_assert(li != NULL);
ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert(event != NULL);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_DEVICE_ADDED);
device = libinput_event_get_device(event);
libinput_device_ref(device);
seat1 = libinput_device_get_seat(device);
libinput_seat_ref(seat1);
seat1_name = libinput_seat_get_logical_name(seat1);
libinput_event_destroy(event);
litest_drain_events(li);
rc = libinput_device_set_seat_logical_name(device,
seat2_name);
ck_assert_int_eq(rc, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_DEVICE_REMOVED);
ck_assert(libinput_event_get_device(event) == device);
libinput_event_destroy(event);
event = libinput_get_event(li);
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_DEVICE_ADDED);
ck_assert(libinput_event_get_device(event) != device);
libinput_device_unref(device);
device = libinput_event_get_device(event);
seat2 = libinput_device_get_seat(device);
ck_assert_str_ne(libinput_seat_get_logical_name(seat2),
seat1_name);
ck_assert_str_eq(libinput_seat_get_logical_name(seat2),
seat2_name);
libinput_event_destroy(event);
libinput_seat_unref(seat1);
libinput_unref(li);
udev_unref(udev);
}
END_TEST
START_TEST(udev_double_suspend)
{
struct libinput *li;
@ -414,7 +489,8 @@ main(int argc, char **argv)
litest_add_no_device("udev:create", udev_create_seat0);
litest_add_no_device("udev:create", udev_create_empty_seat);
litest_add_no_device("udev:seat events", udev_added_seat_default);
litest_add_no_device("udev:seat", udev_added_seat_default);
litest_add_no_device("udev:seat", udev_change_seat);
litest_add_for_device("udev:suspend", udev_double_suspend, LITEST_SYNAPTICS_CLICKPAD);
litest_add_for_device("udev:suspend", udev_double_resume, LITEST_SYNAPTICS_CLICKPAD);

View file

@ -269,15 +269,38 @@ print_device_notify(struct libinput_event *ev)
struct libinput_device *dev = libinput_event_get_device(ev);
struct libinput_seat *seat = libinput_device_get_seat(dev);
double w, h;
uint32_t scroll_methods;
printf("%s %s",
printf("%-30s %s %s",
libinput_device_get_name(dev),
libinput_seat_get_physical_name(seat),
libinput_seat_get_logical_name(seat));
if (libinput_device_get_size(dev, &w, &h) == 0)
printf("\tsize %.2f/%.2fmm", w, h);
if (libinput_device_config_tap_get_finger_count((dev)))
printf(" tap");
if (libinput_device_config_buttons_has_left_handed((dev)))
printf(" left");
if (libinput_device_config_scroll_has_natural_scroll((dev)))
printf(" scroll-nat");
if (libinput_device_config_calibration_has_matrix((dev)))
printf(" calib");
scroll_methods = libinput_device_config_scroll_get_methods(dev);
if (scroll_methods != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) {
printf(" scroll");
if (scroll_methods & LIBINPUT_CONFIG_SCROLL_2FG)
printf("-2fg");
if (scroll_methods & LIBINPUT_CONFIG_SCROLL_EDGE)
printf("-edge");
if (scroll_methods & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)
printf("-button");
}
printf("\n");
}
static void

View file

@ -67,6 +67,8 @@ struct window {
/* l/m/r mouse buttons */
int l, m, r;
struct libinput_device *devices[50];
};
static int
@ -211,18 +213,69 @@ window_init(struct window *w)
gtk_widget_show_all(w->win);
}
static void
window_cleanup(struct window *w)
{
struct libinput_device **dev;
ARRAY_FOR_EACH(w->devices, dev) {
if (*dev)
libinput_device_unref(*dev);
}
}
static void
change_ptraccel(struct window *w, double amount)
{
struct libinput_device **dev;
ARRAY_FOR_EACH(w->devices, dev) {
double speed;
enum libinput_config_status status;
if (*dev == NULL)
continue;
if (!libinput_device_config_accel_is_available(*dev))
continue;
speed = libinput_device_config_accel_get_speed(*dev);
speed = clip(speed + amount, -1, 1);
status = libinput_device_config_accel_set_speed(*dev, speed);
if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) {
msg("%s: failed to change accel to %.2f (%s)\n",
libinput_device_get_name(*dev),
speed,
libinput_config_status_to_str(status));
} else {
printf("%s: speed is %.2f\n",
libinput_device_get_name(*dev),
speed);
}
}
}
static void
handle_event_device_notify(struct libinput_event *ev)
{
struct libinput_device *dev = libinput_event_get_device(ev);
struct libinput *li;
struct window *w;
const char *type;
int i;
if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED)
type = "added";
else
type = "removed";
msg("%s %s\n", libinput_device_get_sysname(dev), type);
msg("%s %-30s %s\n",
libinput_device_get_sysname(dev),
libinput_device_get_name(dev),
type);
if (libinput_device_config_tap_get_finger_count(dev) > 0) {
enum libinput_config_status status;
@ -232,6 +285,26 @@ handle_event_device_notify(struct libinput_event *ev)
error("%s: Failed to enable tapping\n",
libinput_device_get_sysname(dev));
}
li = libinput_event_get_context(ev);
w = libinput_get_user_data(li);
if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) {
for (i = 0; i < ARRAY_LENGTH(w->devices); i++) {
if (w->devices[i] == NULL) {
w->devices[i] = libinput_device_ref(dev);
break;
}
}
} else {
for (i = 0; i < ARRAY_LENGTH(w->devices); i++) {
if (w->devices[i] == dev) {
libinput_device_unref(w->devices[i]);
w->devices[i] = NULL;
break;
}
}
}
}
static void
@ -309,9 +382,24 @@ static int
handle_event_keyboard(struct libinput_event *ev, struct window *w)
{
struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
unsigned int key = libinput_event_keyboard_get_key(k);
if (libinput_event_keyboard_get_key(k) == KEY_ESC)
if (libinput_event_keyboard_get_key_state(k) ==
LIBINPUT_KEY_STATE_RELEASED)
return 0;
switch(key) {
case KEY_ESC:
return 1;
case KEY_UP:
change_ptraccel(w, 0.1);
break;
case KEY_DOWN:
change_ptraccel(w, -0.1);
break;
default:
break;
}
return 0;
}
@ -479,6 +567,7 @@ main(int argc, char *argv[])
gtk_main();
window_cleanup(&w);
libinput_unref(li);
udev_unref(udev);