From 7e0aa6b4e1719730e165fe7f883dad75b062a72e Mon Sep 17 00:00:00 2001 From: David Madison Date: Fri, 8 Jan 2021 23:04:08 -0500 Subject: [PATCH 1/8] Separate X and Y for setJoystickDirect Minor change, but prevents rewriting both axes if only one changes --- src/XInput.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/XInput.cpp b/src/XInput.cpp index d7cb97c..36b03ef 100644 --- a/src/XInput.cpp +++ b/src/XInput.cpp @@ -341,15 +341,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(); } From 1bc01233dac1dc76280c17432b7f3246ea427f27 Mon Sep 17 00:00:00 2001 From: David Madison Date: Fri, 8 Jan 2021 23:15:11 -0500 Subject: [PATCH 2/8] Fix whitespace formatting of default parameters --- src/XInput.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/XInput.h b/src/XInput.h index 902fdd1..48b11bb 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 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 From 867a1eb3d680d5ad16f895e740bda25c71b57c78 Mon Sep 17 00:00:00 2001 From: David Madison Date: Fri, 8 Jan 2021 23:24:43 -0500 Subject: [PATCH 3/8] Change rescaleInput function definition Makes the function static and changes both Range arguments to pass by const reference rather than copy, as the function does not need to (and shouldn't!) modify the input ranges. --- src/XInput.cpp | 2 +- src/XInput.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/XInput.cpp b/src/XInput.cpp index 36b03ef..27a3120 100644 --- a/src/XInput.cpp +++ b/src/XInput.cpp @@ -514,7 +514,7 @@ 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 diff --git a/src/XInput.h b/src/XInput.h index 48b11bb..0035844 100644 --- a/src/XInput.h +++ b/src/XInput.h @@ -161,7 +161,7 @@ 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); }; extern XInputController XInput; From 8c943ada043d3619dae07305a13fbdcb32745e9b Mon Sep 17 00:00:00 2001 From: David Madison Date: Fri, 8 Jan 2021 23:43:58 -0500 Subject: [PATCH 4/8] Add inversion option for joystick axes Note that the 'invert' helper function returns int16_t instead of int32_t because it's used *after* the long value rescaling, and the max value used by the output data is int16 --- src/XInput.cpp | 10 ++++++++-- src/XInput.h | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/XInput.cpp b/src/XInput.cpp index 27a3120..68da925 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 @@ -521,6 +523,10 @@ int32_t XInputController::rescaleInput(int32_t val, const Range& in, const Range 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 0035844..426eff8 100644 --- a/src/XInput.h +++ b/src/XInput.h @@ -91,8 +91,8 @@ class XInputController { void setTrigger(XInputControl trigger, int32_t val); void setJoystick(XInputControl joy, int32_t x, int32_t y); - void setJoystickX(XInputControl joy, int32_t x); - void setJoystickY(XInputControl joy, int32_t y); + void setJoystickX(XInputControl joy, int32_t x, boolean invert=false); + void setJoystickY(XInputControl joy, int32_t y, boolean invert=false); void setJoystick(XInputControl joy, boolean up, boolean down, boolean left, boolean right, boolean useSOCD=true); void releaseAll(); @@ -162,6 +162,7 @@ class XInputController { Range rangeTrigLeft, rangeTrigRight, rangeJoyLeft, rangeJoyRight; Range * getRangeFromEnum(XInputControl ctrl); 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; From 3950120fe8d671a05eaf3eb381d4cf1ad0b1e652 Mon Sep 17 00:00:00 2001 From: David Madison Date: Sun, 10 Jan 2021 06:29:15 -0500 Subject: [PATCH 5/8] Add triggers to 'getButton' function These can already be treated as digital by the 'set' function, so we should be able to treat them as digital with the 'get' function as well. Any input greater than 0 is considered 'pressed' - other thresholds can be done by the user with the analog function. --- src/XInput.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/XInput.cpp b/src/XInput.cpp index 68da925..83f5487 100644 --- a/src/XInput.cpp +++ b/src/XInput.cpp @@ -370,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 { From 98c8cd8ff7f1d1a50f365891e82f7c9f1226e692 Mon Sep 17 00:00:00 2001 From: David Madison Date: Sun, 10 Jan 2021 06:33:51 -0500 Subject: [PATCH 6/8] Only print new data on debug send This makes it easier to follow changes to the debug data stream and helps debug the changing state of 'newData' itself. --- src/XInput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XInput.cpp b/src/XInput.cpp index 83f5487..f0db0e6 100644 --- a/src/XInput.cpp +++ b/src/XInput.cpp @@ -438,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(); From 35c1739b0613ed2d136df3cb2cced1012a1953dd Mon Sep 17 00:00:00 2001 From: David Madison Date: Sun, 10 Jan 2021 06:49:14 -0500 Subject: [PATCH 7/8] Update GamepadPins example with joystick invert In place of calculating this "manually" with the ADC value --- examples/GamepadPins/GamepadPins.ino | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 From 5d205ce775b780273b5542163ef2abb1f5cf1df4 Mon Sep 17 00:00:00 2001 From: David Madison Date: Sun, 10 Jan 2021 07:50:42 -0500 Subject: [PATCH 8/8] Reorder joystick functions in header Oops. In 1bc0123 I accidentally reordered these while git adding a patch. Changing back to keep the axes-specific functions separate from the "joystick as a whole" functions. [skip ci] --- src/XInput.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XInput.h b/src/XInput.h index 426eff8..c0b8d96 100644 --- a/src/XInput.h +++ b/src/XInput.h @@ -91,9 +91,9 @@ class XInputController { 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, boolean invert=false); void setJoystickY(XInputControl joy, int32_t y, boolean invert=false); - void setJoystick(XInputControl joy, boolean up, boolean down, boolean left, boolean right, boolean useSOCD=true); void releaseAll();