Skip to content

Commit ae15e14

Browse files
committed
Implement PPSSPP specific vibration cheat(Xinput)
Syntax is: 0xA0NNLLLL 0x00MMRRRR where NN/MM is time vibration lasts LLLL/RRRR is the vibration power
1 parent 6cf3687 commit ae15e14

File tree

7 files changed

+96
-6
lines changed

7 files changed

+96
-6
lines changed

Core/CwCheat.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
static int CheatEvent = -1;
2525
static CWCheatEngine *cheatEngine;
2626
static bool cheatsEnabled;
27+
SceCtrl vibrationCheat;
2728
void hleCheat(u64 userdata, int cyclesLate);
2829

2930
static inline std::string TrimString(const std::string &s) {
@@ -596,6 +597,13 @@ CheatOperation CWCheatEngine::InterpretNextCwCheat(const CheatCode &cheat, size_
596597
}
597598
return { CheatOp::Invalid };
598599

600+
case 0xA: // Vibration command(PPSSPP specific)
601+
vibrationCheat.SetLeftVibration(line1.part1 & 0x0000FFFF);
602+
vibrationCheat.SetRightVibration(line1.part2 & 0x0000FFFF);
603+
vibrationCheat.SetVibrationLeftDropout(line1.part1 >> 16 & 0x000000FF);
604+
vibrationCheat.SetVibrationRightDropout(line1.part2 >> 16 & 0x000000FF);
605+
return { CheatOp::Invalid };
606+
599607
case 0xB: // Delay command.
600608
return { CheatOp::Delay, 0, 0, arg };
601609

Core/CwCheat.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class CWCheatEngine {
5353
std::string CheatFilename();
5454
void Run();
5555
bool HasCheats();
56-
5756
void InvalidateICache(u32 addr, int size);
5857
private:
5958
u32 GetAddress(u32 value);

Core/HLE/sceCtrl.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ static std::mutex ctrlMutex;
8787

8888
static int ctrlTimer = -1;
8989

90+
static u16 leftVibration = 0;
91+
static u16 rightVibration = 0;
92+
// The higher the dropout, the longer Vibration will run
93+
static u8 vibrationLeftDropout = 160;
94+
static u8 vibrationRightDropout = 160;
95+
9096
// STATE END
9197
//////////////////////////////////////////////////////////////////////////
9298

@@ -288,6 +294,10 @@ static void __CtrlVblank()
288294
{
289295
emuRapidFireFrames++;
290296

297+
// Reduce gamepad Vibration by set % each frame
298+
leftVibration *= (float)vibrationLeftDropout / 256.0f;
299+
rightVibration *= (float)vibrationRightDropout / 256.0f;
300+
291301
// This always runs, so make sure we're in vblank mode.
292302
if (ctrlCycle == 0)
293303
__CtrlDoSample();
@@ -563,3 +573,25 @@ void Register_sceCtrl_driver()
563573
{
564574
RegisterModule("sceCtrl_driver", ARRAY_SIZE(sceCtrl), sceCtrl);
565575
}
576+
577+
u16 GetRightVibration() {
578+
return rightVibration;
579+
}
580+
581+
u16 GetLeftVibration() {
582+
return leftVibration;
583+
}
584+
585+
void SceCtrl::SetRightVibration(u16 rVibration) {
586+
rightVibration = rVibration;
587+
}
588+
void SceCtrl::SetLeftVibration(u16 lVibration) {
589+
leftVibration = lVibration;
590+
}
591+
void SceCtrl::SetVibrationRightDropout(u8 vibrationRDropout) {
592+
vibrationRightDropout = vibrationRDropout;
593+
594+
}
595+
void SceCtrl::SetVibrationLeftDropout(u8 vibrationLDropout) {
596+
vibrationLeftDropout = vibrationLDropout;
597+
}

Core/HLE/sceCtrl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,14 @@ void __CtrlPeekAnalog(int stick, float *x, float *y);
8787
u32 __CtrlReadLatch();
8888

8989
void Register_sceCtrl_driver();
90+
91+
u16 GetRightVibration();
92+
u16 GetLeftVibration();
93+
94+
class SceCtrl {
95+
public:
96+
void SetLeftVibration(u16 lVibration);
97+
void SetRightVibration(u16 rVibration);
98+
void SetVibrationLeftDropout(u8 vibrationLDropout);
99+
void SetVibrationRightDropout(u8 vibrationRDropout);
100+
};

Windows/PPSSPP.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1027,4 +1027,4 @@
10271027
<UserProperties RESOURCE_FILE="DaSh.rc" />
10281028
</VisualStudio>
10291029
</ProjectExtensions>
1030-
</Project>
1030+
</Project>

Windows/XinputDevice.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111
#include "input/input_state.h"
1212
#include "input/keycodes.h"
1313
#include "XinputDevice.h"
14+
#include "Core/Core.h"
15+
#include "Core/HLE/sceCtrl.h"
1416

1517
// Utilities to dynamically load XInput. Adapted from SDL.
1618

1719
#if !PPSSPP_PLATFORM(UWP)
1820

1921
typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState);
22+
typedef DWORD (WINAPI *XInputSetState_t) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
2023

2124
static XInputGetState_t PPSSPP_XInputGetState = NULL;
25+
static XInputSetState_t PPSSPP_XInputSetState = NULL;
2226
static DWORD PPSSPP_XInputVersion = 0;
2327
static HMODULE s_pXInputDLL = 0;
2428
static int s_XInputDLLRefCount = 0;
@@ -65,6 +69,17 @@ static int LoadXInputDLL() {
6569
return -1;
6670
}
6771

72+
/* Let's try the name first, then fall back to a non-Ex version (xinput9_1_0.dll doesn't have Ex) */
73+
PPSSPP_XInputSetState = (XInputSetState_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputSetStateEx");
74+
if (!PPSSPP_XInputSetState) {
75+
PPSSPP_XInputSetState = (XInputSetState_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputSetState");
76+
}
77+
78+
if (!PPSSPP_XInputSetState) {
79+
UnloadXInputDLL();
80+
return -1;
81+
}
82+
6883
return 0;
6984
}
7085

@@ -81,6 +96,7 @@ static void UnloadXInputDLL() {
8196
static int LoadXInputDLL() { return 0; }
8297
static void UnloadXInputDLL() {}
8398
#define PPSSPP_XInputGetState XInputGetState
99+
#define PPSSPP_XInputSetState XInputSetState
84100
#endif
85101

86102
#ifndef XUSER_MAX_COUNT
@@ -231,11 +247,13 @@ int XinputDevice::UpdateState() {
231247
for (int i = 0; i < XUSER_MAX_COUNT; i++) {
232248
XINPUT_STATE state;
233249
ZeroMemory(&state, sizeof(XINPUT_STATE));
250+
XINPUT_VIBRATION vibration;
251+
ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION));
234252
if (check_delay[i]-- > 0)
235253
continue;
236254
DWORD dwResult = PPSSPP_XInputGetState(i, &state);
237255
if (dwResult == ERROR_SUCCESS) {
238-
UpdatePad(i, state);
256+
UpdatePad(i, state, vibration);
239257
anySuccess = true;
240258
} else {
241259
check_delay[i] = 30;
@@ -247,13 +265,14 @@ int XinputDevice::UpdateState() {
247265
return anySuccess ? UPDATESTATE_SKIP_PAD : 0;
248266
}
249267

250-
void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state) {
268+
void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATION &vibration) {
251269
static bool notified = false;
252270
if (!notified) {
253271
notified = true;
254272
KeyMap::NotifyPadConnected("Xbox 360 Pad");
255273
}
256274
ApplyButtons(pad, state);
275+
ApplyVibration(pad, vibration);
257276

258277
const float STICK_DEADZONE = g_Config.fXInputAnalogDeadzone;
259278
const int STICK_INV_MODE = g_Config.iXInputAnalogInverseMode;
@@ -338,3 +357,21 @@ void XinputDevice::ApplyButtons(int pad, const XINPUT_STATE &state) {
338357
}
339358
}
340359
}
360+
361+
362+
void XinputDevice::ApplyVibration(int pad, XINPUT_VIBRATION &vibration) {
363+
if (PSP_IsInited()) {
364+
vibration.wLeftMotorSpeed = GetLeftVibration(); // use any value between 0-65535 here
365+
vibration.wRightMotorSpeed = GetRightVibration(); // use any value between 0-65535 here
366+
if (prevVibration[pad].wLeftMotorSpeed != vibration.wLeftMotorSpeed || prevVibration[pad].wRightMotorSpeed != vibration.wRightMotorSpeed) {
367+
PPSSPP_XInputSetState(pad, &vibration);
368+
prevVibration[pad] = vibration;
369+
}
370+
} else {
371+
DWORD dwResult = PPSSPP_XInputSetState(pad, &vibration);
372+
if (dwResult != ERROR_SUCCESS) {
373+
check_delay[pad] = 30;
374+
}
375+
}
376+
}
377+

Windows/XinputDevice.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include "InputDevice.h"
44
#include "Xinput.h"
5-
5+
#include "Core/HLE/sceCtrl.h"
66

77
class XinputDevice final : public InputDevice {
88
public:
@@ -11,9 +11,12 @@ class XinputDevice final : public InputDevice {
1111
virtual int UpdateState() override;
1212

1313
private:
14-
void UpdatePad(int pad, const XINPUT_STATE &state);
14+
void UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATION &vibration);
1515
void ApplyButtons(int pad, const XINPUT_STATE &state);
16+
void ApplyVibration(int pad, XINPUT_VIBRATION &vibration);
1617
int check_delay[4]{};
1718
XINPUT_STATE prevState[4]{};
19+
XINPUT_VIBRATION prevVibration[4]{};
20+
1821
u32 prevButtons[4]{};
1922
};

0 commit comments

Comments
 (0)