Skip to content

Commit 6c12e20

Browse files
committed
Rescale joystick and trigger values by user range
1 parent d59fc17 commit 6c12e20

2 files changed

Lines changed: 84 additions & 6 deletions

File tree

src/XInput.cpp

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include "XInput.h"
28+
#include <limits>
2829

2930
// --------------------------------------------------------
3031
// XInput Button Maps |
@@ -89,9 +90,15 @@ constexpr const XInputMap_Button * getButtonFromEnum(XInputControl ctrl) {
8990
struct XInputMap_Trigger {
9091
constexpr XInputMap_Trigger(uint8_t i)
9192
: index(i) {}
93+
static const XInputGamepad::Range range;
9294
const uint8_t index;
9395
};
9496

97+
const XInputGamepad::Range XInputMap_Trigger::range = {
98+
std::numeric_limits<uint8_t>::min(), // 0
99+
std::numeric_limits<uint8_t>::max() // 255
100+
};
101+
95102
static const XInputMap_Trigger Map_TriggerLeft(4);
96103
static const XInputMap_Trigger Map_TriggerRight(5);
97104

@@ -111,12 +118,18 @@ constexpr const XInputMap_Trigger * getTriggerFromEnum(XInputControl ctrl) {
111118
struct XInputMap_Joystick {
112119
constexpr XInputMap_Joystick(uint8_t xl, uint8_t xh, uint8_t yl, uint8_t yh)
113120
: x_low(xl), x_high(xh), y_low(yl), y_high(yh) {}
121+
static const XInputGamepad::Range range;
114122
const uint8_t x_low;
115123
const uint8_t x_high;
116124
const uint8_t y_low;
117125
const uint8_t y_high;
118126
};
119127

128+
const XInputGamepad::Range XInputMap_Joystick::range = {
129+
std::numeric_limits<int16_t>::min(), // -32768
130+
std::numeric_limits<int16_t>::max() // 32767
131+
};
132+
120133
static const XInputMap_Joystick Map_JoystickLeft(6, 7, 8, 9);
121134
static const XInputMap_Joystick Map_JoystickRight(10, 11, 12, 13);
122135

@@ -169,7 +182,9 @@ void XInputGamepad::setButton(XInputControl button, boolean state) {
169182
else { tx[buttonData->index] &= ~(buttonData->mask); } // Release
170183
}
171184
else {
172-
setTrigger(button, state ? 255 : 0); // Treat trigger like a button
185+
Range * triggerRange = getRangeFromEnum(button);
186+
if (triggerRange == nullptr) return; // Not a trigger (or joystick, but the trigger function will ignore that)
187+
setTrigger(button, state ? triggerRange->max : triggerRange->min); // Treat trigger like a button
173188
}
174189
}
175190

@@ -188,16 +203,20 @@ void XInputGamepad::setDpad(boolean up, boolean down, boolean left, boolean righ
188203
setDpad(DPAD_RIGHT, right);
189204
}
190205

191-
void XInputGamepad::setTrigger(XInputControl trigger, uint8_t val) {
206+
void XInputGamepad::setTrigger(XInputControl trigger, int32_t val) {
192207
const XInputMap_Trigger * triggerData = getTriggerFromEnum(trigger);
193208
if (triggerData == nullptr) return; // Not a trigger
209+
val = rescaleInput(val, *getRangeFromEnum(trigger), triggerData->range);
194210
tx[triggerData->index] = val;
195211
}
196212

197-
void XInputGamepad::setJoystick(XInputControl joy, int16_t x, int16_t y) {
213+
void XInputGamepad::setJoystick(XInputControl joy, int32_t x, int32_t y) {
198214
const XInputMap_Joystick * joyData = getJoyFromEnum(joy);
199215
if (joyData == nullptr) return; // Not a joystick
200216

217+
x = rescaleInput(x, *getRangeFromEnum(joy), joyData->range);
218+
y = rescaleInput(y, *getRangeFromEnum(joy), joyData->range);
219+
201220
tx[joyData->x_low] = lowByte(x);
202221
tx[joyData->x_high] = highByte(x);
203222

@@ -283,15 +302,58 @@ void XInputGamepad::parseLED(uint8_t leds) {
283302
}
284303
}
285304

305+
XInputGamepad::Range * XInputGamepad::getRangeFromEnum(XInputControl ctrl) {
306+
switch (ctrl) {
307+
case(TRIGGER_LEFT): return &rangeTrigLeft;
308+
case(TRIGGER_RIGHT): return &rangeTrigRight;
309+
case(JOY_LEFT): return &rangeJoyLeft;
310+
case(JOY_RIGHT): return &rangeJoyRight;
311+
default: return nullptr;
312+
}
313+
}
314+
315+
int32_t XInputGamepad::rescaleInput(int32_t val, Range in, Range out) {
316+
if (in.min == out.min && in.max == out.max) return val; // Ranges identical
317+
if (val <= in.min) return out.min; // Out of range -
318+
if (val >= in.max) return out.max; // Out of range +
319+
return map(val, in.min, in.max, out.min, out.max);
320+
}
321+
322+
void XInputGamepad::setTriggerRange(int32_t rangeMin, int32_t rangeMax) {
323+
setRange(TRIGGER_LEFT, rangeMin, rangeMax);
324+
setRange(TRIGGER_RIGHT, rangeMin, rangeMax);
325+
}
326+
327+
void XInputGamepad::setJoystickRange(int32_t rangeMin, int32_t rangeMax) {
328+
setRange(JOY_LEFT, rangeMin, rangeMax);
329+
setRange(JOY_RIGHT, rangeMin, rangeMax);
330+
}
331+
332+
void XInputGamepad::setRange(XInputControl ctrl, int32_t rangeMin, int32_t rangeMax) {
333+
if (rangeMin >= rangeMax) return; // Error: Max < Min
334+
335+
Range * range = getRangeFromEnum(ctrl);
336+
if (range == nullptr) return; // Not an addressable range
337+
338+
range->min = rangeMin;
339+
range->max = rangeMax;
340+
}
341+
286342
// Resets class back to initial values
287343
void XInputGamepad::reset() {
344+
// Reset control data (tx)
288345
releaseAll(); // Clear TX buffer
289346
tx[0] = 0x00; // Set tx message type
290347
tx[1] = 0x14; // Set tx packet size (20)
291348

349+
// Reset received data (rx)
292350
player = 0; // Not connected, no player
293351
memset(rumble, 0x00, sizeof(rumble)); // Clear rumble values
294352
ledPattern = XInputLEDPattern::Off; // No LEDs on
353+
354+
// Reset rescale ranges
355+
setTriggerRange(XInputMap_Trigger::range.min, XInputMap_Trigger::range.max);
356+
setJoystickRange(XInputMap_Joystick::range.min, XInputMap_Joystick::range.max);
295357
}
296358

297359
XInputGamepad XInput;

src/XInput.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ class XInputGamepad {
8181
void setDpad(XInputControl pad, boolean state);
8282
void setDpad(boolean up, boolean down, boolean left, boolean right);
8383

84-
void setTrigger(XInputControl trigger, uint8_t val);
84+
void setTrigger(XInputControl trigger, int32_t val);
8585

86-
void setJoystick(XInputControl joy, int16_t x, int16_t y);
86+
void setJoystick(XInputControl joy, int32_t x, int32_t y);
8787

8888
void releaseAll();
8989

@@ -100,7 +100,14 @@ class XInputGamepad {
100100
void send();
101101
void receive();
102102

103-
// Other
103+
// Control Input Ranges
104+
struct Range { int32_t min; int32_t max; };
105+
106+
void setTriggerRange(int32_t rangeMin, int32_t rangeMax);
107+
void setJoystickRange(int32_t rangeMin, int32_t rangeMax);
108+
void setRange(XInputControl ctrl, int32_t rangeMin, int32_t rangeMax);
109+
110+
// Setup
104111
void reset();
105112

106113
private:
@@ -112,6 +119,15 @@ class XInputGamepad {
112119
XInputLEDPattern ledPattern; // LED pattern data in, buffered
113120

114121
void parseLED(uint8_t leds); // Parse LED data and set pattern/player data
122+
123+
// Control Input Ranges
124+
Range rangeTrigLeft;
125+
Range rangeTrigRight;
126+
Range rangeJoyLeft;
127+
Range rangeJoyRight;
128+
129+
Range * getRangeFromEnum(XInputControl ctrl);
130+
int32_t rescaleInput(int32_t val, Range in, Range out);
115131
};
116132

117133
extern XInputGamepad XInput;

0 commit comments

Comments
 (0)