Input: Fixed bug with gamepad buttons sometimes detected as unpressed when pressed (multithread bug)

This commit is contained in:
Souryo 2017-06-04 17:16:57 -04:00
parent 5cd5c292b6
commit c14f046990
4 changed files with 21 additions and 19 deletions

View file

@ -354,12 +354,11 @@ bool DirectInputManager::IsPressed(int port, int button)
return false; return false;
} }
bool DirectInputManager::UpdateInputState(DirectInputData &data) void DirectInputManager::UpdateInputState(DirectInputData &data)
{ {
DIJOYSTATE2 newState;
HRESULT hr; HRESULT hr;
data.stateValid = false;
// Poll the device to read the current state // Poll the device to read the current state
hr = data.joystick->Poll(); hr = data.joystick->Poll();
if(FAILED(hr)) { if(FAILED(hr)) {
@ -373,18 +372,19 @@ bool DirectInputManager::UpdateInputState(DirectInputData &data)
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This may occur when the app is minimized or in the process of // hr may be DIERR_OTHERAPPHASPRIO or other errors. This may occur when the app is minimized or in the process of
// switching, so just try again later // switching, so just try again later
if(FAILED(hr)) { if(FAILED(hr)) {
return true; data.stateValid = false;
return;
} }
} }
// Get the input's device state // Get the input's device state
if(FAILED(hr = data.joystick->GetDeviceState(sizeof(DIJOYSTATE2), &data.state))) { if(FAILED(hr = data.joystick->GetDeviceState(sizeof(DIJOYSTATE2), &newState))) {
return false; // The device should have been acquired during the Poll() data.stateValid = false;
return; // The device should have been acquired during the Poll()
} }
data.state = newState;
data.stateValid = true; data.stateValid = true;
return true;
} }

View file

@ -23,7 +23,7 @@ private:
static std::vector<GUID> _directInputDeviceGuids; static std::vector<GUID> _directInputDeviceGuids;
bool Initialize(); bool Initialize();
bool UpdateInputState(DirectInputData& joystick); void UpdateInputState(DirectInputData& joystick);
static bool ProcessDevice(const DIDEVICEINSTANCE* pdidInstance, bool checkOnly); static bool ProcessDevice(const DIDEVICEINSTANCE* pdidInstance, bool checkOnly);
static bool IsXInputDevice(const GUID* pGuidProductFromDirectInput); static bool IsXInputDevice(const GUID* pGuidProductFromDirectInput);
static int __stdcall NeedToUpdateCallback(const DIDEVICEINSTANCE* pdidInstance, void* pContext); static int __stdcall NeedToUpdateCallback(const DIDEVICEINSTANCE* pdidInstance, void* pContext);

View file

@ -5,17 +5,21 @@ XInputManager::XInputManager()
{ {
for(int i = 0; i < XUSER_MAX_COUNT; i++) { for(int i = 0; i < XUSER_MAX_COUNT; i++) {
_gamePadStates.push_back(shared_ptr<XINPUT_STATE>(new XINPUT_STATE())); _gamePadStates.push_back(shared_ptr<XINPUT_STATE>(new XINPUT_STATE()));
_gamePadConnected.push_back(true);
} }
} }
void XInputManager::RefreshState() void XInputManager::RefreshState()
{ {
XINPUT_STATE state;
for(DWORD i = 0; i < XUSER_MAX_COUNT; i++) { for(DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
if(_gamePadStates[i] != nullptr) { if(_gamePadConnected[i]) {
ZeroMemory(_gamePadStates[i].get(), sizeof(XINPUT_STATE)); if(XInputGetState(i, &state) != ERROR_SUCCESS) {
if(XInputGetState(i, _gamePadStates[i].get()) != ERROR_SUCCESS) {
//XInputGetState is incredibly slow when no controller is plugged in //XInputGetState is incredibly slow when no controller is plugged in
_gamePadStates[i] = nullptr; ZeroMemory(_gamePadStates[i].get(), sizeof(XINPUT_STATE));
_gamePadConnected[i] = false;
} else {
*_gamePadStates[i] = state;
} }
} }
} }
@ -23,9 +27,8 @@ void XInputManager::RefreshState()
bool XInputManager::NeedToUpdate() bool XInputManager::NeedToUpdate()
{ {
bool needToUpdate = false;
for(int i = 0; i < XUSER_MAX_COUNT; i++) { for(int i = 0; i < XUSER_MAX_COUNT; i++) {
if(_gamePadStates[i] == nullptr) { if(!_gamePadConnected[i]) {
XINPUT_STATE state; XINPUT_STATE state;
if(XInputGetState(i, &state) == ERROR_SUCCESS) { if(XInputGetState(i, &state) == ERROR_SUCCESS) {
return true; return true;
@ -39,15 +42,13 @@ void XInputManager::UpdateDeviceList()
{ {
//Periodically detect if a controller has been plugged in to allow controllers to be plugged in after the emu is started //Periodically detect if a controller has been plugged in to allow controllers to be plugged in after the emu is started
for(int i = 0; i < XUSER_MAX_COUNT; i++) { for(int i = 0; i < XUSER_MAX_COUNT; i++) {
if(_gamePadStates[i] == nullptr) { _gamePadConnected[i] = true;
_gamePadStates[i] = shared_ptr<XINPUT_STATE>(new XINPUT_STATE());
}
} }
} }
bool XInputManager::IsPressed(uint8_t gamepadPort, uint8_t button) bool XInputManager::IsPressed(uint8_t gamepadPort, uint8_t button)
{ {
if(_gamePadStates[gamepadPort] != nullptr) { if(_gamePadConnected[gamepadPort]) {
XINPUT_GAMEPAD &gamepad = _gamePadStates[gamepadPort]->Gamepad; XINPUT_GAMEPAD &gamepad = _gamePadStates[gamepadPort]->Gamepad;
if(button <= 16) { if(button <= 16) {
WORD xinputButton = 1 << (button - 1); WORD xinputButton = 1 << (button - 1);

View file

@ -7,6 +7,7 @@ class XInputManager
{ {
private: private:
vector<shared_ptr<XINPUT_STATE>> _gamePadStates; vector<shared_ptr<XINPUT_STATE>> _gamePadStates;
vector<uint8_t> _gamePadConnected;
public: public:
XInputManager(); XInputManager();