Merge pull request #925 from shuffle2/xbcd-compat

Revert changes to how DInput filters out XInput devices.
This commit is contained in:
shuffle2 2014-09-02 23:21:47 -07:00
commit de71db4864
5 changed files with 158 additions and 12 deletions

View File

@ -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<Core::Device*>& devices, HWND hwnd)
{
std::list<DIDEVICEINSTANCE> 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<TCHAR>, int> name_counts;
std::vector<DWORD> 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;
}

View File

@ -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 <vector>
#include <WbemIdl.h>
#include <Windows.h>
#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<DWORD>* 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

View File

@ -0,0 +1,14 @@
#pragma once
#include <vector>
#include <Windows.h>
namespace ciface
{
namespace DInput
{
void GetXInputGUIDS(std::vector<DWORD>* guids);
}
}

View File

@ -41,6 +41,14 @@
<ClCompile Include="ControllerInterface\DInput\DInput.cpp" />
<ClCompile Include="ControllerInterface\DInput\DInputJoystick.cpp" />
<ClCompile Include="ControllerInterface\DInput\DInputKeyboardMouse.cpp" />
<ClCompile Include="ControllerInterface\DInput\XInputFilter.cpp">
<!--Disable /Zc:strictStrings so that wbem headers may compile-->
<!--
This is somewhat gross as it doesn't dynamically remove the option,
I really hope the issue is fixed in next VS release :(
-->
<AdditionalOptions>/Zo /Zc:inline /Zc:rvalueCast /volatile:iso</AdditionalOptions>
</ClCompile>
<ClCompile Include="ControllerInterface\ExpressionParser.cpp" />
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp" />
<ClCompile Include="ControllerInterface\XInput\XInput.cpp" />
@ -54,6 +62,7 @@
<ClInclude Include="ControllerInterface\DInput\DInput8.h" />
<ClInclude Include="ControllerInterface\DInput\DInputJoystick.h" />
<ClInclude Include="ControllerInterface\DInput\DInputKeyboardMouse.h" />
<ClInclude Include="ControllerInterface\DInput\XInputFilter.h" />
<ClInclude Include="ControllerInterface\ExpressionParser.h" />
<ClInclude Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.h" />
<ClInclude Include="ControllerInterface\XInput\XInput.h" />

View File

@ -41,6 +41,9 @@
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp">
<Filter>ControllerInterface\ForceFeedback</Filter>
</ClCompile>
<ClCompile Include="ControllerInterface\DInput\XInputFilter.cpp">
<Filter>ControllerInterface\DInput</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ControllerEmu.h" />
@ -73,6 +76,9 @@
<ClInclude Include="ControllerInterface\DInput\DInput8.h">
<Filter>ControllerInterface\DInput</Filter>
</ClInclude>
<ClInclude Include="ControllerInterface\DInput\XInputFilter.h">
<Filter>ControllerInterface\DInput</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />