Play-/Source/ui_qt/win32/InputProviderXInput.cpp

183 lines
4.8 KiB
C++
Raw Normal View History

2019-06-18 21:29:09 -04:00
#include "InputProviderXInput.h"
#include "string_format.h"
2019-06-18 21:29:09 -04:00
#define PROVIDER_ID 'xinp'
const char* CInputProviderXInput::g_keyNames[CInputProviderXInput::KEYID_MAX] =
{
"Left Thumb (X Axis)",
"Left Thumb (Y Axis)",
"Right Thumb (X Axis)",
"Right Thumb (Y Axis)",
"Left Trigger",
"Right Trigger",
"DPad Up",
"DPad Down",
"DPad Left",
"DPad Right",
"Start",
"Back",
"Left Thumb",
"Right Thumb",
"Left Shoulder",
"Right Shoulder",
"A",
"B",
"X",
"Y"
};
const CInputProviderXInput::KEYID CInputProviderXInput::g_buttonToKey[MAX_BUTTONS] =
{
KEYID_DPAD_UP,
KEYID_DPAD_DOWN,
KEYID_DPAD_LEFT,
KEYID_DPAD_RIGHT,
KEYID_START,
KEYID_BACK,
KEYID_LTHUMB,
KEYID_RTHUMB,
KEYID_LSHOULDER,
KEYID_RSHOULDER,
KEYID_MAX,
KEYID_MAX,
KEYID_A,
KEYID_B,
KEYID_X,
KEYID_Y
};
2019-06-18 21:29:09 -04:00
CInputProviderXInput::CInputProviderXInput()
{
m_pollingThread = std::thread([this] () { PollDevices(); });
}
CInputProviderXInput::~CInputProviderXInput()
{
m_pollingEnabled = false;
m_pollingThread.join();
}
uint32 CInputProviderXInput::GetId() const
{
return PROVIDER_ID;
}
std::string CInputProviderXInput::GetTargetDescription(const BINDINGTARGET& target) const
{
return string_format("XInput Device %d : %s", target.deviceId[0], g_keyNames[target.keyId]);
2019-06-18 21:29:09 -04:00
}
void CInputProviderXInput::PollDevices()
{
while(m_pollingEnabled)
{
for(unsigned int deviceIndex = 0; deviceIndex < MAX_DEVICES; deviceIndex++)
2019-06-18 21:29:09 -04:00
{
auto& currState = m_states[deviceIndex];
if(currState.idleTime > 0)
{
currState.idleTime--;
continue;
}
2019-06-18 21:29:09 -04:00
XINPUT_STATE state;
DWORD result = XInputGetState(deviceIndex, &state);
2019-06-18 21:29:09 -04:00
if(result == ERROR_SUCCESS)
{
2019-06-19 20:00:57 -04:00
UpdateConnectedDevice(deviceIndex, state);
2019-06-18 21:29:09 -04:00
}
else
{
2019-06-19 20:00:57 -04:00
UpdateDisconnectedDevice(deviceIndex);
2019-06-18 21:29:09 -04:00
}
}
Sleep(16);
2019-06-18 21:29:09 -04:00
}
}
2019-06-19 20:00:57 -04:00
void CInputProviderXInput::UpdateConnectedDevice(uint32 deviceIndex, const XINPUT_STATE& state)
{
auto& currState = m_states[deviceIndex];
if((currState.connected == false) || (currState.packetNumber != state.dwPacketNumber))
{
ReportAxis(deviceIndex, KEYID_LTHUMB_X, state.Gamepad.sThumbLX);
2019-06-19 20:19:33 -04:00
ReportAxis(deviceIndex, KEYID_LTHUMB_Y, -static_cast<int32>(state.Gamepad.sThumbLY));
2019-06-19 20:00:57 -04:00
ReportAxis(deviceIndex, KEYID_RTHUMB_X, state.Gamepad.sThumbRX);
2019-06-19 20:19:33 -04:00
ReportAxis(deviceIndex, KEYID_RTHUMB_Y, -static_cast<int32>(state.Gamepad.sThumbRY));
2019-06-19 20:00:57 -04:00
bool lTriggerState = state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
bool rTriggerState = state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
if(lTriggerState != currState.lTriggerPressed)
{
ReportButton(deviceIndex, KEYID_LTRIGGER, lTriggerState);
currState.lTriggerPressed = lTriggerState;
}
if(rTriggerState != currState.rTriggerPressed)
{
ReportButton(deviceIndex, KEYID_RTRIGGER, rTriggerState);
currState.rTriggerPressed = rTriggerState;
}
for(unsigned int keyIndex = 0; keyIndex < MAX_BUTTONS; keyIndex++)
{
auto keyId = g_buttonToKey[keyIndex];
if(keyId == KEYID_MAX) continue;
bool newState = (state.Gamepad.wButtons & (1 << keyIndex)) != 0;
bool oldState = (currState.buttonState & (1 << keyIndex));
if(newState != oldState)
{
ReportButton(deviceIndex, keyId, newState);
}
}
currState.buttonState = state.Gamepad.wButtons;
currState.packetNumber = state.dwPacketNumber;
}
currState.connected = true;
}
void CInputProviderXInput::UpdateDisconnectedDevice(uint32 deviceIndex)
{
auto& currState = m_states[deviceIndex];
if(currState.connected)
{
//Going from connected to disconnected, reset state
ReportAxis(deviceIndex, KEYID_LTHUMB_X, BINDINGTARGET::AXIS_NEUTRAL);
ReportAxis(deviceIndex, KEYID_LTHUMB_Y, BINDINGTARGET::AXIS_NEUTRAL);
ReportAxis(deviceIndex, KEYID_RTHUMB_X, BINDINGTARGET::AXIS_NEUTRAL);
ReportAxis(deviceIndex, KEYID_RTHUMB_Y, BINDINGTARGET::AXIS_NEUTRAL);
ReportButton(deviceIndex, KEYID_LTRIGGER, false);
ReportButton(deviceIndex, KEYID_RTRIGGER, false);
for(unsigned int keyIndex = 0; keyIndex < MAX_BUTTONS; keyIndex++)
{
auto keyId = g_buttonToKey[keyIndex];
if(keyId == KEYID_MAX) continue;
ReportButton(deviceIndex, keyId, false);
}
currState.lTriggerPressed = false;
currState.rTriggerPressed = false;
currState.buttonState = 0;
}
currState.idleTime = 100;
currState.connected = false;
}
void CInputProviderXInput::ReportButton(uint32 deviceIndex, KEYID keyId, bool pressed)
{
BINDINGTARGET tgt;
tgt.providerId = PROVIDER_ID;
2019-06-19 20:00:57 -04:00
tgt.deviceId[0] = deviceIndex;
tgt.keyType = BINDINGTARGET::KEYTYPE::BUTTON;
tgt.keyId = keyId;
OnInput(tgt, pressed ? 1 : 0);
}
2019-06-19 20:19:33 -04:00
void CInputProviderXInput::ReportAxis(uint32 deviceIndex, KEYID keyId, int32 rawValue)
{
BINDINGTARGET tgt;
tgt.providerId = PROVIDER_ID;
2019-06-19 20:00:57 -04:00
tgt.deviceId[0] = deviceIndex;
tgt.keyType = BINDINGTARGET::KEYTYPE::AXIS;
tgt.keyId = keyId;
2019-06-19 20:19:33 -04:00
uint32 cvtValue = std::min<uint32>((rawValue + 0x8000) >> 8, BINDINGTARGET::AXIS_MAX);
OnInput(tgt, cvtValue);
}