From 947f8c5bdd63d54a4fc833cab373bb087ae8a776 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 19 Feb 2017 15:02:17 +0100 Subject: [PATCH] Let multiple XInput devices be mapped separately. Fixes #8250 --- Windows/XinputDevice.cpp | 184 ++++++++++++++----------------- Windows/XinputDevice.h | 11 +- ext/native/input/input_state.cpp | 3 + ext/native/input/input_state.h | 3 + 4 files changed, 97 insertions(+), 104 deletions(-) diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index e600dbde3..faa125539 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -99,7 +99,6 @@ XinputDevice::XinputDevice() { if (LoadXInputDLL() != 0) { WARN_LOG(SCECTRL, "Failed to load XInput! DLL missing"); } - this->gamepad_idx = -1; } XinputDevice::~XinputDevice() { @@ -205,121 +204,108 @@ int XinputDevice::UpdateState(InputState &input_state) { if (!s_pXInputDLL) return 0; - if (this->check_delay-- > 0) - return -1; - - XINPUT_STATE state; - ZeroMemory( &state, sizeof(XINPUT_STATE) ); - - DWORD dwResult; - if (this->gamepad_idx >= 0) { - dwResult = PPSSPP_XInputGetState( this->gamepad_idx, &state ); - } else { - // use the first gamepad that responds - for (int i = 0; i < XUSER_MAX_COUNT; i++) { - dwResult = PPSSPP_XInputGetState( i, &state ); - if (dwResult == ERROR_SUCCESS) { - this->gamepad_idx = i; - break; - } + bool anySuccess = false; + for (int i = 0; i < XUSER_MAX_COUNT; i++) { + XINPUT_STATE state; + ZeroMemory(&state, sizeof(XINPUT_STATE)); + if (check_delay[i]-- > 0) + continue; + DWORD dwResult = PPSSPP_XInputGetState(i, &state); + if (dwResult == ERROR_SUCCESS) { + UpdatePad(i, state, input_state); + anySuccess = true; } } - - if ( dwResult == ERROR_SUCCESS ) { - static bool notified = false; - if (!notified) { - notified = true; - KeyMap::NotifyPadConnected("Xbox 360 Pad"); - } - ApplyButtons(state, input_state); - const float STICK_DEADZONE = g_Config.fXInputAnalogDeadzone; - const int STICK_INV_MODE = g_Config.iXInputAnalogInverseMode; - const float STICK_INV_DEADZONE = g_Config.fXInputAnalogInverseDeadzone; - const float STICK_SENSITIVITY = g_Config.fXInputAnalogSensitivity; - - if (NormalizedDeadzoneDiffers(prevState.Gamepad.sThumbLX, prevState.Gamepad.sThumbLY, state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, STICK_DEADZONE)) { - Stick left = NormalizedDeadzoneFilter(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, STICK_DEADZONE, STICK_INV_MODE, STICK_INV_DEADZONE, STICK_SENSITIVITY); - - AxisInput axis; - axis.deviceId = DEVICE_ID_X360_0; - axis.axisId = JOYSTICK_AXIS_X; - axis.value = left.x; - if (prevState.Gamepad.sThumbLX != state.Gamepad.sThumbLX) { - NativeAxis(axis); - } - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = left.y; - if (prevState.Gamepad.sThumbLY != state.Gamepad.sThumbLY) { - NativeAxis(axis); - } - } - - if (NormalizedDeadzoneDiffers(prevState.Gamepad.sThumbRX, prevState.Gamepad.sThumbRY, state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, STICK_DEADZONE)) { - Stick right = NormalizedDeadzoneFilter(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, STICK_DEADZONE, STICK_INV_MODE, STICK_INV_DEADZONE, STICK_SENSITIVITY); - - AxisInput axis; - axis.deviceId = DEVICE_ID_X360_0; - axis.axisId = JOYSTICK_AXIS_Z; - axis.value = right.x; - if (prevState.Gamepad.sThumbRX != state.Gamepad.sThumbRX) { - NativeAxis(axis); - } - axis.axisId = JOYSTICK_AXIS_RZ; - axis.value = right.y; - if (prevState.Gamepad.sThumbRY != state.Gamepad.sThumbRY) { - NativeAxis(axis); - } - } - - if (NormalizedDeadzoneDiffers(prevState.Gamepad.bLeftTrigger, state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) { - AxisInput axis; - axis.deviceId = DEVICE_ID_X360_0; - axis.axisId = JOYSTICK_AXIS_LTRIGGER; - axis.value = (float)state.Gamepad.bLeftTrigger / 255.0f; - NativeAxis(axis); - } - - if (NormalizedDeadzoneDiffers(prevState.Gamepad.bRightTrigger, state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) { - AxisInput axis; - axis.deviceId = DEVICE_ID_X360_0; - axis.axisId = JOYSTICK_AXIS_RTRIGGER; - axis.value = (float)state.Gamepad.bRightTrigger / 255.0f; - NativeAxis(axis); - } - - this->prevState = state; - this->check_delay = 0; - - // If there's an XInput pad, skip following pads. This prevents DInput and XInput - // from colliding. - return UPDATESTATE_SKIP_PAD; - } else { - // wait check_delay frames before polling the controller again - this->gamepad_idx = -1; - this->check_delay = 100; - return -1; - } + // If we get XInput, skip the others. This might not actually be a good idea. + return anySuccess ? UPDATESTATE_SKIP_PAD : 0; } -void XinputDevice::ApplyButtons(XINPUT_STATE &state, InputState &input_state) { +void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, InputState &input_state) { + static bool notified = false; + if (!notified) { + notified = true; + KeyMap::NotifyPadConnected("Xbox 360 Pad"); + } + ApplyButtons(pad, state, input_state); + + const float STICK_DEADZONE = g_Config.fXInputAnalogDeadzone; + const int STICK_INV_MODE = g_Config.iXInputAnalogInverseMode; + const float STICK_INV_DEADZONE = g_Config.fXInputAnalogInverseDeadzone; + const float STICK_SENSITIVITY = g_Config.fXInputAnalogSensitivity; + + if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.sThumbLX, prevState[pad].Gamepad.sThumbLY, state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, STICK_DEADZONE)) { + Stick left = NormalizedDeadzoneFilter(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, STICK_DEADZONE, STICK_INV_MODE, STICK_INV_DEADZONE, STICK_SENSITIVITY); + + AxisInput axis; + axis.deviceId = DEVICE_ID_X360_0 + pad; + axis.axisId = JOYSTICK_AXIS_X; + axis.value = left.x; + if (prevState[pad].Gamepad.sThumbLX != state.Gamepad.sThumbLX) { + NativeAxis(axis); + } + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = left.y; + if (prevState[pad].Gamepad.sThumbLY != state.Gamepad.sThumbLY) { + NativeAxis(axis); + } + } + + if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.sThumbRX, prevState[pad].Gamepad.sThumbRY, state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, STICK_DEADZONE)) { + Stick right = NormalizedDeadzoneFilter(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, STICK_DEADZONE, STICK_INV_MODE, STICK_INV_DEADZONE, STICK_SENSITIVITY); + + AxisInput axis; + axis.deviceId = DEVICE_ID_X360_0 + pad; + axis.axisId = JOYSTICK_AXIS_Z; + axis.value = right.x; + if (prevState[pad].Gamepad.sThumbRX != state.Gamepad.sThumbRX) { + NativeAxis(axis); + } + axis.axisId = JOYSTICK_AXIS_RZ; + axis.value = right.y; + if (prevState[pad].Gamepad.sThumbRY != state.Gamepad.sThumbRY) { + NativeAxis(axis); + } + } + + if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.bLeftTrigger, state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) { + AxisInput axis; + axis.deviceId = DEVICE_ID_X360_0 + pad; + axis.axisId = JOYSTICK_AXIS_LTRIGGER; + axis.value = (float)state.Gamepad.bLeftTrigger / 255.0f; + NativeAxis(axis); + } + + if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.bRightTrigger, state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) { + AxisInput axis; + axis.deviceId = DEVICE_ID_X360_0 + pad; + axis.axisId = JOYSTICK_AXIS_RTRIGGER; + axis.value = (float)state.Gamepad.bRightTrigger / 255.0f; + NativeAxis(axis); + } + + this->prevState[pad] = state; + this->check_delay[pad] = 0; +} + +void XinputDevice::ApplyButtons(int pad, const XINPUT_STATE &state, InputState &input_state) { u32 buttons = state.Gamepad.wButtons; - u32 downMask = buttons & (~prevButtons); - u32 upMask = (~buttons) & prevButtons; - prevButtons = buttons; + u32 downMask = buttons & (~prevButtons[pad]); + u32 upMask = (~buttons) & prevButtons[pad]; + prevButtons[pad] = buttons; for (int i = 0; i < xinput_ctrl_map_size; i++) { if (downMask & xinput_ctrl_map[i].from) { KeyInput key; - key.deviceId = DEVICE_ID_X360_0; + key.deviceId = DEVICE_ID_X360_0 + pad; key.flags = KEY_DOWN; key.keyCode = xinput_ctrl_map[i].to; NativeKey(key); } if (upMask & xinput_ctrl_map[i].from) { KeyInput key; - key.deviceId = DEVICE_ID_X360_0; + key.deviceId = DEVICE_ID_X360_0 + pad; key.flags = KEY_UP; key.keyCode = xinput_ctrl_map[i].to; NativeKey(key); diff --git a/Windows/XinputDevice.h b/Windows/XinputDevice.h index 6428b472c..037c2ded3 100644 --- a/Windows/XinputDevice.h +++ b/Windows/XinputDevice.h @@ -10,10 +10,11 @@ public: ~XinputDevice(); virtual int UpdateState(InputState &input_state); virtual bool IsPad() { return true; } + private: - void ApplyButtons(XINPUT_STATE &state, InputState &input_state); - int gamepad_idx; - int check_delay = 0; - XINPUT_STATE prevState{}; - u32 prevButtons = 0; + void UpdatePad(int pad, const XINPUT_STATE &state, InputState &input_state); + void ApplyButtons(int pad, const XINPUT_STATE &state, InputState &input_state); + int check_delay[4]{}; + XINPUT_STATE prevState[4]{}; + u32 prevButtons[4]{}; }; \ No newline at end of file diff --git a/ext/native/input/input_state.cpp b/ext/native/input/input_state.cpp index c6923d338..bf4b867fc 100644 --- a/ext/native/input/input_state.cpp +++ b/ext/native/input/input_state.cpp @@ -18,6 +18,9 @@ const char *GetDeviceName(int deviceId) { case DEVICE_ID_PAD_8: return "pad9"; case DEVICE_ID_PAD_9: return "pad10"; case DEVICE_ID_X360_0: return "x360"; + case DEVICE_ID_X360_1: return "x360_2"; + case DEVICE_ID_X360_2: return "x360_3"; + case DEVICE_ID_X360_3: return "x360_4"; case DEVICE_ID_ACCELEROMETER: return "accelerometer"; case DEVICE_ID_MOUSE: return "mouse"; default: diff --git a/ext/native/input/input_state.h b/ext/native/input/input_state.h index da35b3693..a63eecae4 100644 --- a/ext/native/input/input_state.h +++ b/ext/native/input/input_state.h @@ -34,6 +34,9 @@ enum { DEVICE_ID_PAD_8 = 18, DEVICE_ID_PAD_9 = 19, DEVICE_ID_X360_0 = 20, // XInput joypads + DEVICE_ID_X360_1 = 21, + DEVICE_ID_X360_2 = 22, + DEVICE_ID_X360_3 = 23, DEVICE_ID_ACCELEROMETER = 30, };