/* * Return true if this joystick is known to have all axes centered at zero * This isn't generally needed unless the joystick never generates an initial axis value near zero, * e.g. it's emulating axes with digital buttons */ static SDL_bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) { static Uint32 zero_centered_joysticks[] = { MAKE_VIDPID(0x0e8f, 0x3013), /* HuiJia SNES USB adapter */ MAKE_VIDPID(0x05a0, 0x3232), /* 8Bitdo Zero Gamepad */ }; int i; Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick), SDL_JoystickGetProduct(joystick)); /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/ if (joystick->naxes == 2) { /* Assume D-pad or thumbstick style axes are centered at 0 */ return SDL_TRUE; } for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) { if (id == zero_centered_joysticks[i]) { return SDL_TRUE; } } return SDL_FALSE; }
static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid) { static Uint32 flightstick_joysticks[] = { MAKE_VIDPID(0x044f, 0x0402), /* HOTAS Warthog Joystick */ MAKE_VIDPID(0x0738, 0x2221), /* Saitek Pro Flight X-56 Rhino Stick */ }; int i; for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) { if (vidpid == flightstick_joysticks[i]) { return SDL_TRUE; } } return SDL_FALSE; }
static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid) { static Uint32 throttle_joysticks[] = { MAKE_VIDPID(0x044f, 0x0404), /* HOTAS Warthog Throttle */ MAKE_VIDPID(0x0738, 0xa221), /* Saitek Pro Flight X-56 Rhino Throttle */ }; int i; for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) { if (vidpid == throttle_joysticks[i]) { return SDL_TRUE; } } return SDL_FALSE; }
static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid) { Uint16 vendor; Uint16 product; Uint32 vidpid; if (guid.data[14] == 'x') { /* XInput GUID, get the type based on the XInput device subtype */ switch (guid.data[15]) { case 0x01: /* XINPUT_DEVSUBTYPE_GAMEPAD */ return SDL_JOYSTICK_TYPE_GAMECONTROLLER; case 0x02: /* XINPUT_DEVSUBTYPE_WHEEL */ return SDL_JOYSTICK_TYPE_WHEEL; case 0x03: /* XINPUT_DEVSUBTYPE_ARCADE_STICK */ return SDL_JOYSTICK_TYPE_ARCADE_STICK; case 0x04: /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */ return SDL_JOYSTICK_TYPE_FLIGHT_STICK; case 0x05: /* XINPUT_DEVSUBTYPE_DANCE_PAD */ return SDL_JOYSTICK_TYPE_DANCE_PAD; case 0x06: /* XINPUT_DEVSUBTYPE_GUITAR */ case 0x07: /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */ case 0x0B: /* XINPUT_DEVSUBTYPE_GUITAR_BASS */ return SDL_JOYSTICK_TYPE_GUITAR; case 0x08: /* XINPUT_DEVSUBTYPE_DRUM_KIT */ return SDL_JOYSTICK_TYPE_DRUM_KIT; case 0x13: /* XINPUT_DEVSUBTYPE_ARCADE_PAD */ return SDL_JOYSTICK_TYPE_ARCADE_PAD; default: return SDL_JOYSTICK_TYPE_UNKNOWN; } } SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); vidpid = MAKE_VIDPID(vendor, product); if (SDL_IsJoystickProductWheel(vidpid)) { return SDL_JOYSTICK_TYPE_WHEEL; } if (SDL_IsJoystickProductFlightStick(vidpid)) { return SDL_JOYSTICK_TYPE_FLIGHT_STICK; } if (SDL_IsJoystickProductThrottle(vidpid)) { return SDL_JOYSTICK_TYPE_THROTTLE; } return SDL_JOYSTICK_TYPE_UNKNOWN; }
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid) { static Uint32 wheel_joysticks[] = { MAKE_VIDPID(0x046d, 0xc294), /* Logitech generic wheel */ MAKE_VIDPID(0x046d, 0xc295), /* Logitech Momo Force */ MAKE_VIDPID(0x046d, 0xc298), /* Logitech Driving Force Pro */ MAKE_VIDPID(0x046d, 0xc299), /* Logitech G25 */ MAKE_VIDPID(0x046d, 0xc29a), /* Logitech Driving Force GT */ MAKE_VIDPID(0x046d, 0xc29b), /* Logitech G27 */ MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */ MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */ MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */ MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */ MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */ MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */ MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */ }; int i; for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) { if (vidpid == wheel_joysticks[i]) { return SDL_TRUE; } } return SDL_FALSE; }
static int IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid) { /* This list is taken from: https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py */ static Uint32 joystick_blacklist[] = { /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */ /* Microsoft Wireless Desktop - Comfort Edition */ MAKE_VIDPID(0x045e, 0x009d), /* Microsoft Microsoft® Digital Media Pro Keyboard */ /* Microsoft Corp. Digital Media Pro Keyboard */ MAKE_VIDPID(0x045e, 0x00b0), /* Microsoft Microsoft® Digital Media Keyboard */ /* Microsoft Corp. Digital Media Keyboard 1.0A */ MAKE_VIDPID(0x045e, 0x00b4), /* Microsoft Microsoft® Digital Media Keyboard 3000 */ MAKE_VIDPID(0x045e, 0x0730), /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */ /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */ /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */ /* Microsoft Wireless Mobile Mouse 1000 */ /* Microsoft Wireless Desktop 3000 */ MAKE_VIDPID(0x045e, 0x0745), /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */ MAKE_VIDPID(0x045e, 0x0748), /* Microsoft Corp. Wired Keyboard 600 */ MAKE_VIDPID(0x045e, 0x0750), /* Microsoft Corp. Sidewinder X4 keyboard */ MAKE_VIDPID(0x045e, 0x0768), /* Microsoft Corp. Arc Touch Mouse Transceiver */ MAKE_VIDPID(0x045e, 0x0773), /* Microsoft® 2.4GHz Transceiver v9.0 */ /* Microsoft® Nano Transceiver v2.1 */ /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */ MAKE_VIDPID(0x045e, 0x07a5), /* Microsoft® Nano Transceiver v1.0 */ /* Microsoft Wireless Keyboard 800 */ MAKE_VIDPID(0x045e, 0x07b2), /* Microsoft® Nano Transceiver v2.0 */ MAKE_VIDPID(0x045e, 0x0800), /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */ MAKE_VIDPID(0x056a, 0x0010), /* Wacom ET-0405 Graphire */ MAKE_VIDPID(0x056a, 0x0011), /* Wacom ET-0405A Graphire2 (4x5) */ MAKE_VIDPID(0x056a, 0x0012), /* Wacom ET-0507A Graphire2 (5x7) */ MAKE_VIDPID(0x056a, 0x0013), /* Wacom CTE-430 Graphire3 (4x5) */ MAKE_VIDPID(0x056a, 0x0014), /* Wacom CTE-630 Graphire3 (6x8) */ MAKE_VIDPID(0x056a, 0x0015), /* Wacom CTE-440 Graphire4 (4x5) */ MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire4 (6x8) */ MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun (4x5) */ MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire 4 6x8 */ MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun 4x5 */ MAKE_VIDPID(0x056a, 0x0018), /* Wacom CTE-650 Bamboo Fun 6x8 */ MAKE_VIDPID(0x056a, 0x0019), /* Wacom CTE-631 Bamboo One */ MAKE_VIDPID(0x056a, 0x00d1), /* Wacom Bamboo Pen and Touch CTH-460 */ MAKE_VIDPID(0x09da, 0x054f), /* A4 Tech Co., G7 750 mouse */ MAKE_VIDPID(0x09da, 0x3043), /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */ MAKE_VIDPID(0x09da, 0x31b5), /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */ MAKE_VIDPID(0x09da, 0x3997), /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */ MAKE_VIDPID(0x09da, 0x3f8b), /* A4 Tech Co., Ltd Bloody V8 mouse */ MAKE_VIDPID(0x09da, 0x51f4), /* Modecom MC-5006 Keyboard */ MAKE_VIDPID(0x09da, 0x5589), /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */ MAKE_VIDPID(0x09da, 0x7b22), /* A4 Tech Co., Ltd Bloody V5 */ MAKE_VIDPID(0x09da, 0x7f2d), /* A4 Tech Co., Ltd Bloody R3 mouse */ MAKE_VIDPID(0x09da, 0x8090), /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */ MAKE_VIDPID(0x09da, 0x9066), /* A4 Tech Co., Sharkoon Fireglider Optical */ MAKE_VIDPID(0x09da, 0x9090), /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */ MAKE_VIDPID(0x09da, 0x90c0), /* A4 Tech Co., Ltd X7 G800V keyboard */ MAKE_VIDPID(0x09da, 0xf012), /* A4 Tech Co., Ltd Bloody V7 mouse */ MAKE_VIDPID(0x09da, 0xf32a), /* A4 Tech Co., Ltd Bloody B540 keyboard */ MAKE_VIDPID(0x09da, 0xf613), /* A4 Tech Co., Ltd Bloody V2 mouse */ MAKE_VIDPID(0x09da, 0xf624), /* A4 Tech Co., Ltd Bloody B120 Keyboard */ MAKE_VIDPID(0x1d57, 0xad03), /* [T3] 2.4GHz and IR Air Mouse Remote Control */ MAKE_VIDPID(0x1e7d, 0x2e4a), /* Roccat Tyon Mouse */ MAKE_VIDPID(0x20a0, 0x422d), /* Winkeyless.kr Keyboards */ MAKE_VIDPID(0x2516, 0x001f), /* Cooler Master Storm Mizar Mouse */ MAKE_VIDPID(0x2516, 0x0028), /* Cooler Master Storm Alcor Mouse */ }; struct input_id inpid; int i; Uint32 id; Uint16 *guid16 = (Uint16 *)guid->data; #if !SDL_USE_LIBUDEV /* When udev is enabled we only get joystick devices here, so there's no need to test them */ unsigned long evbit[NBITS(EV_MAX)] = { 0 }; unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { return (0); } if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) { return 0; } #endif if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) { return 0; } if (ioctl(fd, EVIOCGID, &inpid) < 0) { return 0; } /* Check the joystick blacklist */ id = MAKE_VIDPID(inpid.vendor, inpid.product); for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) { if (id == joystick_blacklist[i]) { return 0; } } #ifdef DEBUG_JOYSTICK printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version); #endif SDL_memset(guid->data, 0, sizeof(guid->data)); /* We only need 16 bits for each of these; space them out to fill 128. */ /* Byteswap so devices get same GUID on little/big endian platforms. */ *guid16++ = SDL_SwapLE16(inpid.bustype); *guid16++ = 0; if (inpid.vendor && inpid.product) { *guid16++ = SDL_SwapLE16(inpid.vendor); *guid16++ = 0; *guid16++ = SDL_SwapLE16(inpid.product); *guid16++ = 0; *guid16++ = SDL_SwapLE16(inpid.version); *guid16++ = 0; } else { SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4); } if (SDL_IsGameControllerNameAndGUID(namebuf, *guid) && SDL_ShouldIgnoreGameController(namebuf, *guid)) { return 0; } return 1; }