// adapted from SDL2, works a lot better than the MSDN version bool joystick_windows::is_xinput_device(const GUID *p_guid) { static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; if (p_guid == &IID_ValveStreamingGamepad || p_guid == &IID_X360WiredGamepad || p_guid == &IID_X360WirelessGamepad) return true; PRAWINPUTDEVICELIST dev_list = NULL; unsigned int dev_list_count = 0; if (GetRawInputDeviceList(NULL, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) { return false; } dev_list = (PRAWINPUTDEVICELIST) malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count); if (!dev_list) return false; if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) { free(dev_list); return false; } for (int i = 0; i < dev_list_count; i++) { RID_DEVICE_INFO rdi; char dev_name[128]; UINT rdiSize = sizeof(rdi); UINT nameSize = sizeof(dev_name); rdi.cbSize = rdiSize; if ( (dev_list[i].dwType == RIM_TYPEHID) && (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) && (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) && (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) && (strstr(dev_name, "IG_") != NULL)) { free(dev_list); return true; } } free(dev_list); return false; }
static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) { UINT r; unsigned i; char name[256]; UINT name_size = sizeof(name); for (i = 0; i < mouse_cnt; ++i) { r = GetRawInputDeviceInfoA(mice[i].hnd, RIDI_DEVICENAME, name, &name_size); if (r == (UINT)-1 || r == 0) name[0] = '\0'; RARCH_LOG("[WINRAW]: Mouse #%u %s.\n", i, name); } }
/* Based on SDL2's implementation. */ static bool guid_is_xinput_device(const GUID* product_guid) { unsigned i, num_raw_devs = 0; PRAWINPUTDEVICELIST raw_devs = NULL; /* Check for well known XInput device GUIDs, * thereby removing the need for the IG_ check. * This lets us skip RAWINPUT for popular devices. * * Also, we need to do this for the Valve Streaming Gamepad * because it's virtualized and doesn't show up in the device list. */ for (i = 0; i < ARRAY_SIZE(common_xinput_guids); ++i) { if (memcmp(product_guid, &common_xinput_guids[i], sizeof(GUID)) == 0) return true; } /* Go through RAWINPUT (WinXP and later) to find HID devices. */ if (!raw_devs) { if ((GetRawInputDeviceList(NULL, &num_raw_devs, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) || (!num_raw_devs)) return false; raw_devs = (PRAWINPUTDEVICELIST) malloc(sizeof(RAWINPUTDEVICELIST) * num_raw_devs); if (!raw_devs) return false; if (GetRawInputDeviceList(raw_devs, &num_raw_devs, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) { free(raw_devs); raw_devs = NULL; return false; } } for (i = 0; i < num_raw_devs; i++) { RID_DEVICE_INFO rdi; char devName[128] = {0}; UINT rdiSize = sizeof(rdi); UINT nameSize = sizeof(devName); rdi.cbSize = sizeof (rdi); if ((raw_devs[i].dwType == RIM_TYPEHID) && (GetRawInputDeviceInfoA(raw_devs[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) && (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)product_guid->Data1)) && (GetRawInputDeviceInfoA(raw_devs[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) && (strstr(devName, "IG_") != NULL) ) { free(raw_devs); raw_devs = NULL; return true; } } free(raw_devs); raw_devs = NULL; return false; }
/* We can't really tell what device is being used for XInput, but we can guess and we'll be correct for the case where only one device is connected. */ static void GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion) { #ifndef __WINRT__ /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */ PRAWINPUTDEVICELIST devices = NULL; UINT i, j, device_count = 0; if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) { return; /* oh well. */ } devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count); if (devices == NULL) { return; } if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) { SDL_free(devices); return; /* oh well. */ } for (i = 0; i < device_count; i++) { RID_DEVICE_INFO rdi; char devName[128]; UINT rdiSize = sizeof(rdi); UINT nameSize = SDL_arraysize(devName); rdi.cbSize = sizeof(rdi); if ((devices[i].dwType == RIM_TYPEHID) && (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) && (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) && (SDL_strstr(devName, "IG_") != NULL)) { SDL_bool found = SDL_FALSE; for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) { if (j == userid) { continue; } if (!s_arrXInputDevicePath[j]) { continue; } if (SDL_strcmp(devName, s_arrXInputDevicePath[j]) == 0) { found = SDL_TRUE; break; } } if (found) { /* We already have this device in our XInput device list */ continue; } /* We don't actually know if this is the right device for this * userid, but we'll record it so we'll at least be consistent * when the raw device list changes. */ *pVID = (Uint16)rdi.hid.dwVendorId; *pPID = (Uint16)rdi.hid.dwProductId; *pVersion = (Uint16)rdi.hid.dwVersionNumber; if (s_arrXInputDevicePath[userid]) { SDL_free(s_arrXInputDevicePath[userid]); } s_arrXInputDevicePath[userid] = SDL_strdup(devName); break; } } SDL_free(devices); #endif /* ifndef __WINRT__ */ }
static SDL_bool SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput) { static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static const GUID *s_XInputProductGUID[] = { &IID_ValveStreamingGamepad, &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */ &IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */ &IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */ &IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */ &IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */ &IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */ &IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */ &IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */ }; size_t iDevice; UINT i; if (!SDL_XINPUT_Enabled()) { return SDL_FALSE; } /* Check for well known XInput device GUIDs */ /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */ for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) { if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) { return SDL_TRUE; } } /* Go through RAWINPUT (WinXP and later) to find HID devices. */ /* Cache this if we end up using it. */ if (SDL_RawDevList == NULL) { if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) { return SDL_FALSE; /* oh well. */ } SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount); if (SDL_RawDevList == NULL) { SDL_OutOfMemory(); return SDL_FALSE; } if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) { SDL_free(SDL_RawDevList); SDL_RawDevList = NULL; return SDL_FALSE; /* oh well. */ } } for (i = 0; i < SDL_RawDevListCount; i++) { RID_DEVICE_INFO rdi; char devName[128]; UINT rdiSize = sizeof(rdi); UINT nameSize = SDL_arraysize(devName); rdi.cbSize = sizeof(rdi); if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) && (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) && (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) && (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) && (SDL_strstr(devName, "IG_") != NULL)) { return SDL_TRUE; } } return SDL_FALSE; }
bool nxRawInputDevice::GetInformation(void) { HKEY hKey = NULL; try { /// Retrieve the encoded device name UINT uSize = 0; // Retrieve the number of characters needed to store the device name (including the null) // Calling the unicode version, that way we get the number of characters properly. // All the characters used, in practice, are representable in ANSI. if (GetRawInputDeviceInfoW(hDevice,RIDI_DEVICENAME,NULL,&uSize) < 0) nxThrow("Couldn't retrieve length of device name string."); // Allocate the space strDeviceName.resize(uSize-1); // Retrieve the device name. Example: "\\??\\ACPI#PNP0303#3&13c0b0c5&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}" if (GetRawInputDeviceInfoA(hDevice,RIDI_DEVICENAME,const_cast<char*>(strDeviceName.c_str()),&uSize) < 0) nxThrow("Couldn't retrieve the encoded device name."); /// Multiply Occurring Error. Placing here so we can include the device name. const std::string strFormatError = std::string("Device name is encoded in an unsupported format. \"") + strDeviceName + std::string("\""); // Validate the device name is nonempty. if (strDeviceName.empty()) nxThrow(strFormatError); /// Split the device name into parts // Delimiter offsets std::string::size_type uCurrent, uNext; // First # position uNext = strDeviceName.find_first_of('#'); // Position of the trailing slash of the beginning "\\??\\" part. uCurrent = strDeviceName.find_last_of('\\',uNext); /// Loop through the fields std::string strField; for (UINT uField = 0;uField < 4;++uField) { // Validate field offsets if (uCurrent == std::string::npos) nxThrow(strFormatError); // Pull out the field data if (uNext != std::string::npos) strField = strDeviceName.substr(uCurrent+1,uNext-uCurrent-1); else strField = strDeviceName.substr(uCurrent+1); // Ensure some value was retrieved if (strField.empty()) nxThrow(strFormatError); /// Set the appropriate field switch (uField) { case 0: strClassCode = strField; break; case 1: strSubClassCode = strField; break; case 2: strProtocolCode = strField; break; case 3: strGUID = strField; break; default: nxThrow("Unhandled token index, notify the developer of his silly mistake."); } // Advance to the next token. uCurrent = uNext; if (uCurrent != std::string::npos) uNext = strDeviceName.find_first_of('#',uCurrent+1); else uNext = std::string::npos; } /// Retrieve the device description and class from the registry DWORD dwKeyType; DWORD dwKeySize; std::string strRegKey = std::string("SYSTEM\\CurrentControlSet\\Enum\\")+strClassCode+"\\"+strSubClassCode+"\\"+strProtocolCode; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,strRegKey.c_str(),0,KEY_QUERY_VALUE,&hKey) != ERROR_SUCCESS) { hKey = NULL; nxThrow(std::string("Couldn't open the device's registry key - ") + strRegKey); } // Retrieve data type and size (including null) if (RegQueryValueEx(hKey,"DeviceDesc",NULL,&dwKeyType,NULL,&dwKeySize) != ERROR_SUCCESS) nxThrow(std::string("Couldn't retrieve size of \"DeviceDesc\" value for registry key - ") + strRegKey); // Size the buffer accordingly strDeviceDesc.resize(dwKeySize-1); // Added the const_cast for clarity, though it isn't necessary. if (RegQueryValueEx(hKey,"DeviceDesc",NULL,&dwKeyType,(BYTE*)const_cast<char*>(strDeviceDesc.c_str()),&dwKeySize) != ERROR_SUCCESS) nxThrow(std::string("Couldn't retrieve value of \"DeviceDesc\" for registry key - ") + strRegKey); // Retrieve data type and size (including null) if (RegQueryValueEx(hKey,"Class",NULL,&dwKeyType,NULL,&dwKeySize) != ERROR_SUCCESS) nxThrow(std::string("Couldn't retrieve size of \"Class\" value for registry key - ") + strRegKey); // Size the buffer accordingly strDeviceClass.resize(dwKeySize-1); // Added the const_cast for clarity, though it isn't necessary. if (RegQueryValueEx(hKey,"Class",NULL,&dwKeyType,(BYTE*)const_cast<char*>(strDeviceClass.c_str()),&dwKeySize) != ERROR_SUCCESS) nxThrow(std::string("Couldn't retrieve value of \"Class\" for registry key - ") + strRegKey); /// Use registry information to verify our keyboards/mice are in fact keyboards and mice. // This will also turn the terminal services "system" devices to HID if (stricmp(strClassCode.c_str(),"root")==0) dwType = RIM_TYPEHID; else if (IsKeyboard()) { if (stricmp(strDeviceClass.c_str(),"keyboard")!=0) dwType = RIM_TYPEHID; } else if (IsMouse()) { if (stricmp(strDeviceClass.c_str(),"mouse")!=0) dwType = RIM_TYPEHID; } else //HID { if (stricmp(strDeviceClass.c_str(),"keyboard")==0) dwType = RIM_TYPEKEYBOARD; else if (stricmp(strDeviceClass.c_str(),"mouse")==0) dwType = RIM_TYPEMOUSE; } // Make sure this isn't vmware's keyboard driver (rather than a physical keyboard) if (IsKeyboard()) { HKEY hKeyVM = NULL; // If this fails, then something is amiss (there should be a control key), but, it isn't really a bail-out situation if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,(strRegKey+"\\Control").c_str(),0,KEY_QUERY_VALUE,&hKeyVM) == ERROR_SUCCESS) { // Retrieve data type and size (including null) if (RegQueryValueEx(hKeyVM,"ActiveService",NULL,&dwKeyType,NULL,&dwKeySize) == ERROR_SUCCESS) { std::string strActiveService; // Size the buffer accordingly strActiveService.resize(dwKeySize-1); // Added the const_cast for clarity, though it isn't necessary. if (RegQueryValueEx(hKeyVM,"ActiveService",NULL,&dwKeyType,(BYTE*)const_cast<char*>(strActiveService.c_str()),&dwKeySize) == ERROR_SUCCESS) { if (stricmp(strActiveService.c_str(),"vmkbd") == 0) { // It's the vmware keyboard, not a physical keyboard. dwType = RIM_TYPEHID; } } } RegCloseKey(hKeyVM); } } // Clean up RegCloseKey(hKey); hKey=NULL; // Return false if it isn't a supported keyboard and mouse if (!IsMouse() && !IsKeyboard()) return false; } catch (const std::exception&e) { nxLog << e.what() << std::endl; Clear(); if (hKey) RegCloseKey(hKey); return false; } return true; }
void WIN_InitMouse(_THIS) { int index = 0; RAWINPUTDEVICELIST *deviceList = NULL; int devCount = 0; int i; int tmp = 0; char *buffer = NULL; char *tab = "wacom"; /* since windows does't give us handles to tablets, we have to detect a tablet by it's name */ const char *rdp = "rdp_mou"; SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; /* WinCE has no RawInputDeviceList */ #ifdef _WIN32_WCE SDL_Mouse mouse; SDL_zero(mouse); mouse.id = 0; SDL_AddMouse(&mouse, "Stylus", 0, 0, 1); #else /* we're checking for the number of rawinput devices */ if (GetRawInputDeviceList(NULL, &devCount, sizeof(RAWINPUTDEVICELIST))) { return; } deviceList = SDL_malloc(sizeof(RAWINPUTDEVICELIST) * devCount); /* we're getting the raw input device list */ GetRawInputDeviceList(deviceList, &devCount, sizeof(RAWINPUTDEVICELIST)); mice = SDL_malloc(devCount * sizeof(HANDLE)); /* we're getting the details of the devices */ for (i = 0; i < devCount; ++i) { int is_rdp = 0; int j; int k; char *default_device_name = "Pointing device xx"; const char *reg_key_root = "System\\CurrentControlSet\\Enum\\"; char *device_name = SDL_malloc(256 * sizeof(char)); char *key_name = NULL; char *tmp_name = NULL; LONG rc = 0; HKEY hkey; DWORD regtype = REG_SZ; DWORD out = 256 * sizeof(char); SDL_Mouse mouse; int l; if (deviceList[i].dwType != RIM_TYPEMOUSE) { /* if a device isn't a mouse type we don't want it */ continue; } if (GetRawInputDeviceInfoA (deviceList[i].hDevice, RIDI_DEVICENAME, NULL, &tmp) < 0) { continue; } buffer = SDL_malloc((tmp + 1) * sizeof(char)); key_name = SDL_malloc((tmp + SDL_strlen(reg_key_root) + 1) * sizeof(char)); /* we're getting the device registry path and polishing it to get it's name, surely there must be an easier way, but we haven't found it yet */ if (GetRawInputDeviceInfoA (deviceList[i].hDevice, RIDI_DEVICENAME, buffer, &tmp) < 0) { continue; } buffer += 4; tmp -= 4; tmp_name = buffer; for (j = 0; j < tmp; ++j) { if (*tmp_name == '#') { *tmp_name = '\\'; } else if (*tmp_name == '{') { break; } ++tmp_name; } *tmp_name = '\0'; SDL_memcpy(key_name, reg_key_root, SDL_strlen(reg_key_root)); SDL_memcpy(key_name + (SDL_strlen(reg_key_root)), buffer, j + 1); l = SDL_strlen(key_name); is_rdp = 0; if (l >= 7) { for (j = 0; j < l - 7; ++j) { for (k = 0; k < 7; ++k) { if (rdp[k] != SDL_tolower((unsigned char) key_name[j + k])) { break; } } if (k == 7) { is_rdp = 1; break; } } } buffer -= 4; if (is_rdp == 1) { SDL_free(buffer); SDL_free(key_name); SDL_free(device_name); is_rdp = 0; continue; } /* we're opening the registry key to get the mouse name */ rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &hkey); if (rc != ERROR_SUCCESS) { SDL_memcpy(device_name, default_device_name, SDL_strlen(default_device_name)); } rc = RegQueryValueExA(hkey, "DeviceDesc", NULL, ®type, device_name, &out); RegCloseKey(hkey); if (rc != ERROR_SUCCESS) { SDL_memcpy(device_name, default_device_name, SDL_strlen(default_device_name)); } /* we're saving the handle to the device */ mice[index] = deviceList[i].hDevice; SDL_zero(mouse); mouse.id = index; l = SDL_strlen(device_name); /* we're checking if the device isn't by any chance a tablet */ if (data->wintabDLL && tablet == -1) { for (j = 0; j < l - 5; ++j) { for (k = 0; k < 5; ++k) { if (tab[k] != SDL_tolower((unsigned char) device_name[j + k])) { break; } } if (k == 5) { tablet = index; break; } } } /* if it's a tablet, let's read it's maximum and minimum pressure */ if (tablet == index) { AXIS pressure; int cursors; data->WTInfoA(WTI_DEVICES, DVC_NPRESSURE, &pressure); data->WTInfoA(WTI_DEVICES, DVC_NCSRTYPES, &cursors); SDL_AddMouse(&mouse, device_name, pressure.axMax, pressure.axMin, cursors); } else { SDL_AddMouse(&mouse, device_name, 0, 0, 1); } ++index; SDL_free(buffer); SDL_free(key_name); } total_mice = index; SDL_free(deviceList); #endif /*_WIN32_WCE*/ }