123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041 |
- /*
- Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
- Copyright (C) 2020-2022 Collabora Ltd.
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely.
- */
- #include "../src/SDL_internal.h"
- #include <stdio.h>
- #include <string.h>
- static int run_test(void);
- #if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
- #include <stdint.h>
- #include "SDL_stdinc.h"
- #include "SDL_endian.h"
- #include "../src/core/linux/SDL_evdev_capabilities.h"
- #include "../src/core/linux/SDL_evdev_capabilities.c"
- static const struct
- {
- int code;
- const char *name;
- } device_classes[] =
- {
- #define CLS(x) \
- { SDL_UDEV_DEVICE_ ## x, #x }
- CLS(MOUSE),
- CLS(KEYBOARD),
- CLS(JOYSTICK),
- CLS(SOUND),
- CLS(TOUCHSCREEN),
- CLS(ACCELEROMETER),
- CLS(TOUCHPAD),
- #undef CLS
- { 0, NULL }
- };
- typedef struct
- {
- const char *name;
- uint16_t bus_type;
- uint16_t vendor_id;
- uint16_t product_id;
- uint16_t version;
- uint8_t ev[(EV_MAX + 1) / 8];
- uint8_t keys[(KEY_MAX + 1) / 8];
- uint8_t abs[(ABS_MAX + 1) / 8];
- uint8_t rel[(REL_MAX + 1) / 8];
- uint8_t ff[(FF_MAX + 1) / 8];
- uint8_t props[INPUT_PROP_MAX / 8];
- int expected;
- } GuessTest;
- /*
- * Test-cases for guessing a device type from its capabilities.
- *
- * The bytes in ev, etc. are in little-endian byte order
- * Trailing zeroes can be omitted.
- *
- * The evemu-describe tool is a convenient way to add a test-case for
- * a physically available device.
- */
- #define ZEROx4 0, 0, 0, 0
- #define ZEROx8 ZEROx4, ZEROx4
- #define FFx4 0xff, 0xff, 0xff, 0xff
- #define FFx8 FFx4, FFx4
- /* Test-cases derived from real devices or from Linux kernel source */
- static const GuessTest guess_tests[] =
- {
- {
- .name = "Xbox 360 wired USB controller",
- .bus_type = 0x0003,
- .vendor_id = 0x045e,
- .product_id = 0x028e,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS, FF */
- .ev = { 0x0b, 0x00, 0x20 },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
- },
- },
- {
- .name = "X-Box One Elite",
- .bus_type = 0x0003,
- .vendor_id = 0x045e,
- .product_id = 0x02e3,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
- },
- },
- {
- .name = "X-Box One S via Bluetooth",
- .bus_type = 0x0005,
- .vendor_id = 0x045e,
- .product_id = 0x02e0,
- .version = 0x1130,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
- },
- },
- {
- .name = "X-Box One S wired",
- .bus_type = 0x0003,
- .vendor_id = 0x045e,
- .product_id = 0x02ea,
- .version = 0x0301,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
- },
- },
- {
- .name = "DualShock 4 - gamepad",
- .bus_type = 0x0003,
- .vendor_id = 0x054c,
- .product_id = 0x09cc,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS, MSC, FF */
- /* Some versions only have 0x0b, SYN, KEY, ABS, like the
- * Bluetooth example below */
- .ev = { 0x1b, 0x00, 0x20 },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
- },
- },
- {
- .name = "DualShock 4 - gamepad via Bluetooth",
- .bus_type = 0x0005,
- .vendor_id = 0x054c,
- .product_id = 0x09cc,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
- },
- },
- {
- .name = "DualShock 4 - touchpad",
- .bus_type = 0x0003,
- .vendor_id = 0x054c,
- .product_id = 0x09cc,
- .expected = SDL_UDEV_DEVICE_TOUCHPAD,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, multitouch */
- .abs = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x02 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* Left mouse button */
- /* 0x100 */ 0x00, 0x00, 0x01, 0x00, ZEROx4,
- /* BTN_TOOL_FINGER and some multitouch stuff */
- /* 0x140 */ 0x20, 0x24, 0x00, 0x00
- },
- /* POINTER, BUTTONPAD */
- .props = { 0x05 },
- },
- {
- .name = "DualShock 4 - accelerometer",
- .bus_type = 0x0003,
- .vendor_id = 0x054c,
- .product_id = 0x09cc,
- .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
- /* SYN, ABS, MSC */
- .ev = { 0x19 },
- /* X, Y, Z, RX, RY, RZ */
- .abs = { 0x3f },
- /* ACCELEROMETER */
- .props = { 0x40 },
- },
- {
- .name = "DualShock 4 via USB dongle",
- .bus_type = 0x0003,
- .vendor_id = 0x054c,
- .product_id = 0x0ba0,
- .version = 0x8111,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, ABS, KEY */
- .ev = { 0x0b },
- /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
- },
- },
- {
- .name = "DualShock 3 - gamepad",
- .bus_type = 0x0003,
- .vendor_id = 0x054c,
- .product_id = 0x0268,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS, MSC, FF */
- .ev = { 0x1b, 0x00, 0x20 },
- /* X, Y, Z, RX, RY, RZ */
- .abs = { 0x3f },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
- /* 0x140 */ ZEROx8,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ ZEROx8,
- /* Digital dpad */
- /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
- },
- },
- {
- .name = "DualShock 3 - accelerometer",
- .bus_type = 0x0003,
- .vendor_id = 0x054c,
- .product_id = 0x0268,
- .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
- /* SYN, ABS */
- .ev = { 0x09 },
- /* X, Y, Z */
- .abs = { 0x07 },
- /* ACCELEROMETER */
- .props = { 0x40 },
- },
- {
- .name = "Steam Controller - gamepad",
- .bus_type = 0x0003,
- .vendor_id = 0x28de,
- .product_id = 0x1142,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, RX, RY, HAT0X, HAT0Y, HAT2X, HAT2Y */
- .abs = { 0x1b, 0x00, 0x33 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL, THUMBR, joystick THUMB, joystick THUMB2 */
- /* 0x100 */ ZEROx4, 0x06, 0x00, 0xdb, 0x7f,
- /* GEAR_DOWN, GEAR_UP */
- /* 0x140 */ 0x00, 0x00, 0x03, 0x00, ZEROx4,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ ZEROx8,
- /* Digital dpad */
- /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
- },
- },
- {
- /* Present to support lizard mode, even if no Steam Controller
- * is connected */
- .name = "Steam Controller - dongle",
- .bus_type = 0x0003,
- .vendor_id = 0x28de,
- .product_id = 0x1142,
- .expected = (SDL_UDEV_DEVICE_KEYBOARD
- | SDL_UDEV_DEVICE_MOUSE),
- /* SYN, KEY, REL, MSC, LED, REP */
- .ev = { 0x17, 0x00, 0x12 },
- /* X, Y, mouse wheel, high-res mouse wheel */
- .rel = { 0x03, 0x09 },
- .keys = {
- /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
- /* 0x40 */ 0xff, 0xff, 0xcf, 0x01, 0xdf, 0xff, 0x80, 0xe0,
- /* 0x80 */ ZEROx8,
- /* 0xc0 */ ZEROx8,
- /* 0x100 */ 0x00, 0x00, 0x1f, 0x00, ZEROx4,
- },
- },
- {
- .name = "Guitar Hero for PS3",
- .bus_type = 0x0003,
- .vendor_id = 0x12ba,
- .product_id = 0x0100,
- .version = 0x0110,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RZ, HAT0X, HAT0Y */
- .abs = { 0x27, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* ABC, XYZ, TL, TR, TL2, TR2, SELECT, START, MODE */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x1f,
- },
- },
- {
- .name = "G27 Racing Wheel, 0003:046d:c29b v0111",
- .bus_type = 0x0003,
- .vendor_id = 0x046d,
- .product_id = 0xc29b,
- .version = 0x0111,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RZ, HAT0X, HAT0Y */
- .abs = { 0x27, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
- * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
- /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
- /* 0x140 */ ZEROx8,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ ZEROx8,
- /* 0x200 */ ZEROx8,
- /* 0x240 */ ZEROx8,
- /* 0x280 */ ZEROx8,
- /* TRIGGER_HAPPY1..TRIGGER_HAPPY7 */
- /* 0x2c0 */ 0x7f,
- },
- },
- {
- .name = "Logitech Driving Force, 0003:046d:c294 v0100",
- .bus_type = 0x0003,
- .vendor_id = 0x046d,
- .product_id = 0xc294,
- .version = 0x0100,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, RZ, HAT0X, HAT0Y */
- .abs = { 0x23, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
- * BASE2..BASE6 */
- /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
- },
- },
- {
- .name = "Logitech Dual Action",
- .bus_type = 0x0003,
- .vendor_id = 0x046d,
- .product_id = 0xc216,
- .version = 0x0110,
- /* Logitech RumblePad 2 USB, 0003:046d:c218 v0110, is the same
- * except for having force feedback, which we don't use in our
- * heuristic */
- /* Jess Tech GGE909 PC Recoil Pad, 0003:0f30:010b v0110, is the same */
- /* 8BitDo SNES30, 0003:2dc8:ab20 v0110, is the same */
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RZ, HAT0X, HAT0Y */
- .abs = { 0x27, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
- * BASE2..BASE6 */
- /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
- },
- },
- {
- .name = "Saitek ST290 Pro flight stick",
- .bus_type = 0x0003,
- .vendor_id = 0x06a3,
- .product_id = 0x0160, /* 0x0460 seems to be the same */
- .version = 0x0100,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS, MSC */
- .ev = { 0x1b },
- /* X, Y, Z, RZ, HAT0X, HAT0Y */
- .abs = { 0x27, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE */
- /* 0x100 */ ZEROx4, 0x3f, 0x00, 0x00, 0x00,
- },
- },
- {
- .name = "Saitek X52 Pro Flight Control System",
- .bus_type = 0x0003,
- .vendor_id = 0x06a3,
- .product_id = 0x0762,
- .version = 0x0111,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- .ev = { 0x0b },
- /* XYZ, RXYZ, throttle, hat0, MISC, unregistered event code 0x29 */
- .abs = { 0x7f, 0x00, 0x03, 0x00, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
- * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
- /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
- /* 0x140 */ ZEROx8,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ ZEROx8,
- /* 0x200 */ ZEROx8,
- /* 0x240 */ ZEROx8,
- /* 0x280 */ ZEROx8,
- /* TRIGGER_HAPPY1..TRIGGER_HAPPY23 */
- /* 0x2c0 */ 0xff, 0xff, 0x7f,
- },
- },
- {
- .name = "Logitech Extreme 3D",
- .bus_type = 0x0003,
- .vendor_id = 0x046d,
- .product_id = 0xc215,
- .version = 0x0110,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS, MSC */
- .ev = { 0x0b },
- /* X, Y, RZ, throttle, hat 0 */
- .abs = { 0x63, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
- * BASE2..BASE6 */
- /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
- },
- },
- {
- .name = "Hori Real Arcade Pro VX-SA",
- .bus_type = 0x0003,
- .vendor_id = 0x24c6,
- .product_id = 0x5501,
- .version = 0x0533,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RX, RY, RZ, hat 0 */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
- },
- },
- {
- .name = "Switch Pro Controller via Bluetooth",
- .bus_type = 0x0005,
- .vendor_id = 0x057e,
- .product_id = 0x2009,
- .version = 0x0001,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, RX, RY, hat 0 */
- .abs = { 0x1b, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
- * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
- /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
- /* 0x140 */ ZEROx8,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ ZEROx8,
- /* 0x200 */ ZEROx8,
- /* 0x240 */ ZEROx8,
- /* 0x280 */ ZEROx8,
- /* TRIGGER_HAPPY1..TRIGGER_HAPPY2 */
- /* 0x2c0 */ 0x03,
- },
- },
- {
- .name = "Switch Pro Controller via USB",
- .bus_type = 0x0003,
- .vendor_id = 0x057e,
- .product_id = 0x2009,
- .version = 0x0111,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, Z, RZ, HAT0X, HAT0Y */
- .abs = { 0x27, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- },
- },
- {
- .name = "Thrustmaster Racing Wheel FFB",
- /* Mad Catz FightStick TE S+ PS4, 0003:0738:8384:0111 v0111
- * (aka Street Fighter V Arcade FightStick TES+)
- * is functionally the same */
- .bus_type = 0x0003,
- .vendor_id = 0x044f,
- .product_id = 0xb66d,
- .version = 0x0110,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- .ev = { 0x0b },
- /* XYZ, RXYZ, hat 0 */
- .abs = { 0x3f, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* ABC, XYZ, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x3f,
- },
- },
- {
- .name = "Thrustmaster T.Flight Hotas X",
- .bus_type = 0x0003,
- .vendor_id = 0x044f,
- .product_id = 0xb108,
- .version = 0x0100,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- .ev = { 0x0b },
- /* XYZ, RZ, throttle, hat 0 */
- .abs = { 0x67, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* trigger, thumb, thumb2, top, top2, pinkie, base,
- * base2..base6 */
- /* 0x100 */ ZEROx4, 0xff, 0x0f
- },
- },
- {
- .name = "8BitDo N30 Pro 2",
- .bus_type = 0x0003,
- .vendor_id = 0x2dc8,
- .product_id = 0x9015,
- .version = 0x0111,
- /* 8BitDo NES30 Pro, 0003:2dc8:9001 v0111, is the same */
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- .ev = { 0x0b },
- /* XYZ, RZ, gas, brake, hat0 */
- .abs = { 0x27, 0x06, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* ABC, XYZ, TL, TR, TL2, TR2, select, start, mode, thumbl,
- * thumbr */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x7f,
- },
- },
- {
- .name = "Retro Power SNES-style controller, 0003:0079:0011 v0110",
- .bus_type = 0x0003,
- .vendor_id = 0x0079,
- .product_id = 0x0011,
- .version = 0x0110,
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- .ev = { 0x0b },
- /* X, Y */
- .abs = { 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* trigger, thumb, thumb2, top, top2, pinkie, base,
- * base2..base4 */
- /* 0x100 */ ZEROx4, 0xff, 0x03, 0x00, 0x00,
- },
- },
- {
- .name = "Wiimote - buttons",
- .bus_type = 0x0005,
- .vendor_id = 0x057e,
- .product_id = 0x0306,
- .version = 0x8600,
- /* This one is a bit weird because some of the buttons are mapped
- * to the arrow, page up and page down keys, so it's a joystick
- * with a subset of a keyboard attached. */
- /* TODO: Should this be JOYSTICK, or even JOYSTICK|KEYBOARD? */
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY */
- .ev = { 0x03 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* left, right, up down */
- /* 0x40 */ ZEROx4, 0x80, 0x16, 0x00, 0x00,
- /* 0x80 */ ZEROx8,
- /* 0xc0 */ ZEROx8,
- /* BTN_1, BTN_2, BTN_A, BTN_B, BTN_MODE */
- /* 0x100 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
- /* 0x140 */ ZEROx8,
- /* next (keyboard page down), previous (keyboard page up) */
- /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4,
- },
- },
- {
- .name = "Wiimote - Motion Plus or accelerometer",
- .bus_type = 0x0005,
- .vendor_id = 0x057e,
- .product_id = 0x0306,
- .version = 0x8600,
- .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
- /* SYN, ABS */
- .ev = { 0x09 },
- /* RX, RY, RZ */
- .abs = { 0x38 },
- },
- {
- .name = "Wiimote - IR positioning",
- .bus_type = 0x0005,
- .vendor_id = 0x057e,
- .product_id = 0x0306,
- .version = 0x8600,
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- /* SYN, ABS */
- .ev = { 0x09 },
- /* HAT0 to HAT3 */
- .abs = { 0x00, 0x1f },
- },
- {
- .name = "Wiimote - Nunchuck",
- .bus_type = 0x0005,
- .vendor_id = 0x057e,
- .product_id = 0x0306,
- .version = 0x8600,
- /* TODO: Should this be JOYSTICK? It has one stick and two buttons */
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* RX, RY, RZ, hat 0 */
- .abs = { 0x38, 0x00, 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* C and Z buttons */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0x24, 0x00,
- },
- },
- {
- /* Flags guessed from kernel source code */
- .name = "Wiimote - Classic Controller",
- /* TODO: Should this be JOYSTICK, or maybe JOYSTICK|KEYBOARD?
- * It's unusual in the same ways as the Wiimote */
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* Hat 1-3 */
- .abs = { 0x00, 0x1c },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* left, right, up down */
- /* 0x40 */ ZEROx4, 0x80, 0x16, 0x00, 0x00,
- /* 0x80 */ ZEROx8,
- /* 0xc0 */ ZEROx8,
- /* A, B, X, Y, MODE, TL, TL2, TR, TR2 */
- /* 0x100 */ ZEROx4, 0x00, 0x13, 0xdb, 0x10,
- /* 0x140 */ ZEROx8,
- /* next (keyboard page down), previous (keyboard page up) */
- /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4,
- },
- },
- {
- /* Flags guessed from kernel source code */
- .name = "Wiimote - Balance Board",
- /* TODO: Should this be JOYSTICK? */
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* Hat 0-1 */
- .abs = { 0x00, 0x0f },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0x01, 0x00,
- },
- },
- {
- /* Flags guessed from kernel source code */
- .name = "Wiimote - Wii U Pro Controller",
- .expected = SDL_UDEV_DEVICE_JOYSTICK,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, RX, RY */
- .abs = { 0x1b },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
- * THUMBL, THUMBR */
- /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
- /* 0x140 */ ZEROx8,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ ZEROx8,
- /* Digital dpad */
- /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
- },
- },
- {
- .name = "Synaptics TM3381-002 (Thinkpad X280 trackpad)",
- .bus_type = 0x001d, /* BUS_RMI */
- .vendor_id = 0x06cb,
- .product_id = 0x0000,
- .version = 0x0000,
- .expected = SDL_UDEV_DEVICE_TOUCHPAD,
- /* SYN, KEY, ABS */
- .ev = { 0x0b },
- /* X, Y, pressure, multitouch */
- .abs = { 0x03, 0x00, 0x00, 0x01, 0x00, 0x80, 0xf3, 0x06 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* Left mouse button */
- /* 0x100 */ 0x00, 0x00, 0x01, 0x00, ZEROx4,
- /* BTN_TOOL_FINGER and some multitouch gestures */
- /* 0x140 */ 0x20, 0xe5
- },
- /* POINTER, BUTTONPAD */
- .props = { 0x05 },
- },
- {
- .name = "TPPS/2 Elan TrackPoint (Thinkpad X280)",
- .bus_type = 0x0011, /* BUS_I8042 */
- .vendor_id = 0x0002,
- .product_id = 0x000a,
- .version = 0x0000,
- .expected = SDL_UDEV_DEVICE_MOUSE,
- /* SYN, KEY, REL */
- .ev = { 0x07 },
- /* X, Y */
- .rel = { 0x03 },
- .keys = {
- /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
- /* Left, middle, right mouse buttons */
- /* 0x100 */ 0x00, 0x00, 0x07,
- },
- /* POINTER, POINTING_STICK */
- .props = { 0x21 },
- },
- {
- .name = "Thinkpad ACPI buttons",
- /* SDL treats this as a keyboard because it has a power button */
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY, MSC, SW */
- .ev = { 0x33 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* 0x40 */ ZEROx4, 0x00, 0x00, 0x0e, 0x01,
- /* 0x80 */ 0x00, 0x50, 0x11, 0x51, 0x00, 0x28, 0x00, 0xc0,
- /* 0xc0 */ 0x04, 0x20, 0x10, 0x02, 0x1b, 0x70, 0x01, 0x00,
- /* 0x100 */ ZEROx8,
- /* 0x140 */ ZEROx4, 0x00, 0x00, 0x50, 0x00,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ 0x00, 0x00, 0x04, 0x18, ZEROx4,
- /* 0x200 */ ZEROx8,
- /* 0x240 */ 0x40, 0x00, 0x01, 0x00, ZEROx4,
- },
- },
- {
- .name = "PC speaker",
- .bus_type = 0x0010, /* BUS_ISA */
- .vendor_id = 0x001f,
- .product_id = 0x0001,
- .version = 0x0100,
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- /* SYN, SND */
- .ev = { 0x01, 0x00, 0x04 },
- },
- {
- .name = "ALSA headphone detection, etc.",
- .bus_type = 0x0000,
- .vendor_id = 0x0000,
- .product_id = 0x0000,
- .version = 0x0000,
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- /* SYN, SW */
- .ev = { 0x21 },
- },
- {
- /* Assumed to be a reasonably typical i8042 (PC AT) keyboard */
- .name = "Thinkpad T520 and X280 keyboards",
- .bus_type = 0x0011, /* BUS_I8042 */
- .vendor_id = 0x0001,
- .product_id = 0x0001,
- .version = 0xab54,
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY, MSC, LED, REP */
- .ev = { 0x13, 0x00, 0x12 },
- .keys = {
- /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
- /* 0x40 */ 0xff, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xff, 0xfe,
- /* 0x80 */ 0x01, 0xd0, 0x00, 0xf8, 0x78, 0x30, 0x80, 0x03,
- /* 0xc0 */ 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00,
- },
- },
- {
- .name = "Thinkpad X280 sleep button",
- .bus_type = 0x0019, /* BUS_HOST */
- .vendor_id = 0x0000,
- .product_id = 0x0003,
- .version = 0x0000,
- /* SDL treats KEY_SLEEP as indicating a keyboard */
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY */
- .ev = { 0x03 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* 0x40 */ ZEROx8,
- /* KEY_SLEEP */
- /* 0x80 */ 0x00, 0x40,
- },
- },
- {
- .name = "Thinkpad X280 lid switch",
- .bus_type = 0x0019, /* BUS_HOST */
- .vendor_id = 0x0000,
- .product_id = 0x0005,
- .version = 0x0000,
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- /* SYN, SW */
- .ev = { 0x21 },
- },
- {
- .name = "Thinkpad X280 power button",
- .bus_type = 0x0019, /* BUS_HOST */
- .vendor_id = 0x0000,
- .product_id = 0x0001,
- .version = 0x0000,
- /* SDL treats KEY_POWER as indicating a keyboard */
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY */
- .ev = { 0x03 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* KEY_POWER */
- /* 0x40 */ ZEROx4, 0x00, 0x00, 0x10, 0x00,
- },
- },
- {
- .name = "Thinkpad X280 video bus",
- .bus_type = 0x0019, /* BUS_HOST */
- .vendor_id = 0x0000,
- .product_id = 0x0006,
- .version = 0x0000,
- /* SDL treats brightness control, etc. as keyboard keys */
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY */
- .ev = { 0x03 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* 0x40 */ ZEROx8,
- /* 0x80 */ ZEROx8,
- /* brightness control, video mode, display off */
- /* 0xc0 */ ZEROx4, 0x0b, 0x00, 0x3e, 0x00,
- },
- },
- {
- .name = "Thinkpad X280 extra buttons",
- .bus_type = 0x0019, /* BUS_HOST */
- .vendor_id = 0x17aa,
- .product_id = 0x5054,
- .version = 0x4101,
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY */
- .ev = { 0x03 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* 0x40 */ ZEROx4, 0x00, 0x00, 0x0e, 0x01,
- /* 0x80 */ 0x00, 0x50, 0x11, 0x51, 0x00, 0x28, 0x00, 0xc0,
- /* 0xc0 */ 0x04, 0x20, 0x10, 0x02, 0x1b, 0x70, 0x01, 0x00,
- /* 0x100 */ ZEROx8,
- /* 0x140 */ ZEROx4, 0x00, 0x00, 0x50, 0x00,
- /* 0x180 */ ZEROx8,
- /* 0x1c0 */ 0x00, 0x00, 0x04, 0x18, ZEROx4,
- /* 0x200 */ ZEROx8,
- /* 0x240 */ 0x40, 0x00, 0x01, 0x00, ZEROx4,
- },
- },
- {
- .name = "Thinkpad USB keyboard with Trackpoint - keyboard",
- .bus_type = 0x0003,
- .vendor_id = 0x17ef,
- .product_id = 0x6009,
- .expected = SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY, MSC, LED, REP */
- .ev = { 0x13, 0x00, 0x12 },
- .keys = {
- /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
- /* 0x40 */ 0xff, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xbe, 0xfe,
- /* 0x80 */ 0xff, 0x57, 0x40, 0xc1, 0x7a, 0x20, 0x9f, 0xff,
- /* 0xc0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
- },
- },
- {
- .name = "Thinkpad USB keyboard with Trackpoint - Trackpoint",
- .bus_type = 0x0003,
- .vendor_id = 0x17ef,
- .product_id = 0x6009,
- /* For some reason the special keys like mute and wlan toggle
- * show up here instead of, or in addition to, as part of
- * the keyboard - so both udev and SDL report this as having keys too. */
- .expected = SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD,
- /* SYN, KEY, REL, MSC, LED */
- .ev = { 0x17, 0x00, 0x02 },
- /* X, Y */
- .rel = { 0x03 },
- .keys = {
- /* 0x00 */ ZEROx8,
- /* 0x40 */ ZEROx4, 0x00, 0x00, 0x1e, 0x00,
- /* 0x80 */ 0x00, 0xcc, 0x11, 0x01, 0x78, 0x40, 0x00, 0xc0,
- /* 0xc0 */ 0x00, 0x20, 0x10, 0x00, 0x0b, 0x50, 0x00, 0x00,
- /* Mouse buttons: left, right, middle, "task" */
- /* 0x100 */ 0x00, 0x00, 0x87, 0x68, ZEROx4,
- /* 0x140 */ ZEROx4, 0x00, 0x00, 0x10, 0x00,
- /* 0x180 */ ZEROx4, 0x00, 0x00, 0x40, 0x00,
- },
- },
- {
- .name = "No information",
- .expected = SDL_UDEV_DEVICE_UNKNOWN,
- }
- };
- /* The Linux kernel provides capability info in EVIOCGBIT and in /sys
- * as an array of unsigned long in native byte order, rather than an array
- * of bytes, an array of native-endian 32-bit words or an array of
- * native-endian 64-bit words like you might have reasonably expected.
- * The order of words in the array is always lowest-valued first: for
- * instance, the first unsigned long in abs[] contains the bit representing
- * absolute axis 0 (ABS_X).
- *
- * The constant arrays above provide test data in little-endian, because
- * that's the easiest representation for hard-coding into a test like this.
- * On a big-endian platform we need to byteswap it, one unsigned long at a
- * time, to match what the kernel would produce. This requires us to choose
- * an appropriate byteswapping function for the architecture's word size. */
- SDL_COMPILE_TIME_ASSERT(sizeof_long, sizeof(unsigned long) == 4 || sizeof(unsigned long) == 8);
- #define SwapLongLE(X) \
- ((sizeof(unsigned long) == 4) ? SDL_SwapLE32(X) : SDL_SwapLE64(X))
- static int
- run_test(void)
- {
- int success = 1;
- size_t i;
- for (i = 0; i < SDL_arraysize(guess_tests); i++) {
- const GuessTest *t = &guess_tests[i];
- size_t j;
- int actual;
- struct {
- unsigned long ev[NBITS(EV_MAX)];
- unsigned long abs[NBITS(ABS_MAX)];
- unsigned long keys[NBITS(KEY_MAX)];
- unsigned long rel[NBITS(REL_MAX)];
- } caps = {};
- printf("%s...\n", t->name);
- memset(&caps, '\0', sizeof(caps));
- memcpy(caps.ev, t->ev, sizeof(t->ev));
- memcpy(caps.keys, t->keys, sizeof(t->keys));
- memcpy(caps.abs, t->abs, sizeof(t->abs));
- memcpy(caps.rel, t->rel, sizeof(t->rel));
- for (j = 0; j < SDL_arraysize(caps.ev); j++) {
- caps.ev[j] = SwapLongLE(caps.ev[j]);
- }
- for (j = 0; j < SDL_arraysize(caps.keys); j++) {
- caps.keys[j] = SwapLongLE(caps.keys[j]);
- }
- for (j = 0; j < SDL_arraysize(caps.abs); j++) {
- caps.abs[j] = SwapLongLE(caps.abs[j]);
- }
- for (j = 0; j < SDL_arraysize(caps.rel); j++) {
- caps.rel[j] = SwapLongLE(caps.rel[j]);
- }
- actual = SDL_EVDEV_GuessDeviceClass(caps.ev, caps.abs, caps.keys,
- caps.rel);
- if (actual == t->expected) {
- printf("\tOK\n");
- }
- else {
- printf("\tExpected 0x%08x\n", t->expected);
- for (j = 0; device_classes[j].code != 0; j++) {
- if (t->expected & device_classes[j].code) {
- printf("\t\t%s\n", device_classes[j].name);
- }
- }
- printf("\tGot 0x%08x\n", actual);
- for (j = 0; device_classes[j].code != 0; j++) {
- if (actual & device_classes[j].code) {
- printf("\t\t%s\n", device_classes[j].name);
- }
- }
- success = 0;
- }
- }
- return success;
- }
- #else /* !(HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)) */
- static int
- run_test(void)
- {
- printf("SDL compiled without evdev capability check.\n");
- return 1;
- }
- #endif
- int
- main(int argc, char *argv[])
- {
- return run_test() ? 0 : 1;
- }
|