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