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;
}
bool DirectInputManager::UpdateInputState(DirectInputData &data)
void DirectInputManager::UpdateInputState(DirectInputData &data)
{
DIJOYSTATE2 newState;
HRESULT hr;
data.stateValid = false;
// Poll the device to read the current state
hr = data.joystick->Poll();
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
// switching, so just try again later
if(FAILED(hr)) {
return true;
data.stateValid = false;
return;
}
}
// Get the input's device state
if(FAILED(hr = data.joystick->GetDeviceState(sizeof(DIJOYSTATE2), &data.state))) {
return false; // The device should have been acquired during the Poll()
if(FAILED(hr = data.joystick->GetDeviceState(sizeof(DIJOYSTATE2), &newState))) {
data.stateValid = false;
return; // The device should have been acquired during the Poll()
}
data.state = newState;
data.stateValid = true;
return true;
}

View file

@ -23,7 +23,7 @@ private:
static std::vector<GUID> _directInputDeviceGuids;
bool Initialize();
bool UpdateInputState(DirectInputData& joystick);
void UpdateInputState(DirectInputData& joystick);
static bool ProcessDevice(const DIDEVICEINSTANCE* pdidInstance, bool checkOnly);
static bool IsXInputDevice(const GUID* pGuidProductFromDirectInput);
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++) {
_gamePadStates.push_back(shared_ptr<XINPUT_STATE>(new XINPUT_STATE()));
_gamePadConnected.push_back(true);
}
}
void XInputManager::RefreshState()
{
XINPUT_STATE state;
for(DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
if(_gamePadStates[i] != nullptr) {
ZeroMemory(_gamePadStates[i].get(), sizeof(XINPUT_STATE));
if(XInputGetState(i, _gamePadStates[i].get()) != ERROR_SUCCESS) {
if(_gamePadConnected[i]) {
if(XInputGetState(i, &state) != ERROR_SUCCESS) {
//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 needToUpdate = false;
for(int i = 0; i < XUSER_MAX_COUNT; i++) {
if(_gamePadStates[i] == nullptr) {
if(!_gamePadConnected[i]) {
XINPUT_STATE state;
if(XInputGetState(i, &state) == ERROR_SUCCESS) {
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
for(int i = 0; i < XUSER_MAX_COUNT; i++) {
if(_gamePadStates[i] == nullptr) {
_gamePadStates[i] = shared_ptr<XINPUT_STATE>(new XINPUT_STATE());
}
_gamePadConnected[i] = true;
}
}
bool XInputManager::IsPressed(uint8_t gamepadPort, uint8_t button)
{
if(_gamePadStates[gamepadPort] != nullptr) {
if(_gamePadConnected[gamepadPort]) {
XINPUT_GAMEPAD &gamepad = _gamePadStates[gamepadPort]->Gamepad;
if(button <= 16) {
WORD xinputButton = 1 << (button - 1);

View file

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