Skip to content

Commit

Permalink
Let multiple XInput devices be mapped separately. Fixes #8250
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Feb 19, 2017
1 parent b14e106 commit 947f8c5
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 93 deletions.
162 changes: 74 additions & 88 deletions Windows/XinputDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ XinputDevice::XinputDevice() {
if (LoadXInputDLL() != 0) {
WARN_LOG(SCECTRL, "Failed to load XInput! DLL missing");
}
this->gamepad_idx = -1;
}

XinputDevice::~XinputDevice() {
Expand Down Expand Up @@ -205,121 +204,108 @@ int XinputDevice::UpdateState(InputState &input_state) {
if (!s_pXInputDLL)
return 0;

if (this->check_delay-- > 0)
return -1;
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;
}
}

XINPUT_STATE state;
ZeroMemory( &state, sizeof(XINPUT_STATE) );
// If we get XInput, skip the others. This might not actually be a good idea.
return anySuccess ? UPDATESTATE_SKIP_PAD : 0;
}

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;
}
}
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");
}

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);
}
}
ApplyButtons(pad, state, input_state);

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);
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;

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[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);

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;
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);

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;
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);
}
}

this->prevState = state;
this->check_delay = 0;
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 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 (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(XINPUT_STATE &state, InputState &input_state) {
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);
Expand Down
11 changes: 6 additions & 5 deletions Windows/XinputDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ class XinputDevice : public InputDevice {
~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]{};
};
3 changes: 3 additions & 0 deletions ext/native/input/input_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions ext/native/input/input_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down

0 comments on commit 947f8c5

Please sign in to comment.