Add optional controller rumble on button press

New "Vibrate controller on button press" setting under Controls. When enabled,
pressing a gamepad button rumbles that pad for as long as it's held - something
the PSP hardware never had, but which some people want from a modern pad.

Implemented per platform behind System_ControllerRumbleStart/Stop: SDL uses
SDL_RumbleGamepad, Windows feeds it into XinputDevice's existing vibration path
so it doesn't fight with the vibration games request through sceCtrl, and
Android goes through InputDevice.getVibrator() in Java. Stubbed elsewhere.

The D-pad is excluded, since it gets tapped constantly while navigating.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
This commit is contained in:
HalexxanderandClaude Opus 5 authored and Henrik Rydgård committed 2026-09-05 12:08:09 -06:00
1 parent 6d4bc5f261
commit e5bd8e8e58
20 files changed
+173

No files matched your search

+34
View File
@@ -7,6 +7,7 @@
#include "Common/StringUtils.h"
#include "Common/Log.h"
#include "Common/System/System.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/KeyMap.h"
#include "Core/ControlMapper.h"
@@ -615,9 +616,42 @@ bool ControlMapper::Key(const KeyInput &key) {
KeyMap::LockMappings();
bool retval = UpdatePSPState(mapping, now);
KeyMap::UnlockMappings();
if (g_Config.bControllerButtonRumble) {
UpdateButtonRumble(key);
}
return retval;
}
// Rumbles the pad for as long as a button is held. Note that we count the buttons held
// per pad - otherwise releasing one of two held buttons would cut the rumble short.
void ControlMapper::UpdateButtonRumble(const KeyInput &key) {
int padIndex;
if (key.deviceId >= DEVICE_ID_PAD_0 && key.deviceId <= DEVICE_ID_PAD_9) {
padIndex = (int)key.deviceId - DEVICE_ID_PAD_0;
} else if (key.deviceId >= DEVICE_ID_XINPUT_0 && key.deviceId <= DEVICE_ID_XINPUT_3) {
padIndex = (int)key.deviceId - DEVICE_ID_XINPUT_0;
} else {
return;
}
// The D-pad gets tapped constantly when navigating, which just feels noisy.
if (key.keyCode == NKCODE_UNKNOWN || (key.keyCode >= NKCODE_DPAD_UP && key.keyCode <= NKCODE_DPAD_RIGHT)) {
return;
}
if (key.flags & KeyInputFlags::DOWN) {
if (buttonsHeld_[padIndex]++ == 0) {
System_ControllerRumbleStart(padIndex);
}
} else if (key.flags & KeyInputFlags::UP) {
if (buttonsHeld_[padIndex] > 0 && --buttonsHeld_[padIndex] == 0) {
System_ControllerRumbleStop(padIndex);
}
}
}
void ControlMapper::ToggleSwapAxes() {
// Note: The lock is already locked here.
swapAxes_ = !swapAxes_;