dolphin/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp
Filoppi a0ecca1a84 ControllerInterface: Implement ChangeWindow on DInput without recreating the devices
Also polished DInput code in general to try and mitigate issue 11702.
Added a lot of logging and comments.
2021-06-07 11:07:06 +03:00

101 lines
3.0 KiB
C++

// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "InputCommon/ControllerInterface/DInput/DInput.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/ControllerInterface/DInput/DInputJoystick.h"
#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h"
#pragma comment(lib, "Dinput8.lib")
#pragma comment(lib, "dxguid.lib")
namespace ciface::DInput
{
static IDirectInput8* s_idi8 = nullptr;
BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
{
((std::list<DIDEVICEOBJECTINSTANCE>*)pvRef)->push_back(*lpddoi);
return DIENUM_CONTINUE;
}
BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{
((std::list<DIDEVICEINSTANCE>*)pvRef)->push_back(*lpddi);
return DIENUM_CONTINUE;
}
std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device)
{
DIPROPSTRING str = {};
str.diph.dwSize = sizeof(str);
str.diph.dwHeaderSize = sizeof(str.diph);
str.diph.dwHow = DIPH_DEVICE;
std::string result;
if (SUCCEEDED(device->GetProperty(DIPROP_PRODUCTNAME, &str.diph)))
{
result = StripSpaces(WStringToUTF8(str.wsz));
}
else
{
ERROR_LOG_FMT(CONTROLLERINTERFACE, "GetProperty(DIPROP_PRODUCTNAME) failed.");
}
return result;
}
// Assumes hwnd had not changed from the previous call
void PopulateDevices(HWND hwnd)
{
if (!s_idi8 && FAILED(DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION,
IID_IDirectInput8, (LPVOID*)&s_idi8, nullptr)))
{
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DirectInput8Create failed.");
return;
}
// Remove old (invalid) devices. No need to ever remove the KeyboardMouse device.
// Note that if we have 2+ DInput controllers, not fully repopulating devices
// will mean that a device with index "2" could persist while there is no device with index "0".
// This is slightly inconsistent as when we refresh all devices, they will instead reset, and
// that happens a lot (for uncontrolled reasons, like starting/stopping the emulation).
g_controller_interface.RemoveDevice(
[](const auto* dev) { return dev->GetSource() == DINPUT_SOURCE_NAME && !dev->IsValid(); });
InitKeyboardMouse(s_idi8, hwnd);
InitJoystick(s_idi8, hwnd);
}
void ChangeWindow(HWND hwnd)
{
if (s_idi8) // Has init? Ignore if called before the first PopulateDevices()
{
// The KeyboardMouse device is marked as virtual device, so we avoid removing it.
// We need to force all the DInput joysticks to be destroyed now, or recreation would fail.
g_controller_interface.RemoveDevice(
[](const auto* dev) {
return dev->GetSource() == DINPUT_SOURCE_NAME && !dev->IsVirtualDevice();
},
true);
SetKeyboardMouseWindow(hwnd);
InitJoystick(s_idi8, hwnd);
}
}
void DeInit()
{
if (s_idi8)
{
s_idi8->Release();
s_idi8 = nullptr;
}
}
} // namespace ciface::DInput