mirror of https://github.com/PCSX2/pcsx2.git
XInputSource: Add support for SCP API extension
Allows to query pressure sensitive DualShock 3 buttons via XInput when DsHidMini is used in SXS mode, with its xinput1_3.dll dropped in the emulator directory.
This commit is contained in:
parent
5e913b0e9e
commit
502a44e9f5
|
@ -97,10 +97,12 @@ XInputSource::~XInputSource() = default;
|
|||
bool XInputSource::Initialize(SettingsInterface& si)
|
||||
{
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
m_xinput_module = LoadLibraryW(L"xinput1_4");
|
||||
// xinput1_3.dll is flawed and obsolete, but it's also commonly used by wrappers.
|
||||
// For this reason, try to load it *only* from the application directory, and not system32.
|
||||
m_xinput_module = LoadLibraryExW(L"xinput1_3", nullptr, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
if (!m_xinput_module)
|
||||
{
|
||||
m_xinput_module = LoadLibraryW(L"xinput1_3");
|
||||
m_xinput_module = LoadLibraryW(L"xinput1_4");
|
||||
}
|
||||
if (!m_xinput_module)
|
||||
{
|
||||
|
@ -121,10 +123,15 @@ bool XInputSource::Initialize(SettingsInterface& si)
|
|||
reinterpret_cast<decltype(m_xinput_set_state)>(GetProcAddress(m_xinput_module, "XInputSetState"));
|
||||
m_xinput_get_capabilities =
|
||||
reinterpret_cast<decltype(m_xinput_get_capabilities)>(GetProcAddress(m_xinput_module, "XInputGetCapabilities"));
|
||||
|
||||
// SCP extension, only exists when the bridge xinput1_3.dll is in use
|
||||
m_xinput_get_extended =
|
||||
reinterpret_cast<decltype(m_xinput_get_extended)>(GetProcAddress(m_xinput_module, "XInputGetExtended"));
|
||||
#else
|
||||
m_xinput_get_state = XInputGetState;
|
||||
m_xinput_set_state = XInputSetState;
|
||||
m_xinput_get_capabilities = XInputGetCapabilities;
|
||||
m_xinput_get_extended = nullptr;
|
||||
#endif
|
||||
if (!m_xinput_get_state || !m_xinput_set_state || !m_xinput_get_capabilities)
|
||||
{
|
||||
|
@ -158,29 +165,44 @@ void XInputSource::Shutdown()
|
|||
m_xinput_get_state = nullptr;
|
||||
m_xinput_set_state = nullptr;
|
||||
m_xinput_get_capabilities = nullptr;
|
||||
m_xinput_get_extended = nullptr;
|
||||
}
|
||||
|
||||
void XInputSource::PollEvents()
|
||||
{
|
||||
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||
{
|
||||
XINPUT_STATE new_state;
|
||||
const DWORD result = m_xinput_get_state(i, &new_state);
|
||||
const bool was_connected = m_controllers[i].connected;
|
||||
|
||||
SCP_EXTN new_state_scp;
|
||||
DWORD result = m_xinput_get_extended ? m_xinput_get_extended(i, &new_state_scp) : ERROR_NOT_SUPPORTED;
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
if (!was_connected)
|
||||
HandleControllerConnection(i);
|
||||
|
||||
CheckForStateChanges(i, new_state);
|
||||
CheckForStateChangesSCP(i, new_state_scp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result != ERROR_DEVICE_NOT_CONNECTED)
|
||||
Console.Warning("XInputGetState(%u) failed: 0x%08X / 0x%08X", i, result, GetLastError());
|
||||
XINPUT_STATE new_state;
|
||||
result = m_xinput_get_state(i, &new_state);
|
||||
|
||||
if (was_connected)
|
||||
HandleControllerDisconnection(i);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
if (!was_connected)
|
||||
HandleControllerConnection(i);
|
||||
|
||||
CheckForStateChanges(i, new_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result != ERROR_DEVICE_NOT_CONNECTED)
|
||||
Console.Warning("XInputGetState(%u) failed: 0x%08X / 0x%08X", i, result, GetLastError());
|
||||
|
||||
if (was_connected)
|
||||
HandleControllerDisconnection(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,6 +384,8 @@ void XInputSource::HandleControllerConnection(u32 index)
|
|||
cd.connected = true;
|
||||
cd.has_large_motor = caps.Vibration.wLeftMotorSpeed != 0;
|
||||
cd.has_small_motor = caps.Vibration.wRightMotorSpeed != 0;
|
||||
cd.last_state = {};
|
||||
cd.last_state_scp = {};
|
||||
|
||||
Host::OnInputDeviceConnected(StringUtil::StdStringFromFormat("XInput-%u", index),
|
||||
StringUtil::StdStringFromFormat("XInput Controller %u", index));
|
||||
|
@ -381,8 +405,6 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
|
|||
if (new_state.dwPacketNumber == cd.last_state.dwPacketNumber)
|
||||
return;
|
||||
|
||||
cd.last_state.dwPacketNumber = new_state.dwPacketNumber;
|
||||
|
||||
XINPUT_GAMEPAD& ogp = cd.last_state.Gamepad;
|
||||
const XINPUT_GAMEPAD& ngp = new_state.Gamepad;
|
||||
|
||||
|
@ -392,7 +414,6 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
|
|||
InputManager::InvokeEvents( \
|
||||
MakeGenericControllerAxisKey(InputSourceType::XInput, index, axis), \
|
||||
static_cast<float>(ngp.field) / ((ngp.field < 0) ? min_value : max_value)); \
|
||||
ogp.field = ngp.field; \
|
||||
}
|
||||
|
||||
// Y axes is inverted in XInput when compared to SDL.
|
||||
|
@ -418,10 +439,68 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
|
|||
MakeGenericControllerButtonKey(InputSourceType::XInput, index, button),
|
||||
(new_button_bits & button_mask) != 0);
|
||||
}
|
||||
|
||||
ogp.wButtons = ngp.wButtons;
|
||||
}
|
||||
}
|
||||
|
||||
cd.last_state = new_state;
|
||||
}
|
||||
|
||||
void XInputSource::CheckForStateChangesSCP(u32 index, const SCP_EXTN& new_state)
|
||||
{
|
||||
ControllerData& cd = m_controllers[index];
|
||||
|
||||
SCP_EXTN& ogp = cd.last_state_scp;
|
||||
const SCP_EXTN& ngp = new_state;
|
||||
|
||||
s32 axis = 0, button = 0;
|
||||
|
||||
#define CHECK_AXIS(field) \
|
||||
if (ogp.field != ngp.field) \
|
||||
{ \
|
||||
InputManager::InvokeEvents( \
|
||||
MakeGenericControllerAxisKey(InputSourceType::XInput, index, axis), ngp.field); \
|
||||
} \
|
||||
axis++;
|
||||
|
||||
#define CHECK_BUTTON(field) \
|
||||
if (ogp.field != ngp.field) \
|
||||
{ \
|
||||
InputManager::InvokeEvents( \
|
||||
MakeGenericControllerButtonKey(InputSourceType::XInput, index, button), ngp.field); \
|
||||
} \
|
||||
button++;
|
||||
|
||||
CHECK_AXIS(SCP_LX);
|
||||
CHECK_AXIS(SCP_LY);
|
||||
CHECK_AXIS(SCP_RX);
|
||||
CHECK_AXIS(SCP_RY);
|
||||
CHECK_AXIS(SCP_L2);
|
||||
CHECK_AXIS(SCP_R2);
|
||||
|
||||
CHECK_BUTTON(SCP_UP);
|
||||
CHECK_BUTTON(SCP_DOWN);
|
||||
CHECK_BUTTON(SCP_LEFT);
|
||||
CHECK_BUTTON(SCP_RIGHT);
|
||||
|
||||
CHECK_BUTTON(SCP_START);
|
||||
CHECK_BUTTON(SCP_SELECT);
|
||||
|
||||
CHECK_BUTTON(SCP_L3);
|
||||
CHECK_BUTTON(SCP_R3);
|
||||
CHECK_BUTTON(SCP_L1);
|
||||
CHECK_BUTTON(SCP_R1);
|
||||
|
||||
CHECK_BUTTON(SCP_X);
|
||||
CHECK_BUTTON(SCP_C);
|
||||
CHECK_BUTTON(SCP_S);
|
||||
CHECK_BUTTON(SCP_T);
|
||||
|
||||
CHECK_BUTTON(SCP_PS);
|
||||
|
||||
#undef CHECK_BUTTON
|
||||
#undef CHECK_AXIS
|
||||
|
||||
cd.last_state_scp = new_state;
|
||||
}
|
||||
|
||||
void XInputSource::UpdateMotorState(InputBindingKey key, float intensity)
|
||||
|
|
|
@ -21,6 +21,39 @@
|
|||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
// SCP XInput extension
|
||||
typedef struct
|
||||
{
|
||||
float SCP_UP;
|
||||
float SCP_RIGHT;
|
||||
float SCP_DOWN;
|
||||
float SCP_LEFT;
|
||||
|
||||
float SCP_LX;
|
||||
float SCP_LY;
|
||||
|
||||
float SCP_L1;
|
||||
float SCP_L2;
|
||||
float SCP_L3;
|
||||
|
||||
float SCP_RX;
|
||||
float SCP_RY;
|
||||
|
||||
float SCP_R1;
|
||||
float SCP_R2;
|
||||
float SCP_R3;
|
||||
|
||||
float SCP_T;
|
||||
float SCP_C;
|
||||
float SCP_X;
|
||||
float SCP_S;
|
||||
|
||||
float SCP_SELECT;
|
||||
float SCP_START;
|
||||
|
||||
float SCP_PS;
|
||||
} SCP_EXTN;
|
||||
|
||||
class SettingsInterface;
|
||||
|
||||
class XInputSource final : public InputSource
|
||||
|
@ -63,9 +96,13 @@ private:
|
|||
|
||||
struct ControllerData
|
||||
{
|
||||
XINPUT_STATE last_state = {};
|
||||
union
|
||||
{
|
||||
XINPUT_STATE last_state;
|
||||
SCP_EXTN last_state_scp;
|
||||
};
|
||||
XINPUT_VIBRATION last_vibration = {};
|
||||
bool connected = false;
|
||||
bool connected = false;
|
||||
bool has_large_motor = false;
|
||||
bool has_small_motor = false;
|
||||
};
|
||||
|
@ -73,6 +110,7 @@ private:
|
|||
using ControllerDataArray = std::array<ControllerData, NUM_CONTROLLERS>;
|
||||
|
||||
void CheckForStateChanges(u32 index, const XINPUT_STATE& new_state);
|
||||
void CheckForStateChangesSCP(u32 index, const SCP_EXTN& new_state);
|
||||
void HandleControllerConnection(u32 index);
|
||||
void HandleControllerDisconnection(u32 index);
|
||||
|
||||
|
@ -82,6 +120,7 @@ private:
|
|||
DWORD(WINAPI* m_xinput_get_state)(DWORD, XINPUT_STATE*);
|
||||
DWORD(WINAPI* m_xinput_set_state)(DWORD, XINPUT_VIBRATION*);
|
||||
DWORD(WINAPI* m_xinput_get_capabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
|
||||
DWORD(WINAPI* m_xinput_get_extended)(DWORD, SCP_EXTN*);
|
||||
|
||||
static const char* s_axis_names[NUM_AXES];
|
||||
static const char* s_button_names[NUM_BUTTONS];
|
||||
|
|
Loading…
Reference in New Issue