Skip to content

Commit 1733b23

Browse files
committed
Harden N64/PSX polling and Wii analog clamp behavior
1 parent 00f77f5 commit 1733b23

3 files changed

Lines changed: 119 additions & 97 deletions

File tree

ReflexMPG/Input_N64.h

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,14 @@ class ReflexInputN64 : public RZInputModule {
159159

160160
void setup2() override { }
161161

162-
bool read() override {
163-
static uint8_t lastControllerCount = 0;
164-
static bool haveController[] = { false, false };
165-
static bool isEnabled[] = { false, false };
166-
static uint16_t oldButtons[] = { 0, 0 };
167-
static int8_t oldX[] = { 0, 0 };
168-
static int8_t oldY[] = { 0, 0 };
162+
bool read() override {
163+
static uint8_t lastControllerCount = 0;
164+
static bool haveController[] = { false, false };
165+
static bool isEnabled[] = { false, false };
166+
static uint16_t oldButtons[] = { 0, 0 };
167+
static int8_t oldX[] = { 0, 0 };
168+
static int8_t oldY[] = { 0, 0 };
169+
static uint8_t readFailCount[] = { 0, 0 };
169170

170171
#ifdef ENABLE_REFLEX_PAD
171172
//static bool firstTime = true;
@@ -255,16 +256,17 @@ static bool isReadSuccess[] = {false,false};
255256
if (!isEnabled[i])
256257
continue;
257258

258-
if (!haveController[i]) {
259-
if (n64->begin()) {
260-
haveController[i] = true;
261-
// tryEnableRumble();
262-
n64ResetJoyValues(i);
263-
#ifdef ENABLE_REFLEX_PAD
264-
showDefaultPadN64(i, true);
265-
#endif
266-
}
267-
} else {
259+
if (!haveController[i]) {
260+
if (n64->begin()) {
261+
haveController[i] = true;
262+
readFailCount[i] = 0;
263+
// tryEnableRumble();
264+
n64ResetJoyValues(i);
265+
#ifdef ENABLE_REFLEX_PAD
266+
showDefaultPadN64(i, true);
267+
#endif
268+
}
269+
} else {
268270
// const PsxControllerProtocol proto = psx->getProtocol();
269271
// if(lastProto[i] != proto)
270272
// tryEnableRumble();
@@ -274,25 +276,27 @@ static bool isReadSuccess[] = {false,false};
274276
// #else
275277
// psx->setRumble (rumble[i].right_power != 0x0, rumble[i].left_power);
276278
// #endif
277-
isReadSuccess[i] = n64->read() && n64->getData().status.device != NINTENDO_DEVICE_N64_NONE;
278-
279-
if (isReadSuccess[i])
280-
n64data[i] = n64->getData();
281-
282-
if (isReadSuccess[i] && options.inputMode == INPUT_MODE_XINPUT) {
283-
n64->setRumble(rumble[i].left_power != 0x0 || rumble[i].right_power != 0x0);
284-
}
285-
286-
//controller just removed?
287-
if (!isReadSuccess[i]){
288-
haveController[i] = false;
289-
n64ResetJoyValues(i);
290-
#ifdef ENABLE_REFLEX_PAD
291-
showDefaultPadN64(i, false);
292-
#endif
293-
}
294-
}
295-
}
279+
if (n64->read()) {
280+
n64data[i] = n64->getData();
281+
isReadSuccess[i] = n64data[i].status.device != NINTENDO_DEVICE_N64_NONE;
282+
}
283+
284+
if (isReadSuccess[i]) {
285+
readFailCount[i] = 0;
286+
if (options.inputMode == INPUT_MODE_XINPUT) {
287+
n64->setRumble(rumble[i].left_power != 0x0 || rumble[i].right_power != 0x0);
288+
}
289+
} else if (++readFailCount[i] >= 2) {
290+
// Require two consecutive failures before dropping to reduce transient disconnects.
291+
haveController[i] = false;
292+
readFailCount[i] = 0;
293+
n64ResetJoyValues(i);
294+
#ifdef ENABLE_REFLEX_PAD
295+
showDefaultPadN64(i, false);
296+
#endif
297+
}
298+
}
299+
}
296300

297301

298302

@@ -310,8 +314,8 @@ static bool isReadSuccess[] = {false,false};
310314

311315

312316
for (uint8_t i = 0; i < totalUsb; ++i) {
313-
if (haveController[i]) {
314-
//controller read sucess
317+
if (haveController[i] && isReadSuccess[i]) {
318+
//controller read sucess
315319

316320
const uint16_t digitalData = (n64data[i].report.buttons0 << 12) + (n64data[i].report.dpad << 8) + (n64data[i].report.buttons1 << 4) + n64data[i].report.cpad;
317321
const bool buttonsChanged = digitalData != oldButtons[i];

ReflexMPG/Input_Psx.h

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,13 @@ class ReflexInputPsx : public RZInputModule {
203203
state[outputIndex].dpad = (state[outputIndex].dpad | specialDpadMask) & 0xF;
204204
}
205205

206-
bool loopDualShock() {
207-
static byte lastLX[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
208-
static byte lastLY[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
209-
static byte lastRX[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
210-
static byte lastRY[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
206+
bool loopDualShock() {
207+
static byte lastLX[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
208+
static byte lastLY[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
209+
static byte lastRX[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
210+
static byte lastRY[] = { ANALOG_IDLE_VALUE, ANALOG_IDLE_VALUE };
211+
static uint8_t lastStableDpad[] = { 0, 0 };
212+
static uint16_t lastStableButtons[] = { 0, 0 };
211213

212214
#ifdef ENABLE_REFLEX_PAD
213215
static PsxControllerProtocol lastPadType[] = { PSPROTO_UNKNOWN, PSPROTO_UNKNOWN };
@@ -219,8 +221,8 @@ class ReflexInputPsx : public RZInputModule {
219221
byte analogY = ANALOG_IDLE_VALUE;
220222
//word convertedX, convertedY;
221223

222-
const bool digitalStateChanged = psx->buttonsChanged();//check if any digital value changed (dpad and buttons)
223-
bool stateChanged = digitalStateChanged;
224+
bool digitalStateChanged = false;
225+
bool stateChanged = false;
224226

225227
const PsxControllerProtocol proto = psx->getProtocol();
226228

@@ -244,10 +246,10 @@ class ReflexInputPsx : public RZInputModule {
244246

245247
// uint16_t buttonData = 0;
246248
//controller buttons
247-
state[outputIndex].buttons = 0
248-
| (psx->buttonPressed(PSB_CROSS) ? GAMEPAD_MASK_B1 : 0) // Generic: K1, Switch: B, Xbox: A
249-
| (psx->buttonPressed(PSB_CIRCLE) ? GAMEPAD_MASK_B2 : 0) // Generic: K2, Switch: A, Xbox: B
250-
| (psx->buttonPressed(PSB_SQUARE) ? GAMEPAD_MASK_B3 : 0) // Generic: P1, Switch: Y, Xbox: X
249+
state[outputIndex].buttons = 0
250+
| (psx->buttonPressed(PSB_CROSS) ? GAMEPAD_MASK_B1 : 0) // Generic: K1, Switch: B, Xbox: A
251+
| (psx->buttonPressed(PSB_CIRCLE) ? GAMEPAD_MASK_B2 : 0) // Generic: K2, Switch: A, Xbox: B
252+
| (psx->buttonPressed(PSB_SQUARE) ? GAMEPAD_MASK_B3 : 0) // Generic: P1, Switch: Y, Xbox: X
251253
| (psx->buttonPressed(PSB_TRIANGLE) ? GAMEPAD_MASK_B4 : 0) // Generic: P2, Switch: X, Xbox: Y
252254
| (psx->buttonPressed(PSB_L1) ? GAMEPAD_MASK_L1 : 0) // Generic: P4, Switch: L, Xbox: LB
253255
| (psx->buttonPressed(PSB_R1) ? GAMEPAD_MASK_R1 : 0) // Generic: P3, Switch: R, Xbox: RB
@@ -256,8 +258,17 @@ class ReflexInputPsx : public RZInputModule {
256258
| (psx->buttonPressed(PSB_SELECT) ? GAMEPAD_MASK_S1 : 0) // Generic: Select, Switch: -, Xbox: View
257259
| (psx->buttonPressed(PSB_START) ? GAMEPAD_MASK_S2 : 0) // Generic: Start, Switch: +, Xbox: Menu
258260
| (psx->buttonPressed(PSB_L3) ? GAMEPAD_MASK_L3 : 0) // All: Left Stick Click
259-
| (psx->buttonPressed(PSB_R3) ? GAMEPAD_MASK_R3 : 0) // All: Right Stick Click
260-
;
261+
| (psx->buttonPressed(PSB_R3) ? GAMEPAD_MASK_R3 : 0) // All: Right Stick Click
262+
;
263+
264+
// Ignore obvious one-frame D-pad corruption without changing normal input latency.
265+
if (specialDpadMask == 0x0
266+
&& state[outputIndex].dpad == (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT)) {
267+
state[outputIndex].dpad = lastStableDpad[outputIndex];
268+
}
269+
digitalStateChanged = state[outputIndex].dpad != lastStableDpad[outputIndex]
270+
|| state[outputIndex].buttons != lastStableButtons[outputIndex];
271+
stateChanged = digitalStateChanged;
261272

262273

263274
//if(proto != PSPROTO_DIGITAL)
@@ -294,8 +305,10 @@ class ReflexInputPsx : public RZInputModule {
294305
if (lastRX[outputIndex] != analogX || lastRY[outputIndex] != analogY)
295306
stateChanged = true;
296307

297-
lastRX[outputIndex] = analogX;
298-
lastRY[outputIndex] = analogY;
308+
lastRX[outputIndex] = analogX;
309+
lastRY[outputIndex] = analogY;
310+
lastStableDpad[outputIndex] = state[outputIndex].dpad;
311+
lastStableButtons[outputIndex] = state[outputIndex].buttons;
299312

300313
if(stateChanged) {
301314
#ifdef ENABLE_REFLEX_PAD
@@ -497,10 +510,11 @@ class ReflexInputPsx : public RZInputModule {
497510
}
498511
}
499512

500-
bool read() override {
501-
static bool isReadSuccess[] = {false,false};
502-
static bool isEnabled[] = {false,false};
503-
bool stateChanged = false;
513+
bool read() override {
514+
static bool isReadSuccess[] = {false,false};
515+
static bool isEnabled[] = {false,false};
516+
static uint8_t readFailCount[] = {0,0};
517+
bool stateChanged = false;
504518

505519
outputIndex = 0;
506520

@@ -603,28 +617,32 @@ class ReflexInputPsx : public RZInputModule {
603617
if (!isEnabled[i])
604618
continue;
605619

606-
if (!haveController[i]) {
607-
if (psx->begin()) {
608-
haveController[i] = true;
609-
tryEnableRumble();
610-
ShowDefaultPadPsx(i, psx->getProtocol());
611-
}
612-
} else {
620+
if (!haveController[i]) {
621+
if (psx->begin()) {
622+
haveController[i] = true;
623+
readFailCount[i] = 0;
624+
tryEnableRumble();
625+
ShowDefaultPadPsx(i, psx->getProtocol());
626+
}
627+
} else {
613628
const PsxControllerProtocol proto = psx->getProtocol();
614629
if(lastProto[i] != proto)
615630
tryEnableRumble();
616631
lastProto[i] = proto;
617632
#ifdef PSX_COMBINE_RUMBLE
618633
psx->setRumble ((rumble[i].left_power | rumble[i].right_power) != 0x0, (rumble[i].left_power | rumble[i].right_power));
619-
#else
620-
psx->setRumble (rumble[i].right_power != 0x0, rumble[i].left_power);
621-
#endif
622-
isReadSuccess[i] = psx->read();
623-
if (!isReadSuccess[i]){ //debug (F("Controller lost.")); debug (F(" last values: x = ")); debug (lastX); debug (F(", y = ")); debugln (lastY);
624-
haveController[i] = false;
625-
ShowDefaultPadPsx(i, PSPROTO_UNKNOWN);
626-
}
627-
}
634+
#else
635+
psx->setRumble (rumble[i].right_power != 0x0, rumble[i].left_power);
636+
#endif
637+
isReadSuccess[i] = psx->read();
638+
if (isReadSuccess[i]) {
639+
readFailCount[i] = 0;
640+
} else if (++readFailCount[i] >= 2){ //debug (F("Controller lost.")); debug (F(" last values: x = ")); debug (lastX); debug (F(", y = ")); debugln (lastY);
641+
haveController[i] = false;
642+
readFailCount[i] = 0;
643+
ShowDefaultPadPsx(i, PSPROTO_UNKNOWN);
644+
}
645+
}
628646
if(isGuncon)//only use first port for guncon
629647
break;
630648
}

ReflexMPG/Input_Wii.h

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -418,30 +418,30 @@ class ReflexInputWii : public RZInputModule {
418418
if (buttonsChanged || analogChanged) { //state changed?
419419
stateChanged = buttonsChanged;
420420

421-
#ifndef WII_ANALOG_RAW
422-
//shift to center
423-
leftX -= wii_lx_shift;
424-
leftY -= wii_ly_shift;
425-
rightX -= wii_rx_shift;
426-
rightY -= wii_ry_shift;
427-
428-
//clamp
429-
if (leftX < wii_analog_stick_min) leftX = wii_analog_stick_min;
430-
else if (leftX > wii_analog_stick_max) leftX = wii_analog_stick_max;
431-
if (leftY < wii_analog_stick_min) leftY = wii_analog_stick_min;
432-
else if (leftY > wii_analog_stick_max) leftY = wii_analog_stick_max;
433-
434-
if (rightX < wii_analog_stick_min) rightX = wii_analog_stick_min;
435-
else if (rightX > wii_analog_stick_max) rightX = wii_analog_stick_max;
436-
if (rightY < wii_analog_stick_min) rightY = wii_analog_stick_min;
437-
else if (rightY > wii_analog_stick_max) rightY = wii_analog_stick_max;
438-
439-
//scale
440-
leftX = map(leftX, wii_analog_stick_min, wii_analog_stick_max, 0, 255);
441-
leftY = map(leftY, wii_analog_stick_min, wii_analog_stick_max, 0, 255);
442-
rightX = map(rightX, wii_analog_stick_min, wii_analog_stick_max, 0, 255);
443-
rightY = map(rightY, wii_analog_stick_min, wii_analog_stick_max, 0, 255);
444-
#endif
421+
#ifndef WII_ANALOG_RAW
422+
//shift to center
423+
int16_t leftXi = static_cast<int16_t>(leftX) - wii_lx_shift;
424+
int16_t leftYi = static_cast<int16_t>(leftY) - wii_ly_shift;
425+
int16_t rightXi = static_cast<int16_t>(rightX) - wii_rx_shift;
426+
int16_t rightYi = static_cast<int16_t>(rightY) - wii_ry_shift;
427+
428+
//clamp
429+
if (leftXi < wii_analog_stick_min) leftXi = wii_analog_stick_min;
430+
else if (leftXi > wii_analog_stick_max) leftXi = wii_analog_stick_max;
431+
if (leftYi < wii_analog_stick_min) leftYi = wii_analog_stick_min;
432+
else if (leftYi > wii_analog_stick_max) leftYi = wii_analog_stick_max;
433+
434+
if (rightXi < wii_analog_stick_min) rightXi = wii_analog_stick_min;
435+
else if (rightXi > wii_analog_stick_max) rightXi = wii_analog_stick_max;
436+
if (rightYi < wii_analog_stick_min) rightYi = wii_analog_stick_min;
437+
else if (rightYi > wii_analog_stick_max) rightYi = wii_analog_stick_max;
438+
439+
//scale
440+
leftX = static_cast<uint8_t>(map(leftXi, wii_analog_stick_min, wii_analog_stick_max, 0, 255));
441+
leftY = static_cast<uint8_t>(map(leftYi, wii_analog_stick_min, wii_analog_stick_max, 0, 255));
442+
rightX = static_cast<uint8_t>(map(rightXi, wii_analog_stick_min, wii_analog_stick_max, 0, 255));
443+
rightY = static_cast<uint8_t>(map(rightYi, wii_analog_stick_min, wii_analog_stick_max, 0, 255));
444+
#endif
445445

446446
state[0].lx = convertAnalog( leftX);
447447
state[0].ly = convertAnalog((uint8_t)~leftY);

0 commit comments

Comments
 (0)