Example #1
0
// 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;
}
Example #2
0
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);
   }
}
Example #3
0
/* 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;
}
Example #4
0
/* 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__ */
}
Example #5
0
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;
}
Example #7
0
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, &regtype, 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*/
}