From 3c0227445cb75f2798d8bcf1d284566c16f6f940 Mon Sep 17 00:00:00 2001 From: Shawn Hoffman Date: Sun, 31 Aug 2014 22:41:33 -0700 Subject: [PATCH] Revert changes to how DInput filters out XInput devices. This is to remain compatible with XBCD devices. --- .../DInput/DInputJoystick.cpp | 18 +-- .../DInput/XInputFilter.cpp | 123 ++++++++++++++++++ .../ControllerInterface/DInput/XInputFilter.h | 14 ++ Source/Core/InputCommon/InputCommon.vcxproj | 9 ++ .../InputCommon/InputCommon.vcxproj.filters | 6 + 5 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp create mode 100644 Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp index 7d1db57427..1ff48877db 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp @@ -8,6 +8,7 @@ #include "InputCommon/ControllerInterface/DInput/DInput.h" #include "InputCommon/ControllerInterface/DInput/DInputJoystick.h" +#include "InputCommon/ControllerInterface/DInput/XInputFilter.h" namespace ciface { @@ -16,29 +17,22 @@ namespace DInput #define DATA_BUFFER_SIZE 32 -static const GUID s_known_xinput_guids[] = { - // ValveStreamingGamepad - { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, - // IID_X360WiredGamepad - { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, - // IID_X360WirelessGamepad - { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, -}; - void InitJoystick(IDirectInput8* const idi8, std::vector& devices, HWND hwnd) { std::list joysticks; - idi8->EnumDevices( DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, (LPVOID)&joysticks, DIEDFL_ATTACHEDONLY ); + idi8->EnumDevices(DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, (LPVOID)&joysticks, DIEDFL_ATTACHEDONLY); // this is used to number the joysticks // multiple joysticks with the same name shall get unique ids starting at 0 std::map< std::basic_string, int> name_counts; + std::vector xinput_guids; + GetXInputGUIDS(&xinput_guids); + for (DIDEVICEINSTANCE& joystick : joysticks) { // skip XInput Devices - if (std::find(std::begin(s_known_xinput_guids), std::end(s_known_xinput_guids), - joystick.guidProduct) != std::end(s_known_xinput_guids)) + if (std::find(xinput_guids.begin(), xinput_guids.end(), joystick.guidProduct.Data1) != xinput_guids.end()) { continue; } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp new file mode 100644 index 0000000000..a9a6c33918 --- /dev/null +++ b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp @@ -0,0 +1,123 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +// This function is contained in a separate file because WbemIdl.h pulls in files which break on +// /Zc:strictStrings, so this compilation unit is compiled without /Zc:strictStrings. + +#include +#include +#include + +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=nullptr; } } + +namespace ciface +{ +namespace DInput +{ + +//----------------------------------------------------------------------------- +// Modified some MSDN code to get all the XInput device GUID.Data1 values in a vector, +// faster than checking all the devices for each DirectInput device, like MSDN says to do +//----------------------------------------------------------------------------- +void GetXInputGUIDS(std::vector* guids) +{ + IWbemLocator* pIWbemLocator = nullptr; + IEnumWbemClassObject* pEnumDevices = nullptr; + IWbemClassObject* pDevices[20] = {0}; + IWbemServices* pIWbemServices = nullptr; + BSTR bstrNamespace = nullptr; + BSTR bstrDeviceID = nullptr; + BSTR bstrClassName = nullptr; + DWORD uReturned = 0; + VARIANT var; + HRESULT hr; + + // CoInit if needed + hr = CoInitialize(nullptr); + bool bCleanupCOM = SUCCEEDED(hr); + + // Create WMI + hr = CoCreateInstance(__uuidof(WbemLocator), + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWbemLocator), + (LPVOID*) &pIWbemLocator); + if (FAILED(hr) || pIWbemLocator == nullptr) + goto LCleanup; + + bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == nullptr) goto LCleanup; + bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == nullptr) goto LCleanup; + bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == nullptr) goto LCleanup; + + // Connect to WMI + hr = pIWbemLocator->ConnectServer(bstrNamespace, nullptr, nullptr, 0L, 0L, nullptr, nullptr, &pIWbemServices); + if (FAILED(hr) || pIWbemServices == nullptr) + goto LCleanup; + + // Switch security level to IMPERSONATE. + CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); + + hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, nullptr, &pEnumDevices); + if (FAILED(hr) || pEnumDevices == nullptr) + goto LCleanup; + + // Loop over all devices + while (true) + { + // Get 20 at a time + hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned); + if (FAILED(hr) || uReturned == 0) + break; + + for (UINT iDevice = 0; iDevice < uReturned; ++iDevice) + { + // For each device, get its device ID + hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, nullptr, nullptr); + if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != nullptr) + { + // Check if the device ID contains "IG_". If it does, then it's an XInput device + // This information can not be found from DirectInput + if (wcsstr(var.bstrVal, L"IG_")) + { + // If it does, then get the VID/PID from var.bstrVal + DWORD dwPid = 0, dwVid = 0; + WCHAR* strVid = wcsstr(var.bstrVal, L"VID_"); + if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1) + dwVid = 0; + WCHAR* strPid = wcsstr(var.bstrVal, L"PID_"); + if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1) + dwPid = 0; + + // Compare the VID/PID to the DInput device + DWORD dwVidPid = MAKELONG(dwVid, dwPid); + guids->push_back(dwVidPid); + //bIsXinputDevice = true; + } + } + SAFE_RELEASE(pDevices[iDevice]); + } + } + +LCleanup: + if (bstrNamespace) + SysFreeString(bstrNamespace); + if (bstrDeviceID) + SysFreeString(bstrDeviceID); + if (bstrClassName) + SysFreeString(bstrClassName); + for (UINT iDevice = 0; iDevice < 20; iDevice++) + SAFE_RELEASE(pDevices[iDevice]); + SAFE_RELEASE(pEnumDevices); + SAFE_RELEASE(pIWbemLocator); + SAFE_RELEASE(pIWbemServices); + + if (bCleanupCOM) + CoUninitialize(); +} + +} +} + +#undef SAFE_RELEASE diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h new file mode 100644 index 0000000000..1dcc1141bf --- /dev/null +++ b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace ciface +{ +namespace DInput +{ + +void GetXInputGUIDS(std::vector* guids); + +} +} diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index 2866846075..8a53642137 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -41,6 +41,14 @@ + + + + /Zo /Zc:inline /Zc:rvalueCast /volatile:iso + @@ -54,6 +62,7 @@ + diff --git a/Source/Core/InputCommon/InputCommon.vcxproj.filters b/Source/Core/InputCommon/InputCommon.vcxproj.filters index 25fab7a227..3c16ad5f26 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj.filters +++ b/Source/Core/InputCommon/InputCommon.vcxproj.filters @@ -41,6 +41,9 @@ ControllerInterface\ForceFeedback + + ControllerInterface\DInput + @@ -73,6 +76,9 @@ ControllerInterface\DInput + + ControllerInterface\DInput +