mumble-voip_mumble/3rdparty/xinputcheck-src/xinputcheck.cpp

161 lines
7.1 KiB
C++

/*
Simple DirectMedia Layer
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "xinputcheck.h"
#include <string.h>
#include <stdlib.h>
// XInputCheck is an XInput check abstracted away from SDL.
//
// If you need to update this file, please arrange the code such that
// it is possible to copy/paste directly from SDL. This makes code
// sharing easier! Right now, the SDL_IsXInputDevice is directly
// copied from SDL.
//
// Below, we have a few preprocessor defines, that allow the SDL functions
// we use, to run in our environment.
//
// After that, there is an implementation of the SDL_XINPUT_Enabled
// that always returns true.
//
// Then comes the implementation of SDL_IsXInputDevice, which is copied
// directly from SDL.
//
// At the bottom of the file, you'll find our wrapper interfaces --
// the public API for the XInputCheck library.
//
// Again, if you ever need to change anything in the SDL functions, well.
// Think again! If you find a bug, feel free to fix it, but report it
// upstream as well.
// If at all possible, try to use wrapper functions to implement "new"
// functionality (such as XInputCheck_ClearDeviceCache, for clearing
// the internal cache).
// Preprocessor helpers for running SDL code as-is.
#define SDL_bool bool
#define SDL_TRUE true
#define SDL_FALSE false
#define SDL_free free
#define SDL_malloc malloc
#define SDL_OutOfMemory abort
#define SDL_strstr strstr
#define SDL_memcmp memcmp
#define SDL_arraysize(array) (sizeof(array)/sizeof(array[0]))
static SDL_bool
SDL_XINPUT_Enabled() {
return SDL_TRUE;
}
static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
static UINT SDL_RawDevListCount = 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 XInputCheck_IsGuidProductXInputDevice(const GUID *pGuidProductFromDirectInput) {
return SDL_IsXInputDevice(pGuidProductFromDirectInput);
}
void XInputCheck_ClearDeviceCache() {
SDL_free(SDL_RawDevList);
SDL_RawDevList = NULL;
SDL_RawDevListCount = 0;
}