/* helper function for direct input, gets called for each connected joystick */ static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) { const Uint16 BUS_USB = 0x03; const Uint16 BUS_BLUETOOTH = 0x05; JoyStick_DeviceData *pNewJoystick; JoyStick_DeviceData *pPrevJoystick = NULL; const DWORD devtype = (pdidInstance->dwDevType & 0xFF); Uint16 *guid16; if (devtype == DI8DEVTYPE_SUPPLEMENTAL) { /* Add any supplemental devices that should be ignored here */ #define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID) static DWORD ignored_devices[] = { MAKE_TABLE_ENTRY(0, 0) }; #undef MAKE_TABLE_ENTRY unsigned int i; for (i = 0; i < SDL_arraysize(ignored_devices); ++i) { if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) { return DIENUM_CONTINUE; } } } if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) { return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */ } pNewJoystick = *(JoyStick_DeviceData **)pContext; while (pNewJoystick) { if (!SDL_memcmp(&pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance))) { /* if we are replacing the front of the list then update it */ if (pNewJoystick == *(JoyStick_DeviceData **)pContext) { *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext; } else if (pPrevJoystick) { pPrevJoystick->pNext = pNewJoystick->pNext; } pNewJoystick->pNext = SYS_Joystick; SYS_Joystick = pNewJoystick; return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */ } pPrevJoystick = pNewJoystick; pNewJoystick = pNewJoystick->pNext; } pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData)); if (!pNewJoystick) { return DIENUM_CONTINUE; /* better luck next time? */ } SDL_zerop(pNewJoystick); pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName); if (!pNewJoystick->joystickname) { SDL_free(pNewJoystick); return DIENUM_CONTINUE; /* better luck next time? */ } SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance, sizeof(DIDEVICEINSTANCE)); SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data)); guid16 = (Uint16 *)pNewJoystick->guid.data; if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) { *guid16++ = SDL_SwapLE16(BUS_USB); *guid16++ = 0; *guid16++ = SDL_SwapLE16((Uint16)LOWORD(pdidInstance->guidProduct.Data1)); /* vendor */ *guid16++ = 0; *guid16++ = SDL_SwapLE16((Uint16)HIWORD(pdidInstance->guidProduct.Data1)); /* product */ *guid16++ = 0; *guid16++ = 0; /* version */ *guid16++ = 0; } else { *guid16++ = SDL_SwapLE16(BUS_BLUETOOTH); *guid16++ = 0; SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4); } if (SDL_IsGameControllerNameAndGUID(pNewJoystick->joystickname, pNewJoystick->guid) && SDL_ShouldIgnoreGameController(pNewJoystick->joystickname, pNewJoystick->guid)) { SDL_free(pNewJoystick); return DIENUM_CONTINUE; } SDL_SYS_AddJoystickDevice(pNewJoystick); return DIENUM_CONTINUE; /* get next device, please */ }
static void AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext) { JoyStick_DeviceData *pPrevJoystick = NULL; JoyStick_DeviceData *pNewJoystick = *pContext; if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD) return; if (SubType == XINPUT_DEVSUBTYPE_UNKNOWN) return; while (pNewJoystick) { if (pNewJoystick->bXInputDevice && (pNewJoystick->XInputUserId == userid) && (pNewJoystick->SubType == SubType)) { /* if we are replacing the front of the list then update it */ if (pNewJoystick == *pContext) { *pContext = pNewJoystick->pNext; } else if (pPrevJoystick) { pPrevJoystick->pNext = pNewJoystick->pNext; } pNewJoystick->pNext = SYS_Joystick; SYS_Joystick = pNewJoystick; return; /* already in the list. */ } pPrevJoystick = pNewJoystick; pNewJoystick = pNewJoystick->pNext; } pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData)); if (!pNewJoystick) { return; /* better luck next time? */ } SDL_zerop(pNewJoystick); pNewJoystick->joystickname = GetXInputName(userid, SubType); if (!pNewJoystick->joystickname) { SDL_free(pNewJoystick); return; /* better luck next time? */ } pNewJoystick->bXInputDevice = SDL_TRUE; if (SDL_XInputUseOldJoystickMapping()) { SDL_zero(pNewJoystick->guid); } else { const Uint16 BUS_USB = 0x03; Uint16 vendor = 0; Uint16 product = 0; Uint16 version = 0; Uint16 *guid16 = (Uint16 *)pNewJoystick->guid.data; GuessXInputDevice(userid, &vendor, &product, &version); *guid16++ = SDL_SwapLE16(BUS_USB); *guid16++ = 0; *guid16++ = SDL_SwapLE16(vendor); *guid16++ = 0; *guid16++ = SDL_SwapLE16(product); *guid16++ = 0; *guid16++ = SDL_SwapLE16(version); *guid16++ = 0; /* Note that this is an XInput device and what subtype it is */ pNewJoystick->guid.data[14] = 'x'; pNewJoystick->guid.data[15] = SubType; } pNewJoystick->SubType = SubType; pNewJoystick->XInputUserId = userid; if (SDL_ShouldIgnoreGameController(pNewJoystick->joystickname, pNewJoystick->guid)) { SDL_free(pNewJoystick); return; } SDL_SYS_AddJoystickDevice(pNewJoystick); }
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; }
static void JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) { recDevice *device; int device_index = 0; io_service_t ioservice; if (res != kIOReturnSuccess) { return; } if (JoystickAlreadyKnown(ioHIDDeviceObject)) { return; /* IOKit sent us a duplicate. */ } device = (recDevice *) SDL_calloc(1, sizeof(recDevice)); if (!device) { SDL_OutOfMemory(); return; } if (!GetDeviceInfo(ioHIDDeviceObject, device)) { SDL_free(device); return; /* not a device we care about, probably. */ } if (SDL_IsGameControllerNameAndGUID(device->product, device->guid) && SDL_ShouldIgnoreGameController(device->product, device->guid)) { SDL_free(device); return; } /* Get notified when this device is disconnected. */ IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device); IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE); /* Allocate an instance ID for this device */ device->instance_id = ++s_joystick_instance_id; /* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */ ioservice = IOHIDDeviceGetService(ioHIDDeviceObject); #if SDL_HAPTIC_IOKIT if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { device->ffservice = ioservice; MacHaptic_MaybeAddDevice(ioservice); } #endif /* Add device to the end of the list */ if ( !gpDeviceList ) { gpDeviceList = device; } else { recDevice *curdevice; curdevice = gpDeviceList; while ( curdevice->pNext ) { ++device_index; curdevice = curdevice->pNext; } curdevice->pNext = device; ++device_index; /* bump by one since we counted by pNext. */ } SDL_PrivateJoystickAdded(device_index); }