ForceFeedback: Apply immediately as well

This commit is contained in:
Jasper St. Pierre 2014-11-13 01:27:26 -08:00
parent 1958a10b6f
commit 86e4da2c07
2 changed files with 52 additions and 80 deletions

View File

@ -38,17 +38,6 @@ static const ForceType force_type_names[] =
//{GUID_Friction, "Friction"}, //{GUID_Friction, "Friction"},
}; };
ForceFeedbackDevice::~ForceFeedbackDevice()
{
// release the ff effect iface's
for (EffectState& state : m_state_out)
{
state.iface->Stop();
state.iface->Unload();
state.iface->Release();
}
}
bool ForceFeedbackDevice::InitForceFeedback(const LPDIRECTINPUTDEVICE8 device, int cAxes) bool ForceFeedbackDevice::InitForceFeedback(const LPDIRECTINPUTDEVICE8 device, int cAxes)
{ {
if (cAxes == 0) if (cAxes == 0)
@ -107,14 +96,12 @@ bool ForceFeedbackDevice::InitForceFeedback(const LPDIRECTINPUTDEVICE8 device, i
LPDIRECTINPUTEFFECT pEffect; LPDIRECTINPUTEFFECT pEffect;
if (SUCCEEDED(device->CreateEffect(f.guid, &eff, &pEffect, nullptr))) if (SUCCEEDED(device->CreateEffect(f.guid, &eff, &pEffect, nullptr)))
{ {
m_state_out.push_back(EffectState(pEffect));
if (f.guid == GUID_ConstantForce) if (f.guid == GUID_ConstantForce)
AddOutput(new ForceConstant(f.name, m_state_out.back())); AddOutput(new ForceConstant(f.name, pEffect));
else if (f.guid == GUID_RampForce) else if (f.guid == GUID_RampForce)
AddOutput(new ForceRamp(f.name, m_state_out.back())); AddOutput(new ForceRamp(f.name, pEffect));
else else
AddOutput(new ForcePeriodic(f.name, m_state_out.back())); AddOutput(new ForcePeriodic(f.name, pEffect));
} }
} }
@ -133,32 +120,32 @@ bool ForceFeedbackDevice::InitForceFeedback(const LPDIRECTINPUTDEVICE8 device, i
return true; return true;
} }
void ForceFeedbackDevice::UpdateOutput() template<typename P>
ForceFeedbackDevice::Force<P>::~Force()
{ {
DIEFFECT eff; m_iface->Stop();
memset(&eff, 0, sizeof(eff)); m_iface->Unload();
m_iface->Release();
}
template<typename P>
void ForceFeedbackDevice::Force<P>::Update()
{
DIEFFECT eff = {};
eff.dwSize = sizeof(DIEFFECT); eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
for (EffectState& state : m_state_out) eff.cbTypeSpecificParams = sizeof(P);
{ eff.lpvTypeSpecificParams = &params;
if (state.params)
{
if (state.size)
{
eff.cbTypeSpecificParams = state.size;
eff.lpvTypeSpecificParams = state.params;
// set params and start effect
state.iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START);
}
else
{
state.iface->Stop();
}
state.params = nullptr; // set params and start effect
} m_iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START);
} }
template<typename P>
void ForceFeedbackDevice::Force<P>::Stop()
{
m_iface->Stop();
} }
template<> template<>
@ -166,15 +153,14 @@ void ForceFeedbackDevice::ForceConstant::SetState(const ControlState state)
{ {
const LONG new_val = LONG(10000 * state); const LONG new_val = LONG(10000 * state);
LONG &val = params.lMagnitude; if (params.lMagnitude == new_val)
if (val != new_val) return;
{
val = new_val;
m_state.params = &params; // tells UpdateOutput the state has changed
// tells UpdateOutput to either start or stop the force params.lMagnitude = new_val;
m_state.size = new_val ? sizeof(params) : 0; if (new_val)
} Update();
else
Stop();
} }
template<> template<>
@ -182,14 +168,14 @@ void ForceFeedbackDevice::ForceRamp::SetState(const ControlState state)
{ {
const LONG new_val = LONG(10000 * state); const LONG new_val = LONG(10000 * state);
if (params.lStart != new_val) if (params.lStart == new_val)
{ return;
params.lStart = params.lEnd = new_val;
m_state.params = &params; // tells UpdateOutput the state has changed
// tells UpdateOutput to either start or stop the force params.lStart = params.lEnd = new_val;
m_state.size = new_val ? sizeof(params) : 0; if (new_val)
} Update();
else
Stop();
} }
template<> template<>
@ -197,22 +183,19 @@ void ForceFeedbackDevice::ForcePeriodic::SetState(const ControlState state)
{ {
const DWORD new_val = DWORD(10000 * state); const DWORD new_val = DWORD(10000 * state);
DWORD &val = params.dwMagnitude; if (params.dwMagnitude == new_val)
if (val != new_val) return;
{
val = new_val;
//params.dwPeriod = 0;//DWORD(0.05 * DI_SECONDS); // zero is working fine for me
m_state.params = &params; // tells UpdateOutput the state has changed params.dwMagnitude = new_val;
if (new_val)
// tells UpdateOutput to either start or stop the force Update();
m_state.size = new_val ? sizeof(params) : 0; else
} Stop();
} }
template <typename P> template <typename P>
ForceFeedbackDevice::Force<P>::Force(const std::string& name, EffectState& state) ForceFeedbackDevice::Force<P>::Force(const std::string& name, LPDIRECTINPUTEFFECT iface)
: m_name(name), m_state(state) : m_name(name), m_iface(iface)
{ {
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
} }

View File

@ -25,25 +25,19 @@ namespace ForceFeedback
class ForceFeedbackDevice : public Core::Device class ForceFeedbackDevice : public Core::Device
{ {
private: private:
struct EffectState
{
EffectState(LPDIRECTINPUTEFFECT eff) : iface(eff), params(nullptr), size(0) {}
LPDIRECTINPUTEFFECT iface;
void* params; // null when force hasn't changed
u8 size; // zero when force should stop
};
template <typename P> template <typename P>
class Force : public Output class Force : public Output
{ {
public: public:
std::string GetName() const; std::string GetName() const;
Force(const std::string& name, EffectState& state); Force(const std::string& name, LPDIRECTINPUTEFFECT iface);
~Force();
void SetState(ControlState state); void SetState(ControlState state);
void Update();
void Stop();
private: private:
const std::string m_name; const std::string m_name;
EffectState& m_state; LPDIRECTINPUTEFFECT m_iface;
P params; P params;
}; };
typedef Force<DICONSTANTFORCE> ForceConstant; typedef Force<DICONSTANTFORCE> ForceConstant;
@ -52,11 +46,6 @@ private:
public: public:
bool InitForceFeedback(const LPDIRECTINPUTDEVICE8, int cAxes); bool InitForceFeedback(const LPDIRECTINPUTDEVICE8, int cAxes);
void UpdateOutput() override;
virtual ~ForceFeedbackDevice();
private:
std::list<EffectState> m_state_out;
}; };