mirror of https://github.com/PCSX2/pcsx2.git
USB: add direct-to-directinput hack for windows for testing
This commit is contained in:
parent
2d5faa627f
commit
6d9b9d44a1
|
@ -195,13 +195,52 @@ namespace usb_pad
|
||||||
if (m_constant_effect_id < 0)
|
if (m_constant_effect_id < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const s16 new_level = static_cast<s16>(std::clamp(level, -32768, 32767));
|
s16 new_level = static_cast<s16>(std::clamp(level, -32768, 32767));
|
||||||
if (m_constant_effect.constant.level != new_level)
|
if (m_constant_effect.constant.level != new_level)
|
||||||
{
|
{
|
||||||
|
#ifdef __WIN32__
|
||||||
|
if (bypass_sdl_when_updating)
|
||||||
|
{
|
||||||
|
new_level = new_level * 10000 / 32767;
|
||||||
|
// TODO: Other force types probably need the same type of attention, but constant forces are
|
||||||
|
// the most sensitive to this issue as they're generally going to be updated the most frequently.
|
||||||
|
|
||||||
|
// DANGER! Reading this code may give you radiation poisoning.
|
||||||
|
// It's ugly, but it works. Ideally SDL would be patched to make this unnecessary,
|
||||||
|
// but if patching SDL proves to be too unwieldy, a cleaned-up version of this
|
||||||
|
// might be appropriate.
|
||||||
|
|
||||||
|
// It's not easy to identify by hand if you're not highly experienced, so I'd recommend
|
||||||
|
// average joes use USBPcap via Wireshark in order to verify whether your approach works.
|
||||||
|
// Try this filter:
|
||||||
|
// usb.src=="host" && usb.data_len!=0 && usbhid.data
|
||||||
|
|
||||||
|
// Steal the raw DirectInput references from SDL and update them directly.
|
||||||
|
// Allows us to set our own flags for SetParameters. This is important because
|
||||||
|
// SDL sends unnecessary flags with its updates, which causes unnecessary HID reports,
|
||||||
|
// which may be causing a loss in detail due to wheels unnecessarily reinitializing
|
||||||
|
// the force.
|
||||||
|
|
||||||
|
// Yeah there's raw C casts, I couldn't figure out how to appease the C++ compiler
|
||||||
|
// when using stl casts before I had to stop working on this
|
||||||
|
_SDL_Haptic* real = (_SDL_Haptic*)(m_haptic);
|
||||||
|
auto ref = real->effects[m_constant_effect_id].hweffect->ref;
|
||||||
|
auto k = (DICONSTANTFORCE*)real->effects[m_constant_effect_id].hweffect->effect.lpvTypeSpecificParams;
|
||||||
|
k->lMagnitude = new_level;
|
||||||
|
ref->SetParameters(&real->effects[m_constant_effect_id].hweffect->effect, DIEP_TYPESPECIFICPARAMS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_constant_effect.constant.level = new_level;
|
m_constant_effect.constant.level = new_level;
|
||||||
if (SDL_HapticUpdateEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0)
|
if (SDL_HapticUpdateEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0)
|
||||||
Console.Warning("SDL_HapticUpdateEffect() for constant failed: %s", SDL_GetError());
|
Console.Warning("SDL_HapticUpdateEffect() for constant failed: %s", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
m_constant_effect.constant.level = new_level;
|
||||||
|
if (SDL_HapticUpdateEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0)
|
||||||
|
Console.Warning("SDL_HapticUpdateEffect() for constant failed: %s", SDL_GetError());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid re-running already-running effects by default. Re-running a running effect
|
// Avoid re-running already-running effects by default. Re-running a running effect
|
||||||
// causes a variety of issues on different wheels, ranging from quality/detail loss,
|
// causes a variety of issues on different wheels, ranging from quality/detail loss,
|
||||||
|
|
|
@ -5,6 +5,51 @@
|
||||||
|
|
||||||
#include "USB/usb-pad/usb-pad.h"
|
#include "USB/usb-pad/usb-pad.h"
|
||||||
#include "Input/SDLInputSource.h"
|
#include "Input/SDLInputSource.h"
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#include <sdl_haptic.h>
|
||||||
|
#include <dinput.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
// Copied some internal structure definitions from SDL's source
|
||||||
|
// in order to scoop out their inner bits that are excluded from
|
||||||
|
// public-facing headers.
|
||||||
|
|
||||||
|
// It's ugly, but it works for the purposes of this hack/PoC
|
||||||
|
|
||||||
|
struct haptic_hweffect
|
||||||
|
{
|
||||||
|
DIEFFECT effect;
|
||||||
|
LPDIRECTINPUTEFFECT ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct haptic_effect
|
||||||
|
{
|
||||||
|
SDL_HapticEffect effect; // The current event
|
||||||
|
struct haptic_hweffect* hweffect; // The hardware behind the event
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _SDL_Haptic
|
||||||
|
{
|
||||||
|
Uint8 index; /* Stores index it is attached to */
|
||||||
|
|
||||||
|
struct haptic_effect* effects; /* Allocated effects */
|
||||||
|
int neffects; /* Maximum amount of effects */
|
||||||
|
int nplaying; /* Maximum amount of effects to play at the same time */
|
||||||
|
unsigned int supported; /* Supported effects */
|
||||||
|
int naxes; /* Number of axes on the device. */
|
||||||
|
|
||||||
|
struct haptic_hwdata* hwdata; /* Driver dependent */
|
||||||
|
int ref_count; /* Count for multiple opens */
|
||||||
|
|
||||||
|
int rumble_id; /* ID of rumble effect for simple rumble API. */
|
||||||
|
SDL_HapticEffect rumble_effect; /* Rumble effect. */
|
||||||
|
struct _SDL_Haptic* next; /* pointer to next haptic we have allocated */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace usb_pad
|
namespace usb_pad
|
||||||
{
|
{
|
||||||
|
|
|
@ -166,6 +166,9 @@ namespace usb_pad
|
||||||
"Off", nullptr, nullptr, nullptr, nullptr, SteeringCurveExponentOptions},
|
"Off", nullptr, nullptr, nullptr, nullptr, SteeringCurveExponentOptions},
|
||||||
{SettingInfo::Type::Boolean, "FfbDropoutWorkaround", TRANSLATE_NOOP("USB", "Workaround for Intermittent FFB Loss"),
|
{SettingInfo::Type::Boolean, "FfbDropoutWorkaround", TRANSLATE_NOOP("USB", "Workaround for Intermittent FFB Loss"),
|
||||||
TRANSLATE_NOOP("USB", "Works around bugs in some wheels' firmware that result in brief interruptions in force. Leave this disabled unless you need it, as it has negative side effects on many wheels."),
|
TRANSLATE_NOOP("USB", "Works around bugs in some wheels' firmware that result in brief interruptions in force. Leave this disabled unless you need it, as it has negative side effects on many wheels."),
|
||||||
|
"false"},
|
||||||
|
{SettingInfo::Type::Boolean, "FfbDirectInputHack", TRANSLATE_NOOP("USB", "HACK: Bypass SDL for FFB updates on Windows"),
|
||||||
|
TRANSLATE_NOOP("USB", "Forgive me, SDL. It's not you, it's me. (It's you). Has no effect on non-Windows platforms."),
|
||||||
"false"}
|
"false"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -234,6 +237,11 @@ namespace usb_pad
|
||||||
const bool use_ffb_dropout_workaround = USB::GetConfigBool(si, port, devname, "FfbDropoutWorkaround", false);
|
const bool use_ffb_dropout_workaround = USB::GetConfigBool(si, port, devname, "FfbDropoutWorkaround", false);
|
||||||
mFFdev->use_ffb_dropout_workaround = use_ffb_dropout_workaround;
|
mFFdev->use_ffb_dropout_workaround = use_ffb_dropout_workaround;
|
||||||
}
|
}
|
||||||
|
if (mFFdev != NULL)
|
||||||
|
{
|
||||||
|
const bool bypass_sdl_when_updating = USB::GetConfigBool(si, port, devname, "FfbDirectInputHack", false);
|
||||||
|
mFFdev->bypass_sdl_when_updating = bypass_sdl_when_updating;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,7 @@ namespace usb_pad
|
||||||
virtual void DisableForce(EffectID force) = 0;
|
virtual void DisableForce(EffectID force) = 0;
|
||||||
|
|
||||||
bool use_ffb_dropout_workaround = false;
|
bool use_ffb_dropout_workaround = false;
|
||||||
|
bool bypass_sdl_when_updating = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PadState
|
struct PadState
|
||||||
|
|
Loading…
Reference in New Issue