Merge pull request #20347 from hrydgard/dinput-fixes

DInput: Properly ignore XInput devices individually, instead of ignoring all if XInput is available
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2025-05-17 01:21:39 +02:00
commit 9a0f9a2674
7 files changed
+118 -74

No files matched your search

+85 -37
View File
@@ -24,6 +24,9 @@
#include <XInput.h>
#include <wrl/client.h>
#include <wbemidl.h>
#include <comdef.h>
#include <set>
#include "Common/Input/InputState.h"
#include "Common/Input/KeyCodes.h"
#include "Common/StringUtils.h"
@@ -32,10 +35,12 @@
#include "Windows/DinputDevice.h"
#pragma comment(lib,"dinput8.lib")
//initialize static members of DinputDevice
// static members of DinputDevice
unsigned int DinputDevice::pInstances = 0;
Microsoft::WRL::ComPtr<IDirectInput8> DinputDevice::pDI;
std::vector<DIDEVICEINSTANCE> DinputDevice::devices;
std::set<u32> DinputDevice::ignoreDevices_;
bool DinputDevice::needsCheck_ = true;
// In order from 0. There can be 128, but most controllers do not have that many.
@@ -64,23 +69,7 @@ static const InputKeyCode dinput_buttons[] = {
#define JOY_POVBACKWARD_LEFT JOY_POVBACKWARD + DIFF
#define JOY_POVLEFT_FORWARD JOY_POVLEFT + DIFF
struct XINPUT_DEVICE_NODE {
DWORD dwVidPid;
XINPUT_DEVICE_NODE* pNext;
};
XINPUT_DEVICE_NODE* g_pXInputDeviceList = NULL;
bool IsXInputDevice( const GUID* pGuidProductFromDirectInput ) {
XINPUT_DEVICE_NODE* pNode = g_pXInputDeviceList;
while( pNode )
{
if( pNode->dwVidPid == pGuidProductFromDirectInput->Data1 )
return true;
pNode = pNode->pNext;
}
return false;
}
static std::set<u32> DetectXInputVIDPIDs();
LPDIRECTINPUT8 DinputDevice::getPDI()
{
@@ -94,30 +83,28 @@ LPDIRECTINPUT8 DinputDevice::getPDI()
return pDI.Get();
}
BOOL CALLBACK DinputDevice::DevicesCallback(
LPCDIDEVICEINSTANCE lpddi,
LPVOID pvRef
)
{
BOOL CALLBACK DinputDevice::DevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) {
//check if a device with the same Instance guid is already saved
auto res = std::find_if(devices.begin(), devices.end(),
[lpddi](const DIDEVICEINSTANCE &to_consider){
return lpddi->guidInstance == to_consider.guidInstance;
});
if (res == devices.end()) //not yet in the devices list
{
// Ignore if device supports XInput
if (!IsXInputDevice(&lpddi->guidProduct)) {
if (res == devices.end()) {
// not yet in the devices list
// Ignore if device supports XInput - we'll get the input through there instead.
const u32 vidpid = lpddi->guidProduct.Data1;
const bool isXinputDevice = ignoreDevices_.find(vidpid) != ignoreDevices_.end();
if (!isXinputDevice) {
devices.push_back(*lpddi);
}
}
return DIENUM_CONTINUE;
}
void DinputDevice::getDevices(bool refresh)
{
if (refresh)
{
void DinputDevice::getDevices(bool refresh) {
if (refresh) {
// We don't want duplicate reporting from XInput devices through DInput.
ignoreDevices_ = DetectXInputVIDPIDs();
getPDI()->EnumDevices(DI8DEVCLASS_GAMECTRL, &DinputDevice::DevicesCallback, NULL, DIEDFL_ATTACHEDONLY);
}
}
@@ -126,8 +113,6 @@ DinputDevice::DinputDevice(int devnum) {
pInstances++;
pDevNum = devnum;
pJoystick = nullptr;
memset(lastButtons_, 0, sizeof(lastButtons_));
memset(lastPOV_, 0, sizeof(lastPOV_));
last_lX_ = 0;
last_lY_ = 0;
last_lZ_ = 0;
@@ -135,13 +120,11 @@ DinputDevice::DinputDevice(int devnum) {
last_lRy_ = 0;
last_lRz_ = 0;
if (getPDI() == NULL)
{
if (!getPDI()) {
return;
}
if (devnum >= MAX_NUM_PADS)
{
if (devnum >= MAX_NUM_PADS) {
return;
}
@@ -325,3 +308,68 @@ size_t DinputDevice::getNumPads()
needsCheck_ = false;
return devices.size();
}
static std::set<u32> DetectXInputVIDPIDs() {
std::set<u32> xinputVidPids;
/*
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
return xinputVidPids;
}
*/
IWbemLocator* pIWbemLocator = nullptr;
if (FAILED(CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER,
__uuidof(IWbemLocator), (void**)&pIWbemLocator)))
return xinputVidPids;
IWbemServices* pIWbemServices = nullptr;
if (FAILED(pIWbemLocator->ConnectServer(_bstr_t(L"root\\cimv2"), nullptr, nullptr, nullptr, 0,
nullptr, nullptr, &pIWbemServices))) {
pIWbemLocator->Release();
return xinputVidPids;
}
CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
IEnumWbemClassObject* pEnumDevices = nullptr;
if (FAILED(pIWbemServices->CreateInstanceEnum(_bstr_t(L"Win32_PNPEntity"), 0, nullptr, &pEnumDevices))) {
pIWbemServices->Release();
pIWbemLocator->Release();
return xinputVidPids;
}
IWbemClassObject* pDevices[20] = { 0 };
ULONG uReturned = 0;
while (SUCCEEDED(pEnumDevices->Next(10000, 20, pDevices, &uReturned)) && uReturned > 0) {
for (ULONG i = 0; i < uReturned; i++) {
VARIANT var;
if (SUCCEEDED(pDevices[i]->Get(L"DeviceID", 0, &var, nullptr, nullptr)))
{
if (wcsstr(var.bstrVal, L"IG_"))
{
DWORD vid = 0, pid = 0;
const WCHAR *strVid = wcsstr(var.bstrVal, L"VID_");
const WCHAR *strPid = wcsstr(var.bstrVal, L"PID_");
if (strVid) swscanf_s(strVid, L"VID_%4x", &vid);
if (strPid) swscanf_s(strPid, L"PID_%4x", &pid);
const DWORD vidpid = MAKELONG(vid, pid);
xinputVidPids.insert((u32)vidpid);
}
VariantClear(&var);
}
pDevices[i]->Release();
}
}
pEnumDevices->Release();
pIWbemServices->Release();
pIWbemLocator->Release();
// CoUninitialize();
return xinputVidPids;
}
+13 -7
View File
@@ -18,6 +18,7 @@
#pragma once
#include <vector>
#include <set>
#include <InitGuid.h>
#include <wrl/client.h>
#define DIRECTINPUT_VERSION 0x0800
@@ -25,6 +26,8 @@
#include "InputDevice.h"
#include <dinput.h>
// TODO: This needs a major refactor into a DinputManager and individual devices inside.
class DinputDevice final :
public InputDevice
{
@@ -39,6 +42,10 @@ public:
needsCheck_ = true;
}
static void SetDevicesToIgnore(std::set<u32> &&ignoreDevices) {
ignoreDevices_ = std::move(ignoreDevices);
}
private:
void ApplyButtons(DIJOYSTATE2 &state);
//unfortunate and unclean way to keep only one DirectInput instance around
@@ -49,20 +56,19 @@ private:
//also, it excludes the devices that are compatible with XInput
static void getDevices(bool refresh);
//callback for the WinAPI to call
static BOOL CALLBACK DevicesCallback(
LPCDIDEVICEINSTANCE lpddi,
LPVOID pvRef
);
static unsigned int pInstances;
static BOOL CALLBACK DevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
static unsigned int pInstances;
static std::vector<DIDEVICEINSTANCE> devices;
static Microsoft::WRL::ComPtr<IDirectInput8> pDI;
static bool needsCheck_;
static std::set<u32> ignoreDevices_;
int pDevNum;
Microsoft::WRL::ComPtr<IDirectInputDevice8> pJoystick;
DIJOYSTATE2 pPrevState;
bool analog;
BYTE lastButtons_[128];
WORD lastPOV_[4];
BYTE lastButtons_[128]{};
WORD lastPOV_[4]{};
int last_lX_;
int last_lY_;
int last_lZ_;
+10 -2
View File
@@ -159,7 +159,10 @@ void MainThreadFunc() {
// We'll start up a separate thread we'll call Emu
SetCurrentThreadName(useEmuThread ? "RenderThread" : "EmuThread");
SetConsolePosition();
const HWND console = GetConsoleWindow();
if (console && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) {
SetWindowPos(console, NULL, g_Config.iConsoleWindowX, g_Config.iConsoleWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
System_SetWindowTitle("");
@@ -333,7 +336,12 @@ void MainThreadFunc() {
delete g_graphicsContext;
UpdateConsolePosition();
RECT rc;
if (console && GetWindowRect(console, &rc) && !IsIconic(console)) {
g_Config.iConsoleWindowX = rc.left;
g_Config.iConsoleWindowY = rc.top;
}
NativeShutdown();
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0);
+8 -8
View File
@@ -249,7 +249,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86/lib</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
@@ -289,7 +289,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86_64/lib</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
@@ -325,7 +325,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/aarch64/lib</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
@@ -359,7 +359,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/arm/lib</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
@@ -397,7 +397,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -446,7 +446,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86_64/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
@@ -489,7 +489,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/aarch64/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
@@ -530,7 +530,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wbemuuid.lib;dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../ffmpeg/Windows/arm/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
+1 -16
View File
@@ -48,26 +48,11 @@
#include "Windows/main.h"
void SetConsolePosition() {
HWND console = GetConsoleWindow();
if (console != NULL && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) {
SetWindowPos(console, NULL, g_Config.iConsoleWindowX, g_Config.iConsoleWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
void UpdateConsolePosition() {
RECT rc;
HWND console = GetConsoleWindow();
if (console != NULL && GetWindowRect(console, &rc) && !IsIconic(console)) {
g_Config.iConsoleWindowX = rc.left;
g_Config.iConsoleWindowY = rc.top;
}
}
void WindowsInputManager::Init() {
//add first XInput device to respond
input.push_back(std::make_unique<XinputDevice>());
#ifndef _M_ARM
//find all connected DInput devices of class GamePad
numDinputDevices_ = DinputDevice::getNumPads();
for (size_t i = 0; i < numDinputDevices_; i++) {
-3
View File
@@ -21,9 +21,6 @@
#include "Common/CommonWindows.h"
#include "Windows/InputDevice.h"
void SetConsolePosition();
void UpdateConsolePosition();
class WindowsInputManager {
public:
void Init();
+1 -1
View File
@@ -183,7 +183,7 @@ int XinputDevice::UpdateState() {
// If we get XInput, skip the others. This might not actually be a good idea,
// and was done to avoid conflicts between DirectInput and XInput.
return anySuccess ? UPDATESTATE_SKIP_PAD : 0;
return 0; // anySuccess ? UPDATESTATE_SKIP_PAD : 0;
}
void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATION &vibration) {