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:
Jordan Woyak 2010-09-16 05:09:29 +00:00
parent 7824855116
commit 2cddf48cde
2 changed files with 112 additions and 53 deletions

View File

@ -10,20 +10,25 @@ namespace ciface
namespace DInput
{
// template instantiation
template class Joystick::Force<DICONSTANTFORCE>;
template class Joystick::Force<DIRAMPFORCE>;
template class Joystick::Force<DIPERIODIC>;
static const struct
{
GUID guid;
const char* name;
} force_type_names[] =
{
{GUID_ConstantForce, "Constant"},
{GUID_RampForce, "Ramp"},
{GUID_Square, "Square"},
{GUID_ConstantForce, "Constant"}, // DICONSTANTFORCE
{GUID_RampForce, "Ramp"}, // DIRAMPFORCE
{GUID_Square, "Square"}, // DIPERIODIC ...
{GUID_Sine, "Sine"},
{GUID_Triangle, "Triangle"},
{GUID_SawtoothUp, "SawtoothUp"},
{GUID_SawtoothDown, "SawtoothDown"},
//{GUID_Spring, "Spring"},
//{GUID_Spring, "Spring"}, // DIEFT_CUSTOMFORCE ... < i think
//{GUID_Damper, "Damper"},
//{GUID_Inertia, "Inertia"},
//{GUID_Friction, "Friction"},
@ -278,34 +283,49 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
LONG rglDirection[] = {0, 0};
DIEFFECT eff;
ZeroMemory(&eff, sizeof(eff));
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.dwDuration = INFINITE;
eff.dwSamplePeriod = 0;
eff.dwDuration = INFINITE; // (4 * DI_SECONDS)
eff.dwGain = DI_FFNOMINALMAX;
eff.dwTriggerButton = DIEB_NOTRIGGER;
eff.dwTriggerRepeatInterval = 0;
eff.cAxes = std::min((DWORD)2, (DWORD)objects.size());
eff.rgdwAxes = rgdwAxes;
eff.rglDirection = rglDirection;
eff.lpEnvelope = NULL;
eff.dwStartDelay = 0;
// TODO: this only works for Constant force
DICONSTANTFORCE cf = {0};
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
eff.lpvTypeSpecificParams = &cf;
// DIPERIODIC is the largest, so we'll use that
DIPERIODIC f;
eff.lpvTypeSpecificParams = &f;
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)
{
// TODO: diff specific params for different effect types
//eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
//eff.lpvTypeSpecificParams = &cf;
// ugly if ladder
if (0 == f)
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
else if (1 == f)
eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
else
eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
LPDIRECTINPUTEFFECT pEffect;
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));
}
}
@ -414,50 +434,35 @@ bool Joystick::UpdateInput()
bool Joystick::UpdateOutput()
{
// temporary
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();
for (; i!=e; ++i)
{
if (i->changed)
if (i->params)
{
i->changed = false;
// 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)
if (i->size)
{
DIEFFECT eff;
ZeroMemory( &eff, sizeof(eff));
ZeroMemory(&eff, sizeof(eff));
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.cbTypeSpecificParams = sizeof(cf);
eff.lpvTypeSpecificParams = &cf;
eff.cbTypeSpecificParams = i->size;
eff.lpvTypeSpecificParams = i->params;
// set params and start effect
ok_count += SUCCEEDED(i->iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START));
}
else
ok_count += SUCCEEDED(i->iface->Stop());
i->params = NULL;
}
else
++ok_count;
}
return ( m_state_out.size() == ok_count );
return (m_state_out.size() == ok_count);
}
// get name
@ -495,7 +500,8 @@ std::string Joystick::Hat::GetName() const
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;
}
@ -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 );
}
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;
joystate[m_index].changed = true;
const LONG new_val = LONG(10000 * state);
LONG &val = params.lMagnitude;
if (val != new_val)
{
val = new_val;
joystate[m_index].params = &params; // 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 = &params; // 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 = &params; // 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(&params, sizeof(params));
}
}

View File

@ -32,10 +32,11 @@ protected:
struct EffectState
{
EffectState( LPDIRECTINPUTEFFECT eff ) : changed(0), iface(eff) {}
LPDIRECTINPUTEFFECT iface;
ControlState magnitude;
bool changed;
EffectState(LPDIRECTINPUTEFFECT eff) : iface(eff), params(NULL), size(0) {}
LPDIRECTINPUTEFFECT iface;
void* params; // null when force hasn't changed
u8 size; // zero when force should stop
};
class Input : public ControllerInterface::Device::Input
@ -92,18 +93,23 @@ protected:
const unsigned int m_direction;
};
template <typename P>
class Force : public Output
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Force(const unsigned int index, const unsigned int type) : m_index(index), m_type(type) {}
void SetState( const ControlState state, EffectState* const joystate );
Force(const unsigned int index, const unsigned int type);
void SetState(const ControlState state, EffectState* const joystate);
private:
const unsigned int m_index;
const unsigned int m_type;
P params;
};
typedef Force<DICONSTANTFORCE> ForceConstant;
typedef Force<DIRAMPFORCE> ForceRamp;
typedef Force<DIPERIODIC> ForcePeriodic;
bool UpdateInput();
bool UpdateOutput();