diff --git a/examples/GamepadPins/GamepadPins.ino b/examples/GamepadPins/GamepadPins.ino index 0c54539..649dd9f 100644 --- a/examples/GamepadPins/GamepadPins.ino +++ b/examples/GamepadPins/GamepadPins.ino @@ -28,6 +28,8 @@ * and all of the main buttons. * * * Joysticks should be your typical 10k dual potentiometers. + * To prevent random values caused by floating inputs, + joysticks are disabled by default. * * Triggers can be either analog (pots) or digital (buttons). * Set the 'TriggerButtons' variable to change between the two. * * Buttons use the internal pull-ups and should be connected @@ -187,12 +189,11 @@ void loop() { // White lie here... most generic joysticks are typically // inverted by default. If the "Invert" variable is false - // then we need to do this transformation. - if (InvertLeftYAxis == false) { - leftJoyY = ADC_Max - leftJoyY; - } + // then we'll take the opposite value with 'not' (!). + boolean invert = !InvertLeftYAxis; - XInput.setJoystick(JOY_LEFT, leftJoyX, leftJoyY); + XInput.setJoystickX(JOY_LEFT, leftJoyX); + XInput.setJoystickY(JOY_LEFT, leftJoyY, invert); } // Set right joystick @@ -200,11 +201,10 @@ void loop() { int rightJoyX = analogRead(Pin_RightJoyX); int rightJoyY = analogRead(Pin_RightJoyY); - if (InvertRightYAxis == false) { - rightJoyY = ADC_Max - rightJoyY; - } + boolean invert = !InvertRightYAxis; - XInput.setJoystick(JOY_RIGHT, rightJoyX, rightJoyY); + XInput.setJoystickX(JOY_RIGHT, rightJoyX); + XInput.setJoystickY(JOY_RIGHT, rightJoyY, invert); } // Send control data to the computer diff --git a/src/XInput.cpp b/src/XInput.cpp index d7cb97c..f0db0e6 100644 --- a/src/XInput.cpp +++ b/src/XInput.cpp @@ -277,11 +277,12 @@ void XInputController::setJoystick(XInputControl joy, int32_t x, int32_t y) { setJoystickDirect(joy, x, y); } -void XInputController::setJoystickX(XInputControl joy, int32_t x) { +void XInputController::setJoystickX(XInputControl joy, int32_t x, boolean invert) { const XInputMap_Joystick * joyData = getJoyFromEnum(joy); if (joyData == nullptr) return; // Not a joystick x = rescaleInput(x, *getRangeFromEnum(joy), XInputMap_Joystick::range); + if (invert) x = invertInput(x, XInputMap_Joystick::range); if (getJoystickX(joy) == x) return; // Axis hasn't changed @@ -292,11 +293,12 @@ void XInputController::setJoystickX(XInputControl joy, int32_t x) { autosend(); } -void XInputController::setJoystickY(XInputControl joy, int32_t y) { +void XInputController::setJoystickY(XInputControl joy, int32_t y, boolean invert) { const XInputMap_Joystick * joyData = getJoyFromEnum(joy); if (joyData == nullptr) return; // Not a joystick y = rescaleInput(y, *getRangeFromEnum(joy), XInputMap_Joystick::range); + if (invert) y = invertInput(y, XInputMap_Joystick::range); if (getJoystickY(joy) == y) return; // Axis hasn't changed @@ -341,15 +343,18 @@ void XInputController::setJoystickDirect(XInputControl joy, int16_t x, int16_t y const XInputMap_Joystick * joyData = getJoyFromEnum(joy); if (joyData == nullptr) return; // Not a joystick - if (getJoystickX(joy) == x && getJoystickY(joy) == y) return; // Joy hasn't changed - - tx[joyData->x_low] = lowByte(x); - tx[joyData->x_high] = highByte(x); + if (getJoystickX(joy) != x) { + tx[joyData->x_low] = lowByte(x); + tx[joyData->x_high] = highByte(x); + newData = true; + } - tx[joyData->y_low] = lowByte(y); - tx[joyData->y_high] = highByte(y); + if (getJoystickY(joy) != y) { + tx[joyData->y_low] = lowByte(y); + tx[joyData->y_high] = highByte(y); + newData = true; + } - newData = true; autosend(); } @@ -365,9 +370,15 @@ void XInputController::setAutoSend(boolean a) { } boolean XInputController::getButton(uint8_t button) const { - const XInputMap_Button * buttonData = getButtonFromEnum((XInputControl) button); - if (buttonData == nullptr) return 0; // Not a button - return tx[buttonData->index] & buttonData->mask; + const XInputMap_Button* buttonData = getButtonFromEnum((XInputControl) button); + if (buttonData != nullptr) { + return tx[buttonData->index] & buttonData->mask; + } + const XInputMap_Trigger* triggerData = getTriggerFromEnum((XInputControl) button); + if (triggerData != nullptr) { + return getTrigger((XInputControl) button) != 0 ? 1 : 0; + } + return 0; // Not a button or a trigger } boolean XInputController::getDpad(XInputControl dpad) const { @@ -427,8 +438,8 @@ boolean XInputController::connected() { //Send an update packet to the PC int XInputController::send() { if (!newData) return 0; // TX data hasn't changed -#ifdef USB_XINPUT newData = false; +#ifdef USB_XINPUT return XInputUSB::send(tx, sizeof(tx)); #else printDebug(); @@ -511,13 +522,17 @@ XInputController::Range * XInputController::getRangeFromEnum(XInputControl ctrl) } } -int32_t XInputController::rescaleInput(int32_t val, Range in, Range out) { +int32_t XInputController::rescaleInput(int32_t val, const Range& in, const Range& out) { if (val <= in.min) return out.min; // Out of range - if (val >= in.max) return out.max; // Out of range + if (in.min == out.min && in.max == out.max) return val; // Ranges identical return map(val, in.min, in.max, out.min, out.max); } +int16_t XInputController::invertInput(int16_t val, const Range& range) { + return range.max - val + range.min; +} + void XInputController::setTriggerRange(int32_t rangeMin, int32_t rangeMax) { setRange(TRIGGER_LEFT, rangeMin, rangeMax); setRange(TRIGGER_RIGHT, rangeMin, rangeMax); diff --git a/src/XInput.h b/src/XInput.h index 902fdd1..c0b8d96 100644 --- a/src/XInput.h +++ b/src/XInput.h @@ -86,14 +86,14 @@ class XInputController { void setButton(uint8_t button, boolean state); void setDpad(XInputControl pad, boolean state); - void setDpad(boolean up, boolean down, boolean left, boolean right, boolean useSOCD = true); + void setDpad(boolean up, boolean down, boolean left, boolean right, boolean useSOCD=true); void setTrigger(XInputControl trigger, int32_t val); void setJoystick(XInputControl joy, int32_t x, int32_t y); - void setJoystick(XInputControl joy, boolean up, boolean down, boolean left, boolean right, boolean useSOCD = true); - void setJoystickX(XInputControl joy, int32_t x); - void setJoystickY(XInputControl joy, int32_t y); + void setJoystick(XInputControl joy, boolean up, boolean down, boolean left, boolean right, boolean useSOCD=true); + void setJoystickX(XInputControl joy, int32_t x, boolean invert=false); + void setJoystickY(XInputControl joy, int32_t y, boolean invert=false); void releaseAll(); @@ -136,7 +136,7 @@ class XInputController { void reset(); // Debug - void printDebug(Print& output = Serial) const; + void printDebug(Print& output=Serial) const; private: // Sent Data @@ -161,7 +161,8 @@ class XInputController { // Control Input Ranges Range rangeTrigLeft, rangeTrigRight, rangeJoyLeft, rangeJoyRight; Range * getRangeFromEnum(XInputControl ctrl); - int32_t rescaleInput(int32_t val, Range in, Range out); + static int32_t rescaleInput(int32_t val, const Range& in, const Range &out); + static int16_t invertInput(int16_t val, const Range& range); }; extern XInputController XInput;