From 2cddf48cdebda1a6da4fcb9c8cb1e99ec83e5b82 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 16 Sep 2010 05:09:29 +0000 Subject: [PATCH] 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 --- .../DInput/DInputJoystick.cpp | 147 ++++++++++++------ .../DInput/DInputJoystick.h | 18 ++- 2 files changed, 112 insertions(+), 53 deletions(-) diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp index 321555559f..720f41b2d3 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp @@ -10,20 +10,25 @@ namespace ciface namespace DInput { +// template instantiation +template class Joystick::Force; +template class Joystick::Force; +template class Joystick::Force; + 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::iterator i = m_state_out.begin(), + std::vector::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 +std::string Joystick::Force

::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 = ¶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 +Joystick::Force

::Force(const unsigned int index, const unsigned int type) + : m_index(index), m_type(type) +{ + ZeroMemory(¶ms, sizeof(params)); } } diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h index 452e2e5e87..35faf2ee95 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h +++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h @@ -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 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 ForceConstant; + typedef Force ForceRamp; + typedef Force ForcePeriodic; bool UpdateInput(); bool UpdateOutput();