Skip to content

Commit 633a6f6

Browse files
gyf304hrydgard
authored andcommitted
Refactor and unify analog input settings
1 parent c96692f commit 633a6f6

File tree

9 files changed

+102
-214
lines changed

9 files changed

+102
-214
lines changed

Core/Config.cpp

+5-12
Original file line numberDiff line numberDiff line change
@@ -962,18 +962,11 @@ static ConfigSetting controlSettings[] = {
962962
ConfigSetting("AnalogRotationCWKeyX", "AnalogRotationKeyCWY", "AnalogRotationKeyCWScale", "ShowAnalogRotationCWKey", &g_Config.touchAnalogRotationCWKey, defaultTouchPosHide, true, true),
963963
ConfigSetting("AnalogRotationCCWKeyX", "AnalogRotationKeyCCWY", "AnalogRotationKeyCCWScale", "ShowAnalogRotationCCWKey", &g_Config.touchAnalogRotationCCWKey, defaultTouchPosHide, true, true),
964964

965-
#ifdef _WIN32
966-
ConfigSetting("DInputAnalogDeadzone", &g_Config.fDInputAnalogDeadzone, 0.1f, true, true),
967-
ConfigSetting("DInputAnalogInverseMode", &g_Config.iDInputAnalogInverseMode, 0, true, true),
968-
ConfigSetting("DInputAnalogInverseDeadzone", &g_Config.fDInputAnalogInverseDeadzone, 0.0f, true, true),
969-
ConfigSetting("DInputAnalogSensitivity", &g_Config.fDInputAnalogSensitivity, 1.0f, true, true),
970-
971-
ConfigSetting("XInputAnalogDeadzone", &g_Config.fXInputAnalogDeadzone, 0.24f, true, true),
972-
ConfigSetting("XInputAnalogInverseMode", &g_Config.iXInputAnalogInverseMode, 0, true, true),
973-
ConfigSetting("XInputAnalogInverseDeadzone", &g_Config.fXInputAnalogInverseDeadzone, 0.0f, true, true),
974-
#endif
975-
// Also reused as generic analog sensitivity
976-
ConfigSetting("XInputAnalogSensitivity", &g_Config.fXInputAnalogSensitivity, 1.0f, true, true),
965+
ConfigSetting("AnalogDeadzone", &g_Config.fAnalogDeadzone, 0.0f, true, true),
966+
ConfigSetting("AnalogInverseDeadzone", &g_Config.fAnalogInverseDeadzone, 0.0f, true, true),
967+
ConfigSetting("AnalogSensitivity", &g_Config.fAnalogSensitivity, 1.0f, true, true),
968+
ConfigSetting("AnalogIsCircular", &g_Config.bAnalogIsCircular, true, true, true),
969+
977970
ConfigSetting("AnalogLimiterDeadzone", &g_Config.fAnalogLimiterDeadzone, 0.6f, true, true),
978971

979972
ConfigSetting("UseMouse", &g_Config.bMouseControl, false, true, true),

Core/Config.h

+6-9
Original file line numberDiff line numberDiff line change
@@ -381,16 +381,13 @@ struct Config {
381381

382382
bool bHapticFeedback;
383383

384-
float fDInputAnalogDeadzone;
385-
int iDInputAnalogInverseMode;
386-
float fDInputAnalogInverseDeadzone;
387-
float fDInputAnalogSensitivity;
388-
389384
// We also use the XInput settings as analog settings on other platforms like Android.
390-
float fXInputAnalogDeadzone;
391-
int iXInputAnalogInverseMode;
392-
float fXInputAnalogInverseDeadzone;
393-
float fXInputAnalogSensitivity;
385+
float fAnalogDeadzone;
386+
float fAnalogInverseDeadzone;
387+
float fAnalogSensitivity;
388+
// convert analog stick circle to square
389+
bool bAnalogIsCircular;
390+
394391

395392
float fAnalogLimiterDeadzone;
396393

SDL/SDLJoystick.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,7 @@ void SDLJoystick::ProcessInput(SDL_Event &event){
174174
case SDL_CONTROLLERAXISMOTION:
175175
AxisInput axis;
176176
axis.axisId = event.caxis.axis;
177-
// 1.2 to try to approximate the PSP's clamped rectangular range.
178-
axis.value = 1.2 * event.caxis.value * g_Config.fXInputAnalogSensitivity / 32767.0f;
177+
axis.value = event.caxis.value / 32767.0f;
179178
if (axis.value > 1.0f) axis.value = 1.0f;
180179
if (axis.value < -1.0f) axis.value = -1.0f;
181180
axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which);

UI/GameSettingsScreen.cpp

+6-17
Original file line numberDiff line numberDiff line change
@@ -727,23 +727,12 @@ void GameSettingsScreen::CreateViews() {
727727
style->SetEnabledPtr(&g_Config.bShowTouchControls);
728728
}
729729

730-
#ifdef _WIN32
731-
static const char *inverseDeadzoneModes[] = { "Off", "X", "Y", "X + Y" };
732-
733-
controlsSettings->Add(new ItemHeader(co->T("DInput Analog Settings", "DInput Analog Settings")));
734-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fDInputAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
735-
controlsSettings->Add(new PopupMultiChoice(&g_Config.iDInputAnalogInverseMode, co->T("Analog Mapper Mode"), inverseDeadzoneModes, 0, ARRAY_SIZE(inverseDeadzoneModes), co->GetName(), screenManager()));
736-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fDInputAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
737-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fDInputAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
738-
739-
controlsSettings->Add(new ItemHeader(co->T("XInput Analog Settings", "XInput Analog Settings")));
740-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
741-
controlsSettings->Add(new PopupMultiChoice(&g_Config.iXInputAnalogInverseMode, co->T("Analog Mapper Mode"), inverseDeadzoneModes, 0, ARRAY_SIZE(inverseDeadzoneModes), co->GetName(), screenManager()));
742-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
743-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
744-
#else
745-
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Axis Sensitivity", "Analog Axis Sensitivity"), 0.01f, screenManager(), "x"));
746-
#endif
730+
controlsSettings->Add(new ItemHeader(co->T("Analog Settings", "Analog Settings")));
731+
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
732+
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
733+
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
734+
controlsSettings->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular Analog Stick Input")));
735+
747736
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAutoRotSpeed, 0.0f, 25.0f, co->T("Analog auto-rotation speed"), 1.0f, screenManager()));
748737

749738
controlsSettings->Add(new ItemHeader(co->T("Keyboard", "Keyboard Control Settings")));

UI/NativeApp.cpp

+75
Original file line numberDiff line numberDiff line change
@@ -1326,9 +1326,84 @@ bool NativeKey(const KeyInput &key) {
13261326
return retval;
13271327
}
13281328

1329+
static float MapAxisValue(float v) {
1330+
const float deadzone = g_Config.fAnalogDeadzone;
1331+
const float invDeadzone = g_Config.fAnalogInverseDeadzone;
1332+
const float sensitivity = g_Config.fAnalogSensitivity;
1333+
const float sign = v >= 0.0f ? 1.0f : -1.0f;
1334+
return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f);
1335+
}
1336+
1337+
static void ConvertAnalogStick(float &x, float &y) {
1338+
const bool isCircular = g_Config.bAnalogIsCircular;
1339+
1340+
float norm = std::max(fabsf(x), fabsf(y));
1341+
1342+
if (norm == 0.0f)
1343+
return;
1344+
1345+
if (isCircular) {
1346+
float newNorm = sqrtf(x * x + y * y);
1347+
float factor = newNorm / norm;
1348+
x *= factor;
1349+
y *= factor;
1350+
norm = newNorm;
1351+
}
1352+
1353+
float mappedNorm = MapAxisValue(norm);
1354+
x = Clamp(x / norm * mappedNorm, -1.0f, 1.0f);
1355+
y = Clamp(y / norm * mappedNorm, -1.0f, 1.0f);
1356+
}
1357+
1358+
static bool AnalogStickAxis(const AxisInput &axis) {
1359+
static float history[JOYSTICK_AXIS_MAX+1] = { 0.0f };
1360+
1361+
if (history[axis.axisId] == axis.value) {
1362+
return true;
1363+
}
1364+
1365+
history[axis.axisId] = axis.value;
1366+
AxisInput axisA = axis;
1367+
AxisInput axisB = axis;
1368+
1369+
switch (axis.axisId) {
1370+
case JOYSTICK_AXIS_X:
1371+
case JOYSTICK_AXIS_Y:
1372+
axisA.axisId = JOYSTICK_AXIS_X;
1373+
axisB.axisId = JOYSTICK_AXIS_Y;
1374+
axisA.value = history[JOYSTICK_AXIS_X];
1375+
axisB.value = history[JOYSTICK_AXIS_Y];
1376+
break;
1377+
case JOYSTICK_AXIS_Z:
1378+
case JOYSTICK_AXIS_RZ:
1379+
axisA.axisId = JOYSTICK_AXIS_Z;
1380+
axisB.axisId = JOYSTICK_AXIS_RZ;
1381+
axisA.value = history[JOYSTICK_AXIS_Z];
1382+
axisB.value = history[JOYSTICK_AXIS_RZ];
1383+
break;
1384+
default:
1385+
break;
1386+
}
1387+
1388+
ConvertAnalogStick(axisA.value, axisB.value);
1389+
bool retA = screenManager->axis(axisA);
1390+
bool retB = screenManager->axis(axisB);
1391+
return retA && retB;
1392+
}
1393+
13291394
bool NativeAxis(const AxisInput &axis) {
13301395
using namespace TiltEventProcessor;
13311396

1397+
switch (axis.axisId) {
1398+
case JOYSTICK_AXIS_X:
1399+
case JOYSTICK_AXIS_Y:
1400+
case JOYSTICK_AXIS_Z:
1401+
case JOYSTICK_AXIS_RZ:
1402+
return AnalogStickAxis(axis);
1403+
default:
1404+
break;
1405+
}
1406+
13321407
// only handle tilt events if tilt is enabled.
13331408
if (g_Config.iTiltInputType == TILT_NULL) {
13341409
// if tilt events are disabled, then run it through the usual way.

Windows/DinputDevice.cpp

+1-67
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ DinputDevice::DinputDevice(int devnum) {
176176
dipw.diph.dwHow = DIPH_DEVICE;
177177
dipw.diph.dwObj = 0;
178178
// dwData 10000 is deadzone(0% - 100%), multiply by config scalar
179-
dipw.dwData = (int)(g_Config.fDInputAnalogDeadzone * 10000);
179+
dipw.dwData = 0;
180180

181181
analog |= FAILED(pJoystick->SetProperty(DIPROP_DEADZONE, &dipw.diph)) ? false : true;
182182
}
@@ -209,60 +209,6 @@ void SendNativeAxis(int deviceId, int value, int &lastValue, int axisId) {
209209
lastValue = value;
210210
}
211211

212-
inline int Signs(int val) {
213-
return (0 < val) - (val < 0);
214-
}
215-
216-
inline int LinearMaps(int val, int a0, int a1, int b0, int b1) {
217-
return b0 + (((val - a0) * (b1 - b0)) / (a1 - a0));
218-
}
219-
inline float LinearMaps(float val, float a0, float a1, float b0, float b1) {
220-
return b0 + (((val - a0) * (b1 - b0)) / (a1 - a0));
221-
}
222-
223-
static void ApplyNormalization(LONG &jsx, LONG &jsy) {
224-
// Circle to Square mapping, cribbed from XInputDevice
225-
float sx = (float)jsx;
226-
float sy = (float)jsy;
227-
float scaleFactor = sqrtf((sx * sx + sy * sy) / std::max(sx * sx, sy * sy));
228-
jsx = (int)(sx * scaleFactor);
229-
jsy = (int)(sy * scaleFactor);
230-
231-
// Linear range mapping (used to invert deadzones)
232-
float dz = g_Config.fDInputAnalogDeadzone;
233-
int idzm = g_Config.iDInputAnalogInverseMode;
234-
float idz = g_Config.fDInputAnalogInverseDeadzone;
235-
float md = std::max(dz, idz);
236-
float st = g_Config.fDInputAnalogSensitivity;
237-
238-
float magnitude = sqrtf((float)(jsx * jsx + jsy * jsy));
239-
if (magnitude > dz * 10000.0f) {
240-
if (idzm == 1) {
241-
int xSign = Signs(jsx);
242-
if (xSign != 0) {
243-
jsx = LinearMaps(jsx, xSign * (int)(dz * 10000), xSign * 10000, xSign * (int)(md * 10000), xSign * (int)(st * 10000));
244-
}
245-
} else if (idzm == 2) {
246-
int ySign = Signs(jsy);
247-
if (ySign != 0) {
248-
jsy = LinearMaps(jsy, ySign * (int)(dz * 10000.0f), ySign * 10000, ySign * (int)(md * 10000.0f), ySign * (int)(st * 10000));
249-
}
250-
} else if (idzm == 3) {
251-
float xNorm = (float)jsx / magnitude;
252-
float yNorm = (float)jsy / magnitude;
253-
float mapMag = LinearMaps(magnitude, dz * 10000.0f, 10000.0f, md * 10000.0f, 10000.0f * st);
254-
jsx = (short)(xNorm * mapMag);
255-
jsy = (short)(yNorm * mapMag);
256-
}
257-
} else {
258-
jsx = 0;
259-
jsy = 0;
260-
}
261-
262-
jsx = (short)std::min(10000.0f, std::max((float)jsx, -10000.0f));
263-
jsy = (short)std::min(10000.0f, std::max((float)jsy, -10000.0f));
264-
}
265-
266212
static LONG *ValueForAxisId(DIJOYSTATE2 &js, int axisId) {
267213
switch (axisId) {
268214
case JOYSTICK_AXIS_X: return &js.lX;
@@ -275,14 +221,6 @@ static LONG *ValueForAxisId(DIJOYSTATE2 &js, int axisId) {
275221
}
276222
}
277223

278-
static void ApplyNormalization(DIJOYSTATE2 &js, int xAxisId, int yAxisId) {
279-
LONG *nrmX = ValueForAxisId(js, xAxisId);
280-
LONG *nrmY = ValueForAxisId(js, yAxisId);
281-
if (nrmX != nullptr && nrmY != nullptr) {
282-
ApplyNormalization(*nrmX, *nrmY);
283-
}
284-
}
285-
286224
int DinputDevice::UpdateState() {
287225
if (!pJoystick) return -1;
288226

@@ -303,10 +241,6 @@ int DinputDevice::UpdateState() {
303241
axis.deviceId = DEVICE_ID_PAD_0 + pDevNum;
304242

305243
auto axesToSquare = KeyMap::MappedAxesForDevice(axis.deviceId);
306-
ApplyNormalization(js, axesToSquare.leftX.axisId, axesToSquare.leftY.axisId);
307-
// Prevent double normalization.
308-
if (axesToSquare.leftX.axisId != axesToSquare.rightX.axisId && axesToSquare.leftX.axisId != axesToSquare.rightY.axisId)
309-
ApplyNormalization(js, axesToSquare.rightX.axisId, axesToSquare.rightY.axisId);
310244

311245
SendNativeAxis(DEVICE_ID_PAD_0 + pDevNum, js.lX, last_lX_, JOYSTICK_AXIS_X);
312246
SendNativeAxis(DEVICE_ID_PAD_0 + pDevNum, js.lY, last_lY_, JOYSTICK_AXIS_Y);

Windows/XinputDevice.cpp

+4-100
Original file line numberDiff line numberDiff line change
@@ -151,88 +151,6 @@ struct Stick {
151151
float y;
152152
};
153153

154-
inline float Clampf(float val, float min, float max) {
155-
if (val < min) return min;
156-
if (val > max) return max;
157-
return val;
158-
}
159-
160-
inline float Signf(float val) {
161-
return (float)((0.0f < val) - (val < 0.0f));
162-
}
163-
164-
inline float LinearMapf(float val, float a0, float a1, float b0, float b1) {
165-
return b0 + (((val - a0) * (b1 - b0)) / (a1 - a0));
166-
}
167-
168-
static Stick NormalizedDeadzoneFilter(short x, short y, float dz, int idzm, float idz, float st) {
169-
Stick s(x, y, 1.0f / 32767.0f);
170-
171-
float magnitude = sqrtf(s.x * s.x + s.y * s.y);
172-
if (magnitude > dz) {
173-
174-
// Circle to square mapping (the PSP stick outputs the full -1..1 square of values)
175-
#if 1
176-
// Looks way better than the old one, below, in the axis tester.
177-
float sx = s.x;
178-
float sy = s.y;
179-
float scaleFactor = sqrtf((sx * sx + sy * sy) / std::max(sx * sx, sy * sy));
180-
s.x = sx * scaleFactor;
181-
s.y = sy * scaleFactor;
182-
#else
183-
if (magnitude > 1.0f) {
184-
s.x *= 1.41421f;
185-
s.y *= 1.41421f;
186-
}
187-
#endif
188-
189-
// Linear range mapping (used to invert deadzones)
190-
float md = std::max(dz, idz);
191-
192-
if (idzm == 1)
193-
{
194-
float xSign = Signf(s.x);
195-
if (xSign != 0.0f) {
196-
s.x = LinearMapf(s.x, xSign * dz, xSign, xSign * md, xSign * st);
197-
}
198-
}
199-
else if (idzm == 2)
200-
{
201-
float ySign = Signf(s.y);
202-
if (ySign != 0.0f) {
203-
s.y = LinearMapf(s.y, ySign * dz, ySign, ySign * md, ySign * st);
204-
}
205-
}
206-
else if (idzm == 3)
207-
{
208-
float xNorm = s.x / magnitude;
209-
float yNorm = s.y / magnitude;
210-
float mapMag = LinearMapf(magnitude, dz, 1.0f, md, st);
211-
s.x = xNorm * mapMag;
212-
s.y = yNorm * mapMag;
213-
}
214-
215-
s.x = Clampf(s.x, -1.0f, 1.0f);
216-
s.y = Clampf(s.y, -1.0f, 1.0f);
217-
} else {
218-
s.x = 0.0f;
219-
s.y = 0.0f;
220-
}
221-
return s;
222-
}
223-
224-
bool NormalizedDeadzoneDiffers(short x1, short y1, short x2, short y2, const float dz) {
225-
Stick s1(x1, y1, 1.0f / 32767.0f);
226-
Stick s2(x2, y2, 1.0f / 32767.0f);
227-
228-
float magnitude1 = sqrtf(s1.x * s1.x + s1.y * s1.y);
229-
float magnitude2 = sqrtf(s2.x * s2.x + s2.y * s2.y);
230-
if (magnitude1 > dz || magnitude2 > dz) {
231-
return x1 != x2 || y1 != y2;
232-
}
233-
return false;
234-
}
235-
236154
bool NormalizedDeadzoneDiffers(u8 x1, u8 x2, const u8 thresh) {
237155
if (x1 > thresh || x2 > thresh) {
238156
return x1 != x2;
@@ -277,11 +195,6 @@ void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATIO
277195
ApplyButtons(pad, state);
278196
ApplyVibration(pad, vibration);
279197

280-
const float STICK_DEADZONE = g_Config.fXInputAnalogDeadzone;
281-
const int STICK_INV_MODE = g_Config.iXInputAnalogInverseMode;
282-
const float STICK_INV_DEADZONE = g_Config.fXInputAnalogInverseDeadzone;
283-
const float STICK_SENSITIVITY = g_Config.fXInputAnalogSensitivity;
284-
285198
AxisInput axis;
286199
axis.deviceId = DEVICE_ID_X360_0 + pad;
287200
auto sendAxis = [&](AndroidJoystickAxis axisId, float value) {
@@ -290,19 +203,10 @@ void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATIO
290203
NativeAxis(axis);
291204
};
292205

293-
if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.sThumbLX, prevState[pad].Gamepad.sThumbLY, state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, STICK_DEADZONE)) {
294-
Stick left = NormalizedDeadzoneFilter(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, STICK_DEADZONE, STICK_INV_MODE, STICK_INV_DEADZONE, STICK_SENSITIVITY);
295-
296-
sendAxis(JOYSTICK_AXIS_X, left.x);
297-
sendAxis(JOYSTICK_AXIS_Y, left.y);
298-
}
299-
300-
if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.sThumbRX, prevState[pad].Gamepad.sThumbRY, state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, STICK_DEADZONE)) {
301-
Stick right = NormalizedDeadzoneFilter(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, STICK_DEADZONE, STICK_INV_MODE, STICK_INV_DEADZONE, STICK_SENSITIVITY);
302-
303-
sendAxis(JOYSTICK_AXIS_Z, right.x);
304-
sendAxis(JOYSTICK_AXIS_RZ, right.y);
305-
}
206+
sendAxis(JOYSTICK_AXIS_X, (float)state.Gamepad.sThumbLX / 32767.0f);
207+
sendAxis(JOYSTICK_AXIS_Y, (float)state.Gamepad.sThumbLY / 32767.0f);
208+
sendAxis(JOYSTICK_AXIS_Z, (float)state.Gamepad.sThumbRX / 32767.0f);
209+
sendAxis(JOYSTICK_AXIS_RZ, (float)state.Gamepad.sThumbRY / 32767.0f);
306210

307211
if (NormalizedDeadzoneDiffers(prevState[pad].Gamepad.bLeftTrigger, state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) {
308212
sendAxis(JOYSTICK_AXIS_LTRIGGER, (float)state.Gamepad.bLeftTrigger / 255.0f);

0 commit comments

Comments
 (0)