diff --git a/port/include/input.h b/port/include/input.h index 6171c26961..833eb8c378 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -205,6 +205,11 @@ void inputRumble(s32 idx, f32 strength, f32 time); f32 inputRumbleGetStrength(s32 cidx); void inputRumbleSetStrength(s32 cidx, f32 val); +// Filter out rumble intensity +// Best for gyro aim or simultaneous gamepad+kb/mouse input +s32 inputRumbleGetFilter(s32 cidx); +void inputRumbleSetFilter(s32 cidx, s32 val); + // locks the mouse cursor in the window and makes it invisible if argument is true void inputLockMouse(s32 lock); @@ -270,4 +275,4 @@ const char *inputGetClipboard(void); // returns keymod values u32 inputGetKeyModState(void); -#endif +#endif \ No newline at end of file diff --git a/port/src/input.c b/port/src/input.c index 20137358c1..0bdbbe37a5 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -36,6 +36,7 @@ static SDL_GameController *pads[INPUT_MAX_CONTROLLERS]; #define CONTROLLERCFG_DEFAULT { \ .rumbleOn = 0, \ .rumbleScale = 0.5f, \ + .rumbleFilter = -1, \ .axisMap = { \ { SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY }, \ { SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY }, \ @@ -51,6 +52,7 @@ static SDL_GameController *pads[INPUT_MAX_CONTROLLERS]; static struct controllercfg { s32 rumbleOn; f32 rumbleScale; + s32 rumbleFilter; u32 axisMap[2][2]; f32 sens[4]; s32 deadzone[4]; @@ -944,15 +946,28 @@ void inputRumble(s32 idx, f32 strength, f32 time) } if (padsCfg[idx].rumbleOn) { + s32 filterSetting = padsCfg[idx].rumbleFilter; + + // Apply user's rumble scale strength *= padsCfg[idx].rumbleScale; + if (strength <= 0.f) { strength = 0.f; time = 0.f; - } else { - strength *= 65535.f; - time *= 1000.f; } - SDL_GameControllerRumble(pads[idx], (u16)strength, (u16)strength, (u32)time); + + u16 lowFreq = (u16)(strength * 65535.f); + u16 highFreq = (u16)(strength * 65535.f); + + // Apply filter to reduce rumble intensity when enabled + if (filterSetting == 1) { + lowFreq = (u16)(lowFreq * 0.20f); // 20% of original + highFreq = (u16)(strength * 65535.f * 0.08f); // 8% of original (recalculate from strength) + } + + u32 duration = (u32)(time * 1000.f); + + SDL_GameControllerRumble(pads[idx], lowFreq, highFreq, duration); } } @@ -966,6 +981,16 @@ void inputRumbleSetStrength(s32 cidx, f32 val) padsCfg[cidx].rumbleScale = val; } +s32 inputRumbleGetFilter(s32 cidx) +{ + return padsCfg[cidx].rumbleFilter; +} + +void inputRumbleSetFilter(s32 cidx, s32 val) +{ + padsCfg[cidx].rumbleFilter = val; +} + s32 inputControllerMask(void) { return connectedMask; @@ -1524,6 +1549,7 @@ PD_CONSTRUCTOR static void inputConfigInit(void) secname[12] = '1' + c; secname[13] = '\0'; configRegisterFloat(strFmt("%s.RumbleScale", secname), &padsCfg[c].rumbleScale, 0.f, 1.f); + configRegisterInt(strFmt("%s.RumbleFilter", secname), &padsCfg[c].rumbleFilter, -1, 1); configRegisterInt(strFmt("%s.LStickDeadzoneX", secname), &padsCfg[c].deadzone[0], 0, 32767); configRegisterInt(strFmt("%s.LStickDeadzoneY", secname), &padsCfg[c].deadzone[1], 0, 32767); configRegisterInt(strFmt("%s.RStickDeadzoneX", secname), &padsCfg[c].deadzone[2], 0, 32767); @@ -1542,4 +1568,4 @@ PD_CONSTRUCTOR static void inputConfigInit(void) configRegisterString(keyname, bindStrs[c][ck], MAX_BIND_STR); } } -} +} \ No newline at end of file