ControllerInterface: DirectInput: Added support for Ramp and various Periodic force types. Only Constant forces were supported prior. (only partially tested due to lack of hardware) This may improve performance for those experiencing emulated wiimote slowdowns when using DInput rumble.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6212 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
7824855116
commit
2cddf48cde
|
@ -10,20 +10,25 @@ namespace ciface
|
||||||
namespace DInput
|
namespace DInput
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// template instantiation
|
||||||
|
template class Joystick::Force<DICONSTANTFORCE>;
|
||||||
|
template class Joystick::Force<DIRAMPFORCE>;
|
||||||
|
template class Joystick::Force<DIPERIODIC>;
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
{
|
{
|
||||||
GUID guid;
|
GUID guid;
|
||||||
const char* name;
|
const char* name;
|
||||||
} force_type_names[] =
|
} force_type_names[] =
|
||||||
{
|
{
|
||||||
{GUID_ConstantForce, "Constant"},
|
{GUID_ConstantForce, "Constant"}, // DICONSTANTFORCE
|
||||||
{GUID_RampForce, "Ramp"},
|
{GUID_RampForce, "Ramp"}, // DIRAMPFORCE
|
||||||
{GUID_Square, "Square"},
|
{GUID_Square, "Square"}, // DIPERIODIC ...
|
||||||
{GUID_Sine, "Sine"},
|
{GUID_Sine, "Sine"},
|
||||||
{GUID_Triangle, "Triangle"},
|
{GUID_Triangle, "Triangle"},
|
||||||
{GUID_SawtoothUp, "SawtoothUp"},
|
{GUID_SawtoothUp, "SawtoothUp"},
|
||||||
{GUID_SawtoothDown, "SawtoothDown"},
|
{GUID_SawtoothDown, "SawtoothDown"},
|
||||||
//{GUID_Spring, "Spring"},
|
//{GUID_Spring, "Spring"}, // DIEFT_CUSTOMFORCE ... < i think
|
||||||
//{GUID_Damper, "Damper"},
|
//{GUID_Damper, "Damper"},
|
||||||
//{GUID_Inertia, "Inertia"},
|
//{GUID_Inertia, "Inertia"},
|
||||||
//{GUID_Friction, "Friction"},
|
//{GUID_Friction, "Friction"},
|
||||||
|
@ -278,34 +283,49 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
||||||
LONG rglDirection[] = {0, 0};
|
LONG rglDirection[] = {0, 0};
|
||||||
|
|
||||||
DIEFFECT eff;
|
DIEFFECT eff;
|
||||||
|
ZeroMemory(&eff, sizeof(eff));
|
||||||
eff.dwSize = sizeof(DIEFFECT);
|
eff.dwSize = sizeof(DIEFFECT);
|
||||||
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
||||||
eff.dwDuration = INFINITE;
|
eff.dwDuration = INFINITE; // (4 * DI_SECONDS)
|
||||||
eff.dwSamplePeriod = 0;
|
|
||||||
eff.dwGain = DI_FFNOMINALMAX;
|
eff.dwGain = DI_FFNOMINALMAX;
|
||||||
eff.dwTriggerButton = DIEB_NOTRIGGER;
|
eff.dwTriggerButton = DIEB_NOTRIGGER;
|
||||||
eff.dwTriggerRepeatInterval = 0;
|
|
||||||
eff.cAxes = std::min((DWORD)2, (DWORD)objects.size());
|
eff.cAxes = std::min((DWORD)2, (DWORD)objects.size());
|
||||||
eff.rgdwAxes = rgdwAxes;
|
eff.rgdwAxes = rgdwAxes;
|
||||||
eff.rglDirection = rglDirection;
|
eff.rglDirection = rglDirection;
|
||||||
eff.lpEnvelope = NULL;
|
|
||||||
eff.dwStartDelay = 0;
|
|
||||||
|
|
||||||
// TODO: this only works for Constant force
|
// DIPERIODIC is the largest, so we'll use that
|
||||||
DICONSTANTFORCE cf = {0};
|
DIPERIODIC f;
|
||||||
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
eff.lpvTypeSpecificParams = &f;
|
||||||
eff.lpvTypeSpecificParams = &cf;
|
ZeroMemory(&f, sizeof(f));
|
||||||
|
|
||||||
|
// doesn't seem needed
|
||||||
|
//DIENVELOPE env;
|
||||||
|
//eff.lpEnvelope = &env;
|
||||||
|
//ZeroMemory(&env, sizeof(env));
|
||||||
|
//env.dwSize = sizeof(env);
|
||||||
|
|
||||||
for (unsigned int f = 0, i = 0; f < sizeof(force_type_names)/sizeof(*force_type_names); ++f)
|
for (unsigned int f = 0, i = 0; f < sizeof(force_type_names)/sizeof(*force_type_names); ++f)
|
||||||
{
|
{
|
||||||
// TODO: diff specific params for different effect types
|
// ugly if ladder
|
||||||
//eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
|
if (0 == f)
|
||||||
//eff.lpvTypeSpecificParams = &cf;
|
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
||||||
|
else if (1 == f)
|
||||||
|
eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
|
||||||
|
else
|
||||||
|
eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
|
||||||
|
|
||||||
LPDIRECTINPUTEFFECT pEffect;
|
LPDIRECTINPUTEFFECT pEffect;
|
||||||
if (SUCCEEDED(m_device->CreateEffect(force_type_names[f].guid, &eff, &pEffect, NULL)))
|
if (SUCCEEDED(m_device->CreateEffect(force_type_names[f].guid, &eff, &pEffect, NULL)))
|
||||||
{
|
{
|
||||||
AddOutput(new Force(i++, f));
|
// ugly if ladder again :/
|
||||||
|
if (0 == f)
|
||||||
|
AddOutput(new ForceConstant(i, f));
|
||||||
|
else if (1 == f)
|
||||||
|
AddOutput(new ForceRamp(i, f));
|
||||||
|
else
|
||||||
|
AddOutput(new ForcePeriodic(i, f));
|
||||||
|
|
||||||
|
++i;
|
||||||
m_state_out.push_back(EffectState(pEffect));
|
m_state_out.push_back(EffectState(pEffect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,50 +434,35 @@ bool Joystick::UpdateInput()
|
||||||
|
|
||||||
bool Joystick::UpdateOutput()
|
bool Joystick::UpdateOutput()
|
||||||
{
|
{
|
||||||
// temporary
|
|
||||||
size_t ok_count = 0;
|
size_t ok_count = 0;
|
||||||
std::vector<EffectState>::iterator i = m_state_out.begin(),
|
std::vector<EffectState>::iterator
|
||||||
|
i = m_state_out.begin(),
|
||||||
e = m_state_out.end();
|
e = m_state_out.end();
|
||||||
for (; i!=e; ++i)
|
for (; i!=e; ++i)
|
||||||
{
|
{
|
||||||
if (i->changed)
|
if (i->params)
|
||||||
{
|
{
|
||||||
i->changed = false;
|
if (i->size)
|
||||||
|
|
||||||
// TODO: this only works for constant force
|
|
||||||
DICONSTANTFORCE cf;
|
|
||||||
cf.lMagnitude = LONG(10000 * i->magnitude);
|
|
||||||
|
|
||||||
// TODO: different specific params for different effect types
|
|
||||||
//DIPERIODIC pf;
|
|
||||||
//pf.dwMagnitude = LONG(10000 * i->magnitude);
|
|
||||||
//pf.lOffset = 0;
|
|
||||||
//pf.dwPhase = 0;
|
|
||||||
//pf.dwPeriod = 0;
|
|
||||||
|
|
||||||
//DIRAMPFORCE rf;
|
|
||||||
//rf.lStart = LONG(10000 * i->magnitude);
|
|
||||||
//rf.lEnd = 0;
|
|
||||||
|
|
||||||
if (cf.lMagnitude)
|
|
||||||
{
|
{
|
||||||
DIEFFECT eff;
|
DIEFFECT eff;
|
||||||
ZeroMemory( &eff, sizeof(eff));
|
ZeroMemory(&eff, sizeof(eff));
|
||||||
eff.dwSize = sizeof(DIEFFECT);
|
eff.dwSize = sizeof(DIEFFECT);
|
||||||
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
||||||
eff.cbTypeSpecificParams = sizeof(cf);
|
eff.cbTypeSpecificParams = i->size;
|
||||||
eff.lpvTypeSpecificParams = &cf;
|
eff.lpvTypeSpecificParams = i->params;
|
||||||
// set params and start effect
|
// set params and start effect
|
||||||
ok_count += SUCCEEDED(i->iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START));
|
ok_count += SUCCEEDED(i->iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ok_count += SUCCEEDED(i->iface->Stop());
|
ok_count += SUCCEEDED(i->iface->Stop());
|
||||||
|
|
||||||
|
i->params = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++ok_count;
|
++ok_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( m_state_out.size() == ok_count );
|
return (m_state_out.size() == ok_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get name
|
// get name
|
||||||
|
@ -495,7 +500,8 @@ std::string Joystick::Hat::GetName() const
|
||||||
return tmpstr;
|
return tmpstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Joystick::Force::GetName() const
|
template <typename P>
|
||||||
|
std::string Joystick::Force<P>::GetName() const
|
||||||
{
|
{
|
||||||
return force_type_names[m_type].name;
|
return force_type_names[m_type].name;
|
||||||
}
|
}
|
||||||
|
@ -534,10 +540,57 @@ ControlState Joystick::Hat::GetState( const DIJOYSTATE* const joystate ) const
|
||||||
return ( abs( (int)(val/4500-m_direction*2+8)%8 - 4) > 2 );
|
return ( abs( (int)(val/4500-m_direction*2+8)%8 - 4) > 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joystick::Force::SetState( const ControlState state, Joystick::EffectState* const joystate )
|
void Joystick::ForceConstant::SetState(const ControlState state, Joystick::EffectState* const joystate)
|
||||||
{
|
{
|
||||||
joystate[m_index].magnitude = state;
|
const LONG new_val = LONG(10000 * state);
|
||||||
joystate[m_index].changed = true;
|
|
||||||
|
LONG &val = params.lMagnitude;
|
||||||
|
if (val != new_val)
|
||||||
|
{
|
||||||
|
val = new_val;
|
||||||
|
joystate[m_index].params = ¶ms; // tells UpdateOutput the state has changed
|
||||||
|
|
||||||
|
// tells UpdateOutput to either start or stop the force
|
||||||
|
joystate[m_index].size = new_val ? sizeof(params) : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Joystick::ForceRamp::SetState(const ControlState state, Joystick::EffectState* const joystate)
|
||||||
|
{
|
||||||
|
const LONG new_val = LONG(10000 * state);
|
||||||
|
|
||||||
|
if (params.lStart != new_val)
|
||||||
|
{
|
||||||
|
params.lStart = params.lEnd = new_val;
|
||||||
|
joystate[m_index].params = ¶ms; // tells UpdateOutput the state has changed
|
||||||
|
|
||||||
|
// tells UpdateOutput to either start or stop the force
|
||||||
|
joystate[m_index].size = new_val ? sizeof(params) : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Joystick::ForcePeriodic::SetState(const ControlState state, Joystick::EffectState* const joystate)
|
||||||
|
{
|
||||||
|
const LONG new_val = LONG(10000 * state);
|
||||||
|
|
||||||
|
DWORD &val = params.dwMagnitude;
|
||||||
|
if (val != new_val)
|
||||||
|
{
|
||||||
|
val = new_val;
|
||||||
|
//params.dwPeriod = 0;//DWORD(0.05 * DI_SECONDS); // zero is working fine for me
|
||||||
|
|
||||||
|
joystate[m_index].params = ¶ms; // tells UpdateOutput the state has changed
|
||||||
|
|
||||||
|
// tells UpdateOutput to either start or stop the force
|
||||||
|
joystate[m_index].size = new_val ? sizeof(params) : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
Joystick::Force<P>::Force(const unsigned int index, const unsigned int type)
|
||||||
|
: m_index(index), m_type(type)
|
||||||
|
{
|
||||||
|
ZeroMemory(¶ms, sizeof(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,11 @@ protected:
|
||||||
|
|
||||||
struct EffectState
|
struct EffectState
|
||||||
{
|
{
|
||||||
EffectState( LPDIRECTINPUTEFFECT eff ) : changed(0), iface(eff) {}
|
EffectState(LPDIRECTINPUTEFFECT eff) : iface(eff), params(NULL), size(0) {}
|
||||||
|
|
||||||
LPDIRECTINPUTEFFECT iface;
|
LPDIRECTINPUTEFFECT iface;
|
||||||
ControlState magnitude;
|
void* params; // null when force hasn't changed
|
||||||
bool changed;
|
u8 size; // zero when force should stop
|
||||||
};
|
};
|
||||||
|
|
||||||
class Input : public ControllerInterface::Device::Input
|
class Input : public ControllerInterface::Device::Input
|
||||||
|
@ -92,18 +93,23 @@ protected:
|
||||||
const unsigned int m_direction;
|
const unsigned int m_direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
class Force : public Output
|
class Force : public Output
|
||||||
{
|
{
|
||||||
friend class Joystick;
|
friend class Joystick;
|
||||||
public:
|
public:
|
||||||
std::string GetName() const;
|
std::string GetName() const;
|
||||||
protected:
|
protected:
|
||||||
Force(const unsigned int index, const unsigned int type) : m_index(index), m_type(type) {}
|
Force(const unsigned int index, const unsigned int type);
|
||||||
void SetState( const ControlState state, EffectState* const joystate );
|
void SetState(const ControlState state, EffectState* const joystate);
|
||||||
private:
|
private:
|
||||||
const unsigned int m_index;
|
const unsigned int m_index;
|
||||||
const unsigned int m_type;
|
const unsigned int m_type;
|
||||||
|
P params;
|
||||||
};
|
};
|
||||||
|
typedef Force<DICONSTANTFORCE> ForceConstant;
|
||||||
|
typedef Force<DIRAMPFORCE> ForceRamp;
|
||||||
|
typedef Force<DIPERIODIC> ForcePeriodic;
|
||||||
|
|
||||||
bool UpdateInput();
|
bool UpdateInput();
|
||||||
bool UpdateOutput();
|
bool UpdateOutput();
|
||||||
|
|
Loading…
Reference in New Issue