🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1041 lines
32 KiB

  1. /*
  2. Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
  3. Copyright (C) 2020-2022 Collabora Ltd.
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely.
  10. */
  11. #include "../src/SDL_internal.h"
  12. #include <stdio.h>
  13. #include <string.h>
  14. static int run_test(void);
  15. #if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
  16. #include <stdint.h>
  17. #include "SDL_stdinc.h"
  18. #include "SDL_endian.h"
  19. #include "../src/core/linux/SDL_evdev_capabilities.h"
  20. #include "../src/core/linux/SDL_evdev_capabilities.c"
  21. static const struct
  22. {
  23. int code;
  24. const char *name;
  25. } device_classes[] =
  26. {
  27. #define CLS(x) \
  28. { SDL_UDEV_DEVICE_ ## x, #x }
  29. CLS(MOUSE),
  30. CLS(KEYBOARD),
  31. CLS(JOYSTICK),
  32. CLS(SOUND),
  33. CLS(TOUCHSCREEN),
  34. CLS(ACCELEROMETER),
  35. CLS(TOUCHPAD),
  36. #undef CLS
  37. { 0, NULL }
  38. };
  39. typedef struct
  40. {
  41. const char *name;
  42. uint16_t bus_type;
  43. uint16_t vendor_id;
  44. uint16_t product_id;
  45. uint16_t version;
  46. uint8_t ev[(EV_MAX + 1) / 8];
  47. uint8_t keys[(KEY_MAX + 1) / 8];
  48. uint8_t abs[(ABS_MAX + 1) / 8];
  49. uint8_t rel[(REL_MAX + 1) / 8];
  50. uint8_t ff[(FF_MAX + 1) / 8];
  51. uint8_t props[INPUT_PROP_MAX / 8];
  52. int expected;
  53. } GuessTest;
  54. /*
  55. * Test-cases for guessing a device type from its capabilities.
  56. *
  57. * The bytes in ev, etc. are in little-endian byte order
  58. * Trailing zeroes can be omitted.
  59. *
  60. * The evemu-describe tool is a convenient way to add a test-case for
  61. * a physically available device.
  62. */
  63. #define ZEROx4 0, 0, 0, 0
  64. #define ZEROx8 ZEROx4, ZEROx4
  65. #define FFx4 0xff, 0xff, 0xff, 0xff
  66. #define FFx8 FFx4, FFx4
  67. /* Test-cases derived from real devices or from Linux kernel source */
  68. static const GuessTest guess_tests[] =
  69. {
  70. {
  71. .name = "Xbox 360 wired USB controller",
  72. .bus_type = 0x0003,
  73. .vendor_id = 0x045e,
  74. .product_id = 0x028e,
  75. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  76. /* SYN, KEY, ABS, FF */
  77. .ev = { 0x0b, 0x00, 0x20 },
  78. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  79. .abs = { 0x3f, 0x00, 0x03 },
  80. .keys = {
  81. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  82. /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
  83. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
  84. },
  85. },
  86. {
  87. .name = "X-Box One Elite",
  88. .bus_type = 0x0003,
  89. .vendor_id = 0x045e,
  90. .product_id = 0x02e3,
  91. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  92. /* SYN, KEY, ABS */
  93. .ev = { 0x0b },
  94. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  95. .abs = { 0x3f, 0x00, 0x03 },
  96. .keys = {
  97. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  98. /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
  99. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
  100. },
  101. },
  102. {
  103. .name = "X-Box One S via Bluetooth",
  104. .bus_type = 0x0005,
  105. .vendor_id = 0x045e,
  106. .product_id = 0x02e0,
  107. .version = 0x1130,
  108. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  109. /* SYN, KEY, ABS */
  110. .ev = { 0x0b },
  111. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  112. .abs = { 0x3f, 0x00, 0x03 },
  113. .keys = {
  114. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  115. /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
  116. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
  117. },
  118. },
  119. {
  120. .name = "X-Box One S wired",
  121. .bus_type = 0x0003,
  122. .vendor_id = 0x045e,
  123. .product_id = 0x02ea,
  124. .version = 0x0301,
  125. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  126. /* SYN, KEY, ABS */
  127. .ev = { 0x0b },
  128. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  129. .abs = { 0x3f, 0x00, 0x03 },
  130. .keys = {
  131. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  132. /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
  133. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
  134. },
  135. },
  136. {
  137. .name = "DualShock 4 - gamepad",
  138. .bus_type = 0x0003,
  139. .vendor_id = 0x054c,
  140. .product_id = 0x09cc,
  141. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  142. /* SYN, KEY, ABS, MSC, FF */
  143. /* Some versions only have 0x0b, SYN, KEY, ABS, like the
  144. * Bluetooth example below */
  145. .ev = { 0x1b, 0x00, 0x20 },
  146. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  147. .abs = { 0x3f, 0x00, 0x03 },
  148. .keys = {
  149. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  150. /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
  151. * THUMBL, THUMBR */
  152. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
  153. },
  154. },
  155. {
  156. .name = "DualShock 4 - gamepad via Bluetooth",
  157. .bus_type = 0x0005,
  158. .vendor_id = 0x054c,
  159. .product_id = 0x09cc,
  160. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  161. /* SYN, KEY, ABS */
  162. .ev = { 0x0b },
  163. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  164. .abs = { 0x3f, 0x00, 0x03 },
  165. .keys = {
  166. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  167. /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
  168. * THUMBL, THUMBR */
  169. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
  170. },
  171. },
  172. {
  173. .name = "DualShock 4 - touchpad",
  174. .bus_type = 0x0003,
  175. .vendor_id = 0x054c,
  176. .product_id = 0x09cc,
  177. .expected = SDL_UDEV_DEVICE_TOUCHPAD,
  178. /* SYN, KEY, ABS */
  179. .ev = { 0x0b },
  180. /* X, Y, multitouch */
  181. .abs = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x02 },
  182. .keys = {
  183. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  184. /* Left mouse button */
  185. /* 0x100 */ 0x00, 0x00, 0x01, 0x00, ZEROx4,
  186. /* BTN_TOOL_FINGER and some multitouch stuff */
  187. /* 0x140 */ 0x20, 0x24, 0x00, 0x00
  188. },
  189. /* POINTER, BUTTONPAD */
  190. .props = { 0x05 },
  191. },
  192. {
  193. .name = "DualShock 4 - accelerometer",
  194. .bus_type = 0x0003,
  195. .vendor_id = 0x054c,
  196. .product_id = 0x09cc,
  197. .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
  198. /* SYN, ABS, MSC */
  199. .ev = { 0x19 },
  200. /* X, Y, Z, RX, RY, RZ */
  201. .abs = { 0x3f },
  202. /* ACCELEROMETER */
  203. .props = { 0x40 },
  204. },
  205. {
  206. .name = "DualShock 4 via USB dongle",
  207. .bus_type = 0x0003,
  208. .vendor_id = 0x054c,
  209. .product_id = 0x0ba0,
  210. .version = 0x8111,
  211. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  212. /* SYN, ABS, KEY */
  213. .ev = { 0x0b },
  214. /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
  215. .abs = { 0x3f, 0x00, 0x03 },
  216. .keys = {
  217. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  218. /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
  219. * THUMBL, THUMBR */
  220. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
  221. },
  222. },
  223. {
  224. .name = "DualShock 3 - gamepad",
  225. .bus_type = 0x0003,
  226. .vendor_id = 0x054c,
  227. .product_id = 0x0268,
  228. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  229. /* SYN, KEY, ABS, MSC, FF */
  230. .ev = { 0x1b, 0x00, 0x20 },
  231. /* X, Y, Z, RX, RY, RZ */
  232. .abs = { 0x3f },
  233. .keys = {
  234. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  235. /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
  236. * THUMBL, THUMBR */
  237. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
  238. /* 0x140 */ ZEROx8,
  239. /* 0x180 */ ZEROx8,
  240. /* 0x1c0 */ ZEROx8,
  241. /* Digital dpad */
  242. /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
  243. },
  244. },
  245. {
  246. .name = "DualShock 3 - accelerometer",
  247. .bus_type = 0x0003,
  248. .vendor_id = 0x054c,
  249. .product_id = 0x0268,
  250. .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
  251. /* SYN, ABS */
  252. .ev = { 0x09 },
  253. /* X, Y, Z */
  254. .abs = { 0x07 },
  255. /* ACCELEROMETER */
  256. .props = { 0x40 },
  257. },
  258. {
  259. .name = "Steam Controller - gamepad",
  260. .bus_type = 0x0003,
  261. .vendor_id = 0x28de,
  262. .product_id = 0x1142,
  263. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  264. /* SYN, KEY, ABS */
  265. .ev = { 0x0b },
  266. /* X, Y, RX, RY, HAT0X, HAT0Y, HAT2X, HAT2Y */
  267. .abs = { 0x1b, 0x00, 0x33 },
  268. .keys = {
  269. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  270. /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
  271. * THUMBL, THUMBR, joystick THUMB, joystick THUMB2 */
  272. /* 0x100 */ ZEROx4, 0x06, 0x00, 0xdb, 0x7f,
  273. /* GEAR_DOWN, GEAR_UP */
  274. /* 0x140 */ 0x00, 0x00, 0x03, 0x00, ZEROx4,
  275. /* 0x180 */ ZEROx8,
  276. /* 0x1c0 */ ZEROx8,
  277. /* Digital dpad */
  278. /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
  279. },
  280. },
  281. {
  282. /* Present to support lizard mode, even if no Steam Controller
  283. * is connected */
  284. .name = "Steam Controller - dongle",
  285. .bus_type = 0x0003,
  286. .vendor_id = 0x28de,
  287. .product_id = 0x1142,
  288. .expected = (SDL_UDEV_DEVICE_KEYBOARD
  289. | SDL_UDEV_DEVICE_MOUSE),
  290. /* SYN, KEY, REL, MSC, LED, REP */
  291. .ev = { 0x17, 0x00, 0x12 },
  292. /* X, Y, mouse wheel, high-res mouse wheel */
  293. .rel = { 0x03, 0x09 },
  294. .keys = {
  295. /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
  296. /* 0x40 */ 0xff, 0xff, 0xcf, 0x01, 0xdf, 0xff, 0x80, 0xe0,
  297. /* 0x80 */ ZEROx8,
  298. /* 0xc0 */ ZEROx8,
  299. /* 0x100 */ 0x00, 0x00, 0x1f, 0x00, ZEROx4,
  300. },
  301. },
  302. {
  303. .name = "Guitar Hero for PS3",
  304. .bus_type = 0x0003,
  305. .vendor_id = 0x12ba,
  306. .product_id = 0x0100,
  307. .version = 0x0110,
  308. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  309. /* SYN, KEY, ABS */
  310. .ev = { 0x0b },
  311. /* X, Y, Z, RZ, HAT0X, HAT0Y */
  312. .abs = { 0x27, 0x00, 0x03 },
  313. .keys = {
  314. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  315. /* ABC, XYZ, TL, TR, TL2, TR2, SELECT, START, MODE */
  316. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x1f,
  317. },
  318. },
  319. {
  320. .name = "G27 Racing Wheel, 0003:046d:c29b v0111",
  321. .bus_type = 0x0003,
  322. .vendor_id = 0x046d,
  323. .product_id = 0xc29b,
  324. .version = 0x0111,
  325. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  326. /* SYN, KEY, ABS */
  327. .ev = { 0x0b },
  328. /* X, Y, Z, RZ, HAT0X, HAT0Y */
  329. .abs = { 0x27, 0x00, 0x03 },
  330. .keys = {
  331. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  332. /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
  333. * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
  334. /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
  335. /* 0x140 */ ZEROx8,
  336. /* 0x180 */ ZEROx8,
  337. /* 0x1c0 */ ZEROx8,
  338. /* 0x200 */ ZEROx8,
  339. /* 0x240 */ ZEROx8,
  340. /* 0x280 */ ZEROx8,
  341. /* TRIGGER_HAPPY1..TRIGGER_HAPPY7 */
  342. /* 0x2c0 */ 0x7f,
  343. },
  344. },
  345. {
  346. .name = "Logitech Driving Force, 0003:046d:c294 v0100",
  347. .bus_type = 0x0003,
  348. .vendor_id = 0x046d,
  349. .product_id = 0xc294,
  350. .version = 0x0100,
  351. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  352. /* SYN, KEY, ABS */
  353. .ev = { 0x0b },
  354. /* X, Y, RZ, HAT0X, HAT0Y */
  355. .abs = { 0x23, 0x00, 0x03 },
  356. .keys = {
  357. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  358. /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
  359. * BASE2..BASE6 */
  360. /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
  361. },
  362. },
  363. {
  364. .name = "Logitech Dual Action",
  365. .bus_type = 0x0003,
  366. .vendor_id = 0x046d,
  367. .product_id = 0xc216,
  368. .version = 0x0110,
  369. /* Logitech RumblePad 2 USB, 0003:046d:c218 v0110, is the same
  370. * except for having force feedback, which we don't use in our
  371. * heuristic */
  372. /* Jess Tech GGE909 PC Recoil Pad, 0003:0f30:010b v0110, is the same */
  373. /* 8BitDo SNES30, 0003:2dc8:ab20 v0110, is the same */
  374. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  375. /* SYN, KEY, ABS */
  376. .ev = { 0x0b },
  377. /* X, Y, Z, RZ, HAT0X, HAT0Y */
  378. .abs = { 0x27, 0x00, 0x03 },
  379. .keys = {
  380. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  381. /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
  382. * BASE2..BASE6 */
  383. /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
  384. },
  385. },
  386. {
  387. .name = "Saitek ST290 Pro flight stick",
  388. .bus_type = 0x0003,
  389. .vendor_id = 0x06a3,
  390. .product_id = 0x0160, /* 0x0460 seems to be the same */
  391. .version = 0x0100,
  392. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  393. /* SYN, KEY, ABS, MSC */
  394. .ev = { 0x1b },
  395. /* X, Y, Z, RZ, HAT0X, HAT0Y */
  396. .abs = { 0x27, 0x00, 0x03 },
  397. .keys = {
  398. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  399. /* TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE */
  400. /* 0x100 */ ZEROx4, 0x3f, 0x00, 0x00, 0x00,
  401. },
  402. },
  403. {
  404. .name = "Saitek X52 Pro Flight Control System",
  405. .bus_type = 0x0003,
  406. .vendor_id = 0x06a3,
  407. .product_id = 0x0762,
  408. .version = 0x0111,
  409. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  410. .ev = { 0x0b },
  411. /* XYZ, RXYZ, throttle, hat0, MISC, unregistered event code 0x29 */
  412. .abs = { 0x7f, 0x00, 0x03, 0x00, 0x00, 0x03 },
  413. .keys = {
  414. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  415. /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
  416. * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
  417. /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
  418. /* 0x140 */ ZEROx8,
  419. /* 0x180 */ ZEROx8,
  420. /* 0x1c0 */ ZEROx8,
  421. /* 0x200 */ ZEROx8,
  422. /* 0x240 */ ZEROx8,
  423. /* 0x280 */ ZEROx8,
  424. /* TRIGGER_HAPPY1..TRIGGER_HAPPY23 */
  425. /* 0x2c0 */ 0xff, 0xff, 0x7f,
  426. },
  427. },
  428. {
  429. .name = "Logitech Extreme 3D",
  430. .bus_type = 0x0003,
  431. .vendor_id = 0x046d,
  432. .product_id = 0xc215,
  433. .version = 0x0110,
  434. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  435. /* SYN, KEY, ABS, MSC */
  436. .ev = { 0x0b },
  437. /* X, Y, RZ, throttle, hat 0 */
  438. .abs = { 0x63, 0x00, 0x03 },
  439. .keys = {
  440. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  441. /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
  442. * BASE2..BASE6 */
  443. /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
  444. },
  445. },
  446. {
  447. .name = "Hori Real Arcade Pro VX-SA",
  448. .bus_type = 0x0003,
  449. .vendor_id = 0x24c6,
  450. .product_id = 0x5501,
  451. .version = 0x0533,
  452. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  453. /* SYN, KEY, ABS */
  454. .ev = { 0x0b },
  455. /* X, Y, Z, RX, RY, RZ, hat 0 */
  456. .abs = { 0x3f, 0x00, 0x03 },
  457. .keys = {
  458. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  459. /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
  460. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
  461. },
  462. },
  463. {
  464. .name = "Switch Pro Controller via Bluetooth",
  465. .bus_type = 0x0005,
  466. .vendor_id = 0x057e,
  467. .product_id = 0x2009,
  468. .version = 0x0001,
  469. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  470. /* SYN, KEY, ABS */
  471. .ev = { 0x0b },
  472. /* X, Y, RX, RY, hat 0 */
  473. .abs = { 0x1b, 0x00, 0x03 },
  474. .keys = {
  475. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  476. /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
  477. * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
  478. /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
  479. /* 0x140 */ ZEROx8,
  480. /* 0x180 */ ZEROx8,
  481. /* 0x1c0 */ ZEROx8,
  482. /* 0x200 */ ZEROx8,
  483. /* 0x240 */ ZEROx8,
  484. /* 0x280 */ ZEROx8,
  485. /* TRIGGER_HAPPY1..TRIGGER_HAPPY2 */
  486. /* 0x2c0 */ 0x03,
  487. },
  488. },
  489. {
  490. .name = "Switch Pro Controller via USB",
  491. .bus_type = 0x0003,
  492. .vendor_id = 0x057e,
  493. .product_id = 0x2009,
  494. .version = 0x0111,
  495. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  496. /* SYN, KEY, ABS */
  497. .ev = { 0x0b },
  498. /* X, Y, Z, RZ, HAT0X, HAT0Y */
  499. .abs = { 0x27, 0x00, 0x03 },
  500. .keys = {
  501. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  502. },
  503. },
  504. {
  505. .name = "Thrustmaster Racing Wheel FFB",
  506. /* Mad Catz FightStick TE S+ PS4, 0003:0738:8384:0111 v0111
  507. * (aka Street Fighter V Arcade FightStick TES+)
  508. * is functionally the same */
  509. .bus_type = 0x0003,
  510. .vendor_id = 0x044f,
  511. .product_id = 0xb66d,
  512. .version = 0x0110,
  513. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  514. .ev = { 0x0b },
  515. /* XYZ, RXYZ, hat 0 */
  516. .abs = { 0x3f, 0x00, 0x03 },
  517. .keys = {
  518. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  519. /* ABC, XYZ, TL, TR, TL2, TR2, SELECT, START, MODE,
  520. * THUMBL */
  521. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x3f,
  522. },
  523. },
  524. {
  525. .name = "Thrustmaster T.Flight Hotas X",
  526. .bus_type = 0x0003,
  527. .vendor_id = 0x044f,
  528. .product_id = 0xb108,
  529. .version = 0x0100,
  530. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  531. .ev = { 0x0b },
  532. /* XYZ, RZ, throttle, hat 0 */
  533. .abs = { 0x67, 0x00, 0x03 },
  534. .keys = {
  535. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  536. /* trigger, thumb, thumb2, top, top2, pinkie, base,
  537. * base2..base6 */
  538. /* 0x100 */ ZEROx4, 0xff, 0x0f
  539. },
  540. },
  541. {
  542. .name = "8BitDo N30 Pro 2",
  543. .bus_type = 0x0003,
  544. .vendor_id = 0x2dc8,
  545. .product_id = 0x9015,
  546. .version = 0x0111,
  547. /* 8BitDo NES30 Pro, 0003:2dc8:9001 v0111, is the same */
  548. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  549. .ev = { 0x0b },
  550. /* XYZ, RZ, gas, brake, hat0 */
  551. .abs = { 0x27, 0x06, 0x03 },
  552. .keys = {
  553. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  554. /* ABC, XYZ, TL, TR, TL2, TR2, select, start, mode, thumbl,
  555. * thumbr */
  556. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x7f,
  557. },
  558. },
  559. {
  560. .name = "Retro Power SNES-style controller, 0003:0079:0011 v0110",
  561. .bus_type = 0x0003,
  562. .vendor_id = 0x0079,
  563. .product_id = 0x0011,
  564. .version = 0x0110,
  565. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  566. .ev = { 0x0b },
  567. /* X, Y */
  568. .abs = { 0x03 },
  569. .keys = {
  570. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  571. /* trigger, thumb, thumb2, top, top2, pinkie, base,
  572. * base2..base4 */
  573. /* 0x100 */ ZEROx4, 0xff, 0x03, 0x00, 0x00,
  574. },
  575. },
  576. {
  577. .name = "Wiimote - buttons",
  578. .bus_type = 0x0005,
  579. .vendor_id = 0x057e,
  580. .product_id = 0x0306,
  581. .version = 0x8600,
  582. /* This one is a bit weird because some of the buttons are mapped
  583. * to the arrow, page up and page down keys, so it's a joystick
  584. * with a subset of a keyboard attached. */
  585. /* TODO: Should this be JOYSTICK, or even JOYSTICK|KEYBOARD? */
  586. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  587. /* SYN, KEY */
  588. .ev = { 0x03 },
  589. .keys = {
  590. /* 0x00 */ ZEROx8,
  591. /* left, right, up down */
  592. /* 0x40 */ ZEROx4, 0x80, 0x16, 0x00, 0x00,
  593. /* 0x80 */ ZEROx8,
  594. /* 0xc0 */ ZEROx8,
  595. /* BTN_1, BTN_2, BTN_A, BTN_B, BTN_MODE */
  596. /* 0x100 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
  597. /* 0x140 */ ZEROx8,
  598. /* next (keyboard page down), previous (keyboard page up) */
  599. /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4,
  600. },
  601. },
  602. {
  603. .name = "Wiimote - Motion Plus or accelerometer",
  604. .bus_type = 0x0005,
  605. .vendor_id = 0x057e,
  606. .product_id = 0x0306,
  607. .version = 0x8600,
  608. .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
  609. /* SYN, ABS */
  610. .ev = { 0x09 },
  611. /* RX, RY, RZ */
  612. .abs = { 0x38 },
  613. },
  614. {
  615. .name = "Wiimote - IR positioning",
  616. .bus_type = 0x0005,
  617. .vendor_id = 0x057e,
  618. .product_id = 0x0306,
  619. .version = 0x8600,
  620. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  621. /* SYN, ABS */
  622. .ev = { 0x09 },
  623. /* HAT0 to HAT3 */
  624. .abs = { 0x00, 0x1f },
  625. },
  626. {
  627. .name = "Wiimote - Nunchuck",
  628. .bus_type = 0x0005,
  629. .vendor_id = 0x057e,
  630. .product_id = 0x0306,
  631. .version = 0x8600,
  632. /* TODO: Should this be JOYSTICK? It has one stick and two buttons */
  633. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  634. /* SYN, KEY, ABS */
  635. .ev = { 0x0b },
  636. /* RX, RY, RZ, hat 0 */
  637. .abs = { 0x38, 0x00, 0x03 },
  638. .keys = {
  639. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  640. /* C and Z buttons */
  641. /* 0x100 */ ZEROx4, 0x00, 0x00, 0x24, 0x00,
  642. },
  643. },
  644. {
  645. /* Flags guessed from kernel source code */
  646. .name = "Wiimote - Classic Controller",
  647. /* TODO: Should this be JOYSTICK, or maybe JOYSTICK|KEYBOARD?
  648. * It's unusual in the same ways as the Wiimote */
  649. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  650. /* SYN, KEY, ABS */
  651. .ev = { 0x0b },
  652. /* Hat 1-3 */
  653. .abs = { 0x00, 0x1c },
  654. .keys = {
  655. /* 0x00 */ ZEROx8,
  656. /* left, right, up down */
  657. /* 0x40 */ ZEROx4, 0x80, 0x16, 0x00, 0x00,
  658. /* 0x80 */ ZEROx8,
  659. /* 0xc0 */ ZEROx8,
  660. /* A, B, X, Y, MODE, TL, TL2, TR, TR2 */
  661. /* 0x100 */ ZEROx4, 0x00, 0x13, 0xdb, 0x10,
  662. /* 0x140 */ ZEROx8,
  663. /* next (keyboard page down), previous (keyboard page up) */
  664. /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4,
  665. },
  666. },
  667. {
  668. /* Flags guessed from kernel source code */
  669. .name = "Wiimote - Balance Board",
  670. /* TODO: Should this be JOYSTICK? */
  671. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  672. /* SYN, KEY, ABS */
  673. .ev = { 0x0b },
  674. /* Hat 0-1 */
  675. .abs = { 0x00, 0x0f },
  676. .keys = {
  677. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  678. /* A */
  679. /* 0x100 */ ZEROx4, 0x00, 0x00, 0x01, 0x00,
  680. },
  681. },
  682. {
  683. /* Flags guessed from kernel source code */
  684. .name = "Wiimote - Wii U Pro Controller",
  685. .expected = SDL_UDEV_DEVICE_JOYSTICK,
  686. /* SYN, KEY, ABS */
  687. .ev = { 0x0b },
  688. /* X, Y, RX, RY */
  689. .abs = { 0x1b },
  690. .keys = {
  691. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  692. /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
  693. * THUMBL, THUMBR */
  694. /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
  695. /* 0x140 */ ZEROx8,
  696. /* 0x180 */ ZEROx8,
  697. /* 0x1c0 */ ZEROx8,
  698. /* Digital dpad */
  699. /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
  700. },
  701. },
  702. {
  703. .name = "Synaptics TM3381-002 (Thinkpad X280 trackpad)",
  704. .bus_type = 0x001d, /* BUS_RMI */
  705. .vendor_id = 0x06cb,
  706. .product_id = 0x0000,
  707. .version = 0x0000,
  708. .expected = SDL_UDEV_DEVICE_TOUCHPAD,
  709. /* SYN, KEY, ABS */
  710. .ev = { 0x0b },
  711. /* X, Y, pressure, multitouch */
  712. .abs = { 0x03, 0x00, 0x00, 0x01, 0x00, 0x80, 0xf3, 0x06 },
  713. .keys = {
  714. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  715. /* Left mouse button */
  716. /* 0x100 */ 0x00, 0x00, 0x01, 0x00, ZEROx4,
  717. /* BTN_TOOL_FINGER and some multitouch gestures */
  718. /* 0x140 */ 0x20, 0xe5
  719. },
  720. /* POINTER, BUTTONPAD */
  721. .props = { 0x05 },
  722. },
  723. {
  724. .name = "TPPS/2 Elan TrackPoint (Thinkpad X280)",
  725. .bus_type = 0x0011, /* BUS_I8042 */
  726. .vendor_id = 0x0002,
  727. .product_id = 0x000a,
  728. .version = 0x0000,
  729. .expected = SDL_UDEV_DEVICE_MOUSE,
  730. /* SYN, KEY, REL */
  731. .ev = { 0x07 },
  732. /* X, Y */
  733. .rel = { 0x03 },
  734. .keys = {
  735. /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
  736. /* Left, middle, right mouse buttons */
  737. /* 0x100 */ 0x00, 0x00, 0x07,
  738. },
  739. /* POINTER, POINTING_STICK */
  740. .props = { 0x21 },
  741. },
  742. {
  743. .name = "Thinkpad ACPI buttons",
  744. /* SDL treats this as a keyboard because it has a power button */
  745. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  746. /* SYN, KEY, MSC, SW */
  747. .ev = { 0x33 },
  748. .keys = {
  749. /* 0x00 */ ZEROx8,
  750. /* 0x40 */ ZEROx4, 0x00, 0x00, 0x0e, 0x01,
  751. /* 0x80 */ 0x00, 0x50, 0x11, 0x51, 0x00, 0x28, 0x00, 0xc0,
  752. /* 0xc0 */ 0x04, 0x20, 0x10, 0x02, 0x1b, 0x70, 0x01, 0x00,
  753. /* 0x100 */ ZEROx8,
  754. /* 0x140 */ ZEROx4, 0x00, 0x00, 0x50, 0x00,
  755. /* 0x180 */ ZEROx8,
  756. /* 0x1c0 */ 0x00, 0x00, 0x04, 0x18, ZEROx4,
  757. /* 0x200 */ ZEROx8,
  758. /* 0x240 */ 0x40, 0x00, 0x01, 0x00, ZEROx4,
  759. },
  760. },
  761. {
  762. .name = "PC speaker",
  763. .bus_type = 0x0010, /* BUS_ISA */
  764. .vendor_id = 0x001f,
  765. .product_id = 0x0001,
  766. .version = 0x0100,
  767. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  768. /* SYN, SND */
  769. .ev = { 0x01, 0x00, 0x04 },
  770. },
  771. {
  772. .name = "ALSA headphone detection, etc.",
  773. .bus_type = 0x0000,
  774. .vendor_id = 0x0000,
  775. .product_id = 0x0000,
  776. .version = 0x0000,
  777. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  778. /* SYN, SW */
  779. .ev = { 0x21 },
  780. },
  781. {
  782. /* Assumed to be a reasonably typical i8042 (PC AT) keyboard */
  783. .name = "Thinkpad T520 and X280 keyboards",
  784. .bus_type = 0x0011, /* BUS_I8042 */
  785. .vendor_id = 0x0001,
  786. .product_id = 0x0001,
  787. .version = 0xab54,
  788. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  789. /* SYN, KEY, MSC, LED, REP */
  790. .ev = { 0x13, 0x00, 0x12 },
  791. .keys = {
  792. /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
  793. /* 0x40 */ 0xff, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xff, 0xfe,
  794. /* 0x80 */ 0x01, 0xd0, 0x00, 0xf8, 0x78, 0x30, 0x80, 0x03,
  795. /* 0xc0 */ 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00,
  796. },
  797. },
  798. {
  799. .name = "Thinkpad X280 sleep button",
  800. .bus_type = 0x0019, /* BUS_HOST */
  801. .vendor_id = 0x0000,
  802. .product_id = 0x0003,
  803. .version = 0x0000,
  804. /* SDL treats KEY_SLEEP as indicating a keyboard */
  805. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  806. /* SYN, KEY */
  807. .ev = { 0x03 },
  808. .keys = {
  809. /* 0x00 */ ZEROx8,
  810. /* 0x40 */ ZEROx8,
  811. /* KEY_SLEEP */
  812. /* 0x80 */ 0x00, 0x40,
  813. },
  814. },
  815. {
  816. .name = "Thinkpad X280 lid switch",
  817. .bus_type = 0x0019, /* BUS_HOST */
  818. .vendor_id = 0x0000,
  819. .product_id = 0x0005,
  820. .version = 0x0000,
  821. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  822. /* SYN, SW */
  823. .ev = { 0x21 },
  824. },
  825. {
  826. .name = "Thinkpad X280 power button",
  827. .bus_type = 0x0019, /* BUS_HOST */
  828. .vendor_id = 0x0000,
  829. .product_id = 0x0001,
  830. .version = 0x0000,
  831. /* SDL treats KEY_POWER as indicating a keyboard */
  832. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  833. /* SYN, KEY */
  834. .ev = { 0x03 },
  835. .keys = {
  836. /* 0x00 */ ZEROx8,
  837. /* KEY_POWER */
  838. /* 0x40 */ ZEROx4, 0x00, 0x00, 0x10, 0x00,
  839. },
  840. },
  841. {
  842. .name = "Thinkpad X280 video bus",
  843. .bus_type = 0x0019, /* BUS_HOST */
  844. .vendor_id = 0x0000,
  845. .product_id = 0x0006,
  846. .version = 0x0000,
  847. /* SDL treats brightness control, etc. as keyboard keys */
  848. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  849. /* SYN, KEY */
  850. .ev = { 0x03 },
  851. .keys = {
  852. /* 0x00 */ ZEROx8,
  853. /* 0x40 */ ZEROx8,
  854. /* 0x80 */ ZEROx8,
  855. /* brightness control, video mode, display off */
  856. /* 0xc0 */ ZEROx4, 0x0b, 0x00, 0x3e, 0x00,
  857. },
  858. },
  859. {
  860. .name = "Thinkpad X280 extra buttons",
  861. .bus_type = 0x0019, /* BUS_HOST */
  862. .vendor_id = 0x17aa,
  863. .product_id = 0x5054,
  864. .version = 0x4101,
  865. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  866. /* SYN, KEY */
  867. .ev = { 0x03 },
  868. .keys = {
  869. /* 0x00 */ ZEROx8,
  870. /* 0x40 */ ZEROx4, 0x00, 0x00, 0x0e, 0x01,
  871. /* 0x80 */ 0x00, 0x50, 0x11, 0x51, 0x00, 0x28, 0x00, 0xc0,
  872. /* 0xc0 */ 0x04, 0x20, 0x10, 0x02, 0x1b, 0x70, 0x01, 0x00,
  873. /* 0x100 */ ZEROx8,
  874. /* 0x140 */ ZEROx4, 0x00, 0x00, 0x50, 0x00,
  875. /* 0x180 */ ZEROx8,
  876. /* 0x1c0 */ 0x00, 0x00, 0x04, 0x18, ZEROx4,
  877. /* 0x200 */ ZEROx8,
  878. /* 0x240 */ 0x40, 0x00, 0x01, 0x00, ZEROx4,
  879. },
  880. },
  881. {
  882. .name = "Thinkpad USB keyboard with Trackpoint - keyboard",
  883. .bus_type = 0x0003,
  884. .vendor_id = 0x17ef,
  885. .product_id = 0x6009,
  886. .expected = SDL_UDEV_DEVICE_KEYBOARD,
  887. /* SYN, KEY, MSC, LED, REP */
  888. .ev = { 0x13, 0x00, 0x12 },
  889. .keys = {
  890. /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
  891. /* 0x40 */ 0xff, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xbe, 0xfe,
  892. /* 0x80 */ 0xff, 0x57, 0x40, 0xc1, 0x7a, 0x20, 0x9f, 0xff,
  893. /* 0xc0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  894. },
  895. },
  896. {
  897. .name = "Thinkpad USB keyboard with Trackpoint - Trackpoint",
  898. .bus_type = 0x0003,
  899. .vendor_id = 0x17ef,
  900. .product_id = 0x6009,
  901. /* For some reason the special keys like mute and wlan toggle
  902. * show up here instead of, or in addition to, as part of
  903. * the keyboard - so both udev and SDL report this as having keys too. */
  904. .expected = SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD,
  905. /* SYN, KEY, REL, MSC, LED */
  906. .ev = { 0x17, 0x00, 0x02 },
  907. /* X, Y */
  908. .rel = { 0x03 },
  909. .keys = {
  910. /* 0x00 */ ZEROx8,
  911. /* 0x40 */ ZEROx4, 0x00, 0x00, 0x1e, 0x00,
  912. /* 0x80 */ 0x00, 0xcc, 0x11, 0x01, 0x78, 0x40, 0x00, 0xc0,
  913. /* 0xc0 */ 0x00, 0x20, 0x10, 0x00, 0x0b, 0x50, 0x00, 0x00,
  914. /* Mouse buttons: left, right, middle, "task" */
  915. /* 0x100 */ 0x00, 0x00, 0x87, 0x68, ZEROx4,
  916. /* 0x140 */ ZEROx4, 0x00, 0x00, 0x10, 0x00,
  917. /* 0x180 */ ZEROx4, 0x00, 0x00, 0x40, 0x00,
  918. },
  919. },
  920. {
  921. .name = "No information",
  922. .expected = SDL_UDEV_DEVICE_UNKNOWN,
  923. }
  924. };
  925. /* The Linux kernel provides capability info in EVIOCGBIT and in /sys
  926. * as an array of unsigned long in native byte order, rather than an array
  927. * of bytes, an array of native-endian 32-bit words or an array of
  928. * native-endian 64-bit words like you might have reasonably expected.
  929. * The order of words in the array is always lowest-valued first: for
  930. * instance, the first unsigned long in abs[] contains the bit representing
  931. * absolute axis 0 (ABS_X).
  932. *
  933. * The constant arrays above provide test data in little-endian, because
  934. * that's the easiest representation for hard-coding into a test like this.
  935. * On a big-endian platform we need to byteswap it, one unsigned long at a
  936. * time, to match what the kernel would produce. This requires us to choose
  937. * an appropriate byteswapping function for the architecture's word size. */
  938. SDL_COMPILE_TIME_ASSERT(sizeof_long, sizeof(unsigned long) == 4 || sizeof(unsigned long) == 8);
  939. #define SwapLongLE(X) \
  940. ((sizeof(unsigned long) == 4) ? SDL_SwapLE32(X) : SDL_SwapLE64(X))
  941. static int
  942. run_test(void)
  943. {
  944. int success = 1;
  945. size_t i;
  946. for (i = 0; i < SDL_arraysize(guess_tests); i++) {
  947. const GuessTest *t = &guess_tests[i];
  948. size_t j;
  949. int actual;
  950. struct {
  951. unsigned long ev[NBITS(EV_MAX)];
  952. unsigned long abs[NBITS(ABS_MAX)];
  953. unsigned long keys[NBITS(KEY_MAX)];
  954. unsigned long rel[NBITS(REL_MAX)];
  955. } caps = {};
  956. printf("%s...\n", t->name);
  957. memset(&caps, '\0', sizeof(caps));
  958. memcpy(caps.ev, t->ev, sizeof(t->ev));
  959. memcpy(caps.keys, t->keys, sizeof(t->keys));
  960. memcpy(caps.abs, t->abs, sizeof(t->abs));
  961. memcpy(caps.rel, t->rel, sizeof(t->rel));
  962. for (j = 0; j < SDL_arraysize(caps.ev); j++) {
  963. caps.ev[j] = SwapLongLE(caps.ev[j]);
  964. }
  965. for (j = 0; j < SDL_arraysize(caps.keys); j++) {
  966. caps.keys[j] = SwapLongLE(caps.keys[j]);
  967. }
  968. for (j = 0; j < SDL_arraysize(caps.abs); j++) {
  969. caps.abs[j] = SwapLongLE(caps.abs[j]);
  970. }
  971. for (j = 0; j < SDL_arraysize(caps.rel); j++) {
  972. caps.rel[j] = SwapLongLE(caps.rel[j]);
  973. }
  974. actual = SDL_EVDEV_GuessDeviceClass(caps.ev, caps.abs, caps.keys,
  975. caps.rel);
  976. if (actual == t->expected) {
  977. printf("\tOK\n");
  978. }
  979. else {
  980. printf("\tExpected 0x%08x\n", t->expected);
  981. for (j = 0; device_classes[j].code != 0; j++) {
  982. if (t->expected & device_classes[j].code) {
  983. printf("\t\t%s\n", device_classes[j].name);
  984. }
  985. }
  986. printf("\tGot 0x%08x\n", actual);
  987. for (j = 0; device_classes[j].code != 0; j++) {
  988. if (actual & device_classes[j].code) {
  989. printf("\t\t%s\n", device_classes[j].name);
  990. }
  991. }
  992. success = 0;
  993. }
  994. }
  995. return success;
  996. }
  997. #else /* !(HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)) */
  998. static int
  999. run_test(void)
  1000. {
  1001. printf("SDL compiled without evdev capability check.\n");
  1002. return 1;
  1003. }
  1004. #endif
  1005. int
  1006. main(int argc, char *argv[])
  1007. {
  1008. return run_test() ? 0 : 1;
  1009. }