GCPad/Wiimote New (ControllerInterface): Some tweaks to the DirectInput code. (fix for a random gamepad which didn't work)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6159 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak 2010-09-02 00:03:25 +00:00
parent 9e17007c90
commit 7afd393acb
2 changed files with 111 additions and 69 deletions

View File

@ -10,6 +10,25 @@ namespace ciface
namespace DInput namespace DInput
{ {
static const struct
{
GUID guid;
const char* name;
} force_type_names[] =
{
{GUID_ConstantForce, "Constant"},
{GUID_RampForce, "Ramp"},
{GUID_Square, "Square"},
{GUID_Sine, "Sine"},
{GUID_Triangle, "Triangle"},
{GUID_SawtoothUp, "SawtoothUp"},
{GUID_SawtoothDown, "SawtoothDown"},
//{GUID_Spring, "Spring"},
//{GUID_Damper, "Damper"},
//{GUID_Inertia, "Inertia"},
//{GUID_Friction, "Friction"},
};
#define DATA_BUFFER_SIZE 32 #define DATA_BUFFER_SIZE 32
#ifdef NO_DUPLICATE_DINPUT_XINPUT #ifdef NO_DUPLICATE_DINPUT_XINPUT
@ -182,38 +201,36 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
, m_index(index) , m_index(index)
//, m_name(TStringToString(lpddi->tszInstanceName)) //, m_name(TStringToString(lpddi->tszInstanceName))
{ {
// this needs to be done before GetCapabilities() maybe?
m_device->Acquire();
// get joystick caps // get joystick caps
DIDEVCAPS js_caps; DIDEVCAPS js_caps;
ZeroMemory( &js_caps, sizeof(js_caps) );
js_caps.dwSize = sizeof(js_caps); js_caps.dwSize = sizeof(js_caps);
m_device->GetCapabilities(&js_caps); if (FAILED(m_device->GetCapabilities(&js_caps)))
return;
// max of 32 buttons and 4 hats / the limit of the data format i am using // max of 32 buttons and 4 hats / the limit of the data format i am using
js_caps.dwButtons = std::min((DWORD)32, js_caps.dwButtons); js_caps.dwButtons = std::min((DWORD)32, js_caps.dwButtons);
js_caps.dwPOVs = std::min((DWORD)4, js_caps.dwPOVs); js_caps.dwPOVs = std::min((DWORD)4, js_caps.dwPOVs);
//m_must_poll = (js_caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0;
// polled or buffered data // polled or buffered data
m_must_poll = (js_caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0;
if (false == m_must_poll)
{
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = DATA_BUFFER_SIZE; dipdw.dwData = DATA_BUFFER_SIZE;
// set the buffer size, // set the buffer size,
// if we can't set the property, we can't use buffered data, // if we can't set the property, we can't use buffered data
// must use polling, which apparently doesn't work as well m_buffered = SUCCEEDED(m_device->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph));
m_must_poll = (DI_OK != m_device->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph));
}
m_device->Acquire();
// buttons // buttons
for ( unsigned int i = 0; i < js_caps.dwButtons; ++i ) for ( unsigned int i = 0; i < js_caps.dwButtons; ++i )
AddInput( new Button( i ) ); AddInput( new Button( i ) );
// hats // hats
for ( unsigned int i = 0; i < js_caps.dwPOVs; ++i ) for ( unsigned int i = 0; i < js_caps.dwPOVs; ++i )
{ {
@ -221,15 +238,16 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
for ( unsigned int d = 0; d<4; ++d ) for ( unsigned int d = 0; d<4; ++d )
AddInput( new Hat( i, d ) ); AddInput( new Hat( i, d ) );
} }
// get up to 6 axes and 2 sliders // get up to 6 axes and 2 sliders
// screw EnumObjects, just go through all the axis offsets and try to GetProperty
// this should be more foolproof, less code, and probably faster
for (unsigned int offset = 0; offset < DIJOFS_BUTTON(0) / sizeof(LONG); ++offset)
{
DIPROPRANGE range; DIPROPRANGE range;
range.diph.dwSize = sizeof(range); range.diph.dwSize = sizeof(range);
range.diph.dwHeaderSize = sizeof(range.diph); range.diph.dwHeaderSize = sizeof(range.diph);
range.diph.dwHow = DIPH_BYOFFSET; range.diph.dwHow = DIPH_BYOFFSET;
// screw EnumObjects, just go through all the axis offsets and try to GetProperty
// this should be more foolproof, less code, and probably faster
for (unsigned int offset = 0; offset < DIJOFS_BUTTON(0) / sizeof(LONG); ++offset)
{
range.diph.dwObj = offset * sizeof(LONG); range.diph.dwObj = offset * sizeof(LONG);
// try to set some nice power of 2 values (8192) // try to set some nice power of 2 values (8192)
range.lMin = -(1 << 13); range.lMin = -(1 << 13);
@ -247,6 +265,8 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
} }
} }
// TODO: check for DIDC_FORCEFEEDBACK in devcaps?
// get supported ff effects // get supported ff effects
std::list<DIDEVICEOBJECTINSTANCE> objects; std::list<DIDEVICEOBJECTINSTANCE> objects;
m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS); m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS);
@ -256,28 +276,40 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
// temporary // temporary
DWORD rgdwAxes[] = {DIJOFS_X, DIJOFS_Y}; DWORD rgdwAxes[] = {DIJOFS_X, DIJOFS_Y};
LONG rglDirection[] = {0, 0}; LONG rglDirection[] = {0, 0};
DICONSTANTFORCE cf = { 0 };
DIEFFECT eff; DIEFFECT eff;
ZeroMemory(&eff, sizeof(DIEFFECT));
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;
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
DICONSTANTFORCE cf = {0};
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
eff.lpvTypeSpecificParams = &cf; eff.lpvTypeSpecificParams = &cf;
LPDIRECTINPUTEFFECT pEffect; for (unsigned int f = 0, i = 0; f < sizeof(force_type_names)/sizeof(*force_type_names); ++f)
if (SUCCEEDED(m_device->CreateEffect(GUID_ConstantForce, &eff, &pEffect, NULL)))
{ {
// temp // TODO: diff specific params for different effect types
AddOutput( new Force( 0 ) ); //eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
//eff.lpvTypeSpecificParams = &cf;
LPDIRECTINPUTEFFECT pEffect;
if (SUCCEEDED(m_device->CreateEffect(force_type_names[f].guid, &eff, &pEffect, NULL)))
{
AddOutput(new Force(i++, f));
m_state_out.push_back(EffectState(pEffect)); m_state_out.push_back(EffectState(pEffect));
} }
} }
}
// disable autocentering // disable autocentering
if (Outputs().size()) if (Outputs().size())
@ -297,7 +329,8 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
Joystick::~Joystick() Joystick::~Joystick()
{ {
// release the ff effect iface's // release the ff effect iface's
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)
{ {
@ -338,21 +371,16 @@ bool Joystick::UpdateInput()
{ {
HRESULT hr = 0; HRESULT hr = 0;
if (m_must_poll) // just always poll,
{ // msdn says if this isn't needed it doesnt do anything
m_device->Poll(); m_device->Poll();
hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in);
} bool need_ = true;
else
if (m_buffered)
{ {
DIDEVICEOBJECTDATA evtbuf[DATA_BUFFER_SIZE]; DIDEVICEOBJECTDATA evtbuf[DATA_BUFFER_SIZE];
DWORD numevents; DWORD numevents = DATA_BUFFER_SIZE;
//DWORD wantevents = INFINITE;
//hr = m_device->GetDeviceData(sizeof(*evtbuf), NULL, &wantevents, DIGDD_PEEK);
GETDEVDATA :
numevents = DATA_BUFFER_SIZE;
hr = m_device->GetDeviceData(sizeof(*evtbuf), evtbuf, &numevents, 0); hr = m_device->GetDeviceData(sizeof(*evtbuf), evtbuf, &numevents, 0);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -367,14 +395,15 @@ GETDEVDATA :
((BYTE*)&m_state_in)[evt->dwOfs] = (BYTE)evt->dwData; ((BYTE*)&m_state_in)[evt->dwOfs] = (BYTE)evt->dwData;
} }
// if there is more data to be received // we lost some data, attempt to use GetDeviceState
// it seems like to me this could cause problems, // maybe this isn't the best thing to do
// if the device was producing so many events that GetDeviceData always returned bufferoverflow // maybe I should clear the input state?
// it seems to be working fine tho
if (DI_BUFFEROVERFLOW == hr) if (DI_BUFFEROVERFLOW == hr)
goto GETDEVDATA; hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in);
} }
} }
else
hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in);
// try reacquire if input lost // try reacquire if input lost
if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr) if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr)
@ -394,9 +423,22 @@ bool Joystick::UpdateOutput()
if (i->changed) if (i->changed)
{ {
i->changed = false; i->changed = false;
// TODO: this only works for constant force
DICONSTANTFORCE cf; DICONSTANTFORCE cf;
cf.lMagnitude = LONG(10000 * i->magnitude); 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 (cf.lMagnitude)
{ {
DIEFFECT eff; DIEFFECT eff;
@ -455,8 +497,7 @@ std::string Joystick::Hat::GetName() const
std::string Joystick::Force::GetName() const std::string Joystick::Force::GetName() const
{ {
// temporary return force_type_names[m_type].name;
return "Constant";
} }
// get / set state // get / set state

View File

@ -98,10 +98,11 @@ protected:
public: public:
std::string GetName() const; std::string GetName() const;
protected: protected:
Force( const unsigned int index ) : m_index(index) {} Force(const unsigned int index, const unsigned int type) : m_index(index), m_type(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;
}; };
bool UpdateInput(); bool UpdateInput();
@ -128,7 +129,7 @@ private:
DIJOYSTATE m_state_in; DIJOYSTATE m_state_in;
std::vector<EffectState> m_state_out; std::vector<EffectState> m_state_out;
bool m_must_poll; bool m_buffered;
}; };
} }