Skip to content

Commit

Permalink
Add option to bypass SOCD cleaning for supported input modes (#210)
Browse files Browse the repository at this point in the history
* Add SOCD resolution with fixes to dual directional

* Add missing SOCD check

---------

Co-authored-by: deeebug <77402236+deeebug@users.noreply.github.com>
  • Loading branch information
henrebotha and deeebug committed May 6, 2023
1 parent f2e8b69 commit 28d47d9
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 11 deletions.
1 change: 1 addition & 0 deletions headers/addons/dualdirectional.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class DualDirectionalInput : public GPAddon {
uint8_t SOCDCombine(SOCDMode, uint8_t);
uint8_t SOCDGamepadClean(uint8_t, bool isLastWin);
void OverrideGamepad(Gamepad *, DpadMode, uint8_t);
const SOCDMode getSOCDMode(GamepadOptions&);
uint8_t dDebState; // Debounce State (stored)
uint8_t dualState; // Dual Directional State
DpadDirection lastGPUD; // Gamepad Last Up-Down
Expand Down
6 changes: 6 additions & 0 deletions headers/gamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ class Gamepad {
GamepadButtonMapping *mapButtonA2;
GamepadButtonMapping **gamepadMappings;

inline static const SOCDMode resolveSOCDMode(const GamepadOptions& options) {
return ((options.socdMode == SOCD_MODE_BYPASS) &&
(options.inputMode == INPUT_MODE_HID || options.inputMode == INPUT_MODE_SWITCH || options.inputMode == INPUT_MODE_PS4)) ?
SOCD_MODE_NEUTRAL : options.socdMode;
};

private:
void releaseAllKeys(void);
void pressKey(uint8_t code);
Expand Down
4 changes: 3 additions & 1 deletion headers/gamepad/GamepadEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef enum
SOCD_MODE_NEUTRAL, // U+D=N, L+R=N
SOCD_MODE_SECOND_INPUT_PRIORITY, // U>D=D, L>R=R (Last Input Priority, aka Last Win)
SOCD_MODE_FIRST_INPUT_PRIORITY, // U>D=U, L>R=L (First Input Priority, aka First Win)
SOCD_MODE_BYPASS, // U+D=UD, L+R=LR (No cleaning applied)
} SOCDMode;

// Enum for tracking last direction state of Second Input SOCD method
Expand All @@ -60,5 +61,6 @@ typedef enum
HOTKEY_SOCD_LAST_INPUT,
HOTKEY_INVERT_X_AXIS,
HOTKEY_INVERT_Y_AXIS,
HOTKEY_SOCD_FIRST_INPUT
HOTKEY_SOCD_FIRST_INPUT,
HOTKEY_SOCD_BYPASS
} GamepadHotkey;
4 changes: 4 additions & 0 deletions headers/gamepad/GamepadState.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ inline uint16_t dpadToAnalogY(uint8_t dpad)
*/
inline uint8_t runSOCDCleaner(SOCDMode mode, uint8_t dpad)
{
if (mode == SOCD_MODE_BYPASS) {
return dpad;
}

static DpadDirection lastUD = DIRECTION_NONE;
static DpadDirection lastLR = DIRECTION_NONE;
uint8_t newDpad = 0;
Expand Down
33 changes: 25 additions & 8 deletions src/addons/dualdirectional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,16 @@ void DualDirectionalInput::preprocess()

// Convert gamepad from process() output to uint8 value
uint8_t gamepadState = gamepad->state.dpad;
const SOCDMode& socdMode = getSOCDMode(gamepad->options);

// Combined Mode
if ( combineMode == DUAL_COMBINE_MODE_MIXED ) {
SOCDDualClean(gamepad->options.socdMode); // Clean up Dual SOCD based on the mode
SOCDDualClean(socdMode); // Clean up Dual SOCD based on the mode

// Second Input (Last Input Priority) needs to happen before we MPG clean
if ( gamepad->options.socdMode == SOCD_MODE_SECOND_INPUT_PRIORITY ||
gamepad->options.socdMode == SOCD_MODE_FIRST_INPUT_PRIORITY ) {
gamepadState = SOCDGamepadClean(gamepadState, gamepad->options.socdMode == SOCD_MODE_SECOND_INPUT_PRIORITY) | dualState;
if ( socdMode == SOCD_MODE_SECOND_INPUT_PRIORITY ||
socdMode == SOCD_MODE_FIRST_INPUT_PRIORITY ) {
gamepadState = SOCDGamepadClean(gamepadState, socdMode == SOCD_MODE_SECOND_INPUT_PRIORITY) | dualState;
}
}
// Gamepad Overwrite Mode
Expand All @@ -117,21 +118,24 @@ void DualDirectionalInput::process()
{
Gamepad * gamepad = Storage::getInstance().GetGamepad();
uint8_t dualOut = dualState;
const SOCDMode& socdMode = getSOCDMode(gamepad->options);

// If we're in mixed mode
if (combineMode == DUAL_COMBINE_MODE_MIXED) {
uint8_t gamepadDpad = gpadToBinary(gamepad->options.dpadMode, gamepad->state);
// Up-Win or Neutral Modify AFTER SOCD(gamepad), Last-Win Modifies BEFORE SOCD(gamepad)
if ( gamepad->options.socdMode == SOCD_MODE_UP_PRIORITY ||
gamepad->options.socdMode == SOCD_MODE_NEUTRAL ) {
if ( socdMode == SOCD_MODE_UP_PRIORITY ||
socdMode == SOCD_MODE_NEUTRAL ) {

// Up-Win or Neutral: SOCD(gamepad) *already done* | SOCD(dual) *done in preprocess()*
dualOut = SOCDCombine(gamepad->options.socdMode, gamepadDpad);
dualOut = SOCDCombine(socdMode, gamepadDpad);

// Modify Gamepad if we're in mixed Up-Win or Neutral and dual != gamepad
if ( dualOut != gamepadDpad ) {
OverrideGamepad(gamepad, gamepad->options.dpadMode, dualOut);
}
} else if (socdMode == SOCD_MODE_BYPASS) {
OverrideGamepad(gamepad, gamepad->options.dpadMode, dualOut | gamepad->state.dpad);
}
} else { // We are not mixed mode, don't change dual output
dualOut = dualState;
Expand Down Expand Up @@ -204,6 +208,11 @@ uint8_t DualDirectionalInput::SOCDGamepadClean(uint8_t gamepadState, bool isLast

uint8_t DualDirectionalInput::SOCDCombine(SOCDMode mode, uint8_t gamepadState) {
uint8_t outState = dualState | gamepadState;

if (mode == SOCD_MODE_BYPASS) {
return outState;
}

switch (outState & (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN)) {
case (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN): // If last state was Up or Down, exclude it from our gamepad
if ( mode == SOCD_MODE_NEUTRAL )
Expand All @@ -225,7 +234,11 @@ uint8_t DualDirectionalInput::SOCDCombine(SOCDMode mode, uint8_t gamepadState) {
return outState;
}

void DualDirectionalInput::SOCDDualClean(SOCDMode socdMode) {
void DualDirectionalInput::SOCDDualClean(SOCDMode socdMode) {
if (socdMode == SOCD_MODE_BYPASS) {
return;
}

// Dual SOCD Last-Win Clean
switch (dualState & (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN)) {
case (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN): // If last state was Up or Down, exclude it from our gamepad
Expand Down Expand Up @@ -310,3 +323,7 @@ uint8_t DualDirectionalInput::gpadToBinary(DpadMode dpadMode, GamepadState state

return out;
}

const SOCDMode DualDirectionalInput::getSOCDMode(GamepadOptions& options) {
return Gamepad::resolveSOCDMode(options);
}
3 changes: 2 additions & 1 deletion src/addons/i2cdisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,12 +945,13 @@ void I2CDisplayAddon::drawStatusBar(Gamepad * gamepad)
case DPAD_MODE_RIGHT_ANALOG: statusBar += " RS"; break;
}

switch (gamepad->options.socdMode)
switch (Gamepad::resolveSOCDMode(gamepad->options))
{
case SOCD_MODE_NEUTRAL: statusBar += " SOCD-N"; break;
case SOCD_MODE_UP_PRIORITY: statusBar += " SOCD-U"; break;
case SOCD_MODE_SECOND_INPUT_PRIORITY: statusBar += " SOCD-L"; break;
case SOCD_MODE_FIRST_INPUT_PRIORITY: statusBar += " SOCD-F"; break;
case SOCD_MODE_BYPASS: statusBar += " "; break;
}
drawText(0, 0, statusBar);
}
Expand Down
3 changes: 2 additions & 1 deletion src/gamepad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void Gamepad::process()
{
memcpy(&rawState, &state, sizeof(GamepadState));

state.dpad = runSOCDCleaner(options.socdMode, state.dpad);
state.dpad = runSOCDCleaner(resolveSOCDMode(options), state.dpad);

switch (options.dpadMode)
{
Expand Down Expand Up @@ -283,6 +283,7 @@ GamepadHotkey Gamepad::hotkey()
case HOTKEY_SOCD_NEUTRAL : options.socdMode = SOCD_MODE_NEUTRAL; break;
case HOTKEY_SOCD_LAST_INPUT : options.socdMode = SOCD_MODE_SECOND_INPUT_PRIORITY; break;
case HOTKEY_SOCD_FIRST_INPUT : options.socdMode = SOCD_MODE_FIRST_INPUT_PRIORITY; break;
case HOTKEY_SOCD_BYPASS : options.socdMode = SOCD_MODE_BYPASS; break;
case HOTKEY_INVERT_X_AXIS : break;
case HOTKEY_INVERT_Y_AXIS :
if (lastAction != HOTKEY_INVERT_Y_AXIS)
Expand Down

0 comments on commit 28d47d9

Please sign in to comment.