mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-26 03:35:26 +00:00
ControllerInterface: Move DInput ForceFeedback support to a seperate class
This commit is contained in:
parent
249b00c469
commit
02a95c139e
@ -12,7 +12,8 @@ if(WIN32)
|
||||
ControllerInterface/DInput/DInputJoystick.cpp
|
||||
ControllerInterface/DInput/DInputKeyboardMouse.cpp
|
||||
ControllerInterface/SDL/SDL.cpp
|
||||
ControllerInterface/XInput/XInput.cpp)
|
||||
ControllerInterface/XInput/XInput.cpp
|
||||
ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(SRCS ${SRCS}
|
||||
ControllerInterface/OSX/OSX.mm
|
||||
|
@ -14,30 +14,6 @@ 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"}, // DICONSTANTFORCE
|
||||
{GUID_RampForce, "Ramp"}, // DIRAMPFORCE
|
||||
{GUID_Square, "Square"}, // DIPERIODIC ...
|
||||
{GUID_Sine, "Sine"},
|
||||
{GUID_Triangle, "Triangle"},
|
||||
{GUID_SawtoothUp, "Sawtooth Up"},
|
||||
{GUID_SawtoothDown, "Sawtooth Down"},
|
||||
//{GUID_Spring, "Spring"}, // DICUSTOMFORCE ... < I think
|
||||
//{GUID_Damper, "Damper"},
|
||||
//{GUID_Inertia, "Inertia"},
|
||||
//{GUID_Friction, "Friction"},
|
||||
};
|
||||
|
||||
#define DATA_BUFFER_SIZE 32
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -267,87 +243,11 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check for DIDC_FORCEFEEDBACK in devcaps?
|
||||
|
||||
// get supported ff effects
|
||||
// force feedback
|
||||
std::list<DIDEVICEOBJECTINSTANCE> objects;
|
||||
m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS);
|
||||
// got some ff axes or something
|
||||
if ( objects.size() )
|
||||
if (SUCCEEDED(m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS)))
|
||||
{
|
||||
// temporary
|
||||
DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y};
|
||||
LONG rglDirection[2] = {-200, 0};
|
||||
|
||||
DIEFFECT eff;
|
||||
ZeroMemory(&eff, sizeof(eff));
|
||||
eff.dwSize = sizeof(DIEFFECT);
|
||||
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
||||
eff.dwDuration = INFINITE; // (4 * DI_SECONDS)
|
||||
eff.dwSamplePeriod = 0;
|
||||
eff.dwGain = DI_FFNOMINALMAX;
|
||||
eff.dwTriggerButton = DIEB_NOTRIGGER;
|
||||
eff.dwTriggerRepeatInterval = 0;
|
||||
eff.cAxes = std::min((DWORD)1, (DWORD)objects.size());
|
||||
eff.rgdwAxes = rgdwAxes;
|
||||
eff.rglDirection = rglDirection;
|
||||
|
||||
// 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; f < sizeof(force_type_names)/sizeof(*force_type_names); ++f)
|
||||
{
|
||||
// ugly if ladder
|
||||
if (0 == f)
|
||||
{
|
||||
DICONSTANTFORCE diCF = {-10000};
|
||||
diCF.lMagnitude = DI_FFNOMINALMAX;
|
||||
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
||||
eff.lpvTypeSpecificParams = &diCF;
|
||||
}
|
||||
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)))
|
||||
{
|
||||
m_state_out.push_back(EffectState(pEffect));
|
||||
|
||||
// ugly if ladder again :/
|
||||
if (0 == f)
|
||||
AddOutput(new ForceConstant(f, m_state_out.back()));
|
||||
else if (1 == f)
|
||||
AddOutput(new ForceRamp(f, m_state_out.back()));
|
||||
else
|
||||
AddOutput(new ForcePeriodic(f, m_state_out.back()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// disable autocentering
|
||||
if (Outputs().size())
|
||||
{
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof( DIPROPDWORD );
|
||||
dipdw.diph.dwHeaderSize = sizeof( DIPROPHEADER );
|
||||
dipdw.diph.dwObj = 0;
|
||||
dipdw.diph.dwHow = DIPH_DEVICE;
|
||||
dipdw.dwData = DIPROPAUTOCENTER_OFF;
|
||||
m_device->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph );
|
||||
InitForceFeedback(m_device, objects.size());
|
||||
}
|
||||
|
||||
ClearInputState();
|
||||
@ -355,14 +255,6 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
||||
|
||||
Joystick::~Joystick()
|
||||
{
|
||||
// release the ff effect iface's
|
||||
for (EffectState& state : m_state_out)
|
||||
{
|
||||
state.iface->Stop();
|
||||
state.iface->Unload();
|
||||
state.iface->Release();
|
||||
}
|
||||
|
||||
m_device->Unacquire();
|
||||
m_device->Release();
|
||||
}
|
||||
@ -434,42 +326,6 @@ bool Joystick::UpdateInput()
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
bool Joystick::UpdateOutput()
|
||||
{
|
||||
size_t ok_count = 0;
|
||||
|
||||
DIEFFECT eff;
|
||||
ZeroMemory(&eff, sizeof(eff));
|
||||
eff.dwSize = sizeof(DIEFFECT);
|
||||
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
||||
|
||||
for (EffectState& state : m_state_out)
|
||||
{
|
||||
if (state.params)
|
||||
{
|
||||
if (state.size)
|
||||
{
|
||||
eff.cbTypeSpecificParams = state.size;
|
||||
eff.lpvTypeSpecificParams = state.params;
|
||||
// set params and start effect
|
||||
ok_count += SUCCEEDED(state.iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START));
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_count += SUCCEEDED(state.iface->Stop());
|
||||
}
|
||||
|
||||
state.params = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
++ok_count;
|
||||
}
|
||||
}
|
||||
|
||||
return (m_state_out.size() == ok_count);
|
||||
}
|
||||
|
||||
// get name
|
||||
|
||||
std::string Joystick::Button::GetName() const
|
||||
@ -507,12 +363,6 @@ std::string Joystick::Hat::GetName() const
|
||||
return tmpstr;
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
std::string Joystick::Force<P>::GetName() const
|
||||
{
|
||||
return force_type_names[m_index].name;
|
||||
}
|
||||
|
||||
// get / set state
|
||||
|
||||
ControlState Joystick::Axis::GetState() const
|
||||
@ -535,58 +385,5 @@ ControlState Joystick::Hat::GetState() const
|
||||
return (abs((int)(m_hat / 4500 - m_direction * 2 + 8) % 8 - 4) > 2);
|
||||
}
|
||||
|
||||
void Joystick::ForceConstant::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
LONG &val = params.lMagnitude;
|
||||
if (val != new_val)
|
||||
{
|
||||
val = new_val;
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Joystick::ForceRamp::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
if (params.lStart != new_val)
|
||||
{
|
||||
params.lStart = params.lEnd = new_val;
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Joystick::ForcePeriodic::SetState(const ControlState state)
|
||||
{
|
||||
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
|
||||
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
Joystick::Force<P>::Force(u8 index, EffectState& state)
|
||||
: m_index(index), m_state(state)
|
||||
{
|
||||
ZeroMemory(¶ms, sizeof(params));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,7 @@
|
||||
#define _CIFACE_DINPUT_JOYSTICK_H_
|
||||
|
||||
#include "../Device.h"
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <dinput.h>
|
||||
|
||||
#include <list>
|
||||
#include "../ForceFeedback/ForceFeedbackDevice.h"
|
||||
|
||||
namespace ciface
|
||||
{
|
||||
@ -18,18 +11,9 @@ namespace DInput
|
||||
|
||||
void InitJoystick(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND hwnd);
|
||||
|
||||
class Joystick : public Core::Device
|
||||
class Joystick : public ForceFeedback::ForceFeedbackDevice
|
||||
{
|
||||
private:
|
||||
struct EffectState
|
||||
{
|
||||
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 Button : public Input
|
||||
{
|
||||
public:
|
||||
@ -64,25 +48,8 @@ private:
|
||||
const u8 m_index, m_direction;
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Force : public Output
|
||||
{
|
||||
public:
|
||||
std::string GetName() const;
|
||||
Force(u8 index, EffectState& state);
|
||||
void SetState(ControlState state);
|
||||
private:
|
||||
EffectState& m_state;
|
||||
P params;
|
||||
const u8 m_index;
|
||||
};
|
||||
typedef Force<DICONSTANTFORCE> ForceConstant;
|
||||
typedef Force<DIRAMPFORCE> ForceRamp;
|
||||
typedef Force<DIPERIODIC> ForcePeriodic;
|
||||
|
||||
public:
|
||||
bool UpdateInput();
|
||||
bool UpdateOutput();
|
||||
|
||||
void ClearInputState();
|
||||
|
||||
@ -98,7 +65,6 @@ private:
|
||||
const unsigned int m_index;
|
||||
|
||||
DIJOYSTATE m_state_in;
|
||||
std::list<EffectState> m_state_out;
|
||||
|
||||
bool m_buffered;
|
||||
};
|
||||
|
@ -0,0 +1,227 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "ForceFeedbackDevice.h"
|
||||
|
||||
namespace ciface
|
||||
{
|
||||
namespace ForceFeedback
|
||||
{
|
||||
|
||||
// template instantiation
|
||||
template class ForceFeedbackDevice::Force<DICONSTANTFORCE>;
|
||||
template class ForceFeedbackDevice::Force<DIRAMPFORCE>;
|
||||
template class ForceFeedbackDevice::Force<DIPERIODIC>;
|
||||
|
||||
static const struct
|
||||
{
|
||||
GUID guid;
|
||||
const char* name;
|
||||
} force_type_names[] =
|
||||
{
|
||||
{GUID_ConstantForce, "Constant"}, // DICONSTANTFORCE
|
||||
{GUID_RampForce, "Ramp"}, // DIRAMPFORCE
|
||||
{GUID_Square, "Square"}, // DIPERIODIC ...
|
||||
{GUID_Sine, "Sine"},
|
||||
{GUID_Triangle, "Triangle"},
|
||||
{GUID_SawtoothUp, "Sawtooth Up"},
|
||||
{GUID_SawtoothDown, "Sawtooth Down"},
|
||||
//{GUID_Spring, "Spring"}, // DICUSTOMFORCE ... < I think
|
||||
//{GUID_Damper, "Damper"},
|
||||
//{GUID_Inertia, "Inertia"},
|
||||
//{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)
|
||||
{
|
||||
if (cAxes == 0)
|
||||
return false;
|
||||
|
||||
// TODO: check for DIDC_FORCEFEEDBACK in devcaps?
|
||||
|
||||
// temporary
|
||||
DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y};
|
||||
LONG rglDirection[2] = {-200, 0};
|
||||
|
||||
DIEFFECT eff;
|
||||
ZeroMemory(&eff, sizeof(eff));
|
||||
eff.dwSize = sizeof(DIEFFECT);
|
||||
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
||||
eff.dwDuration = INFINITE; // (4 * DI_SECONDS)
|
||||
eff.dwSamplePeriod = 0;
|
||||
eff.dwGain = DI_FFNOMINALMAX;
|
||||
eff.dwTriggerButton = DIEB_NOTRIGGER;
|
||||
eff.dwTriggerRepeatInterval = 0;
|
||||
eff.cAxes = std::min((DWORD)1, (DWORD)cAxes);
|
||||
eff.rgdwAxes = rgdwAxes;
|
||||
eff.rglDirection = rglDirection;
|
||||
|
||||
// DIPERIODIC is the largest, so we'll use that
|
||||
DIPERIODIC ff;
|
||||
eff.lpvTypeSpecificParams = &ff;
|
||||
ZeroMemory(&ff, sizeof(ff));
|
||||
|
||||
// doesn't seem needed
|
||||
//DIENVELOPE env;
|
||||
//eff.lpEnvelope = &env;
|
||||
//ZeroMemory(&env, sizeof(env));
|
||||
//env.dwSize = sizeof(env);
|
||||
|
||||
for (unsigned int f = 0; f < sizeof(force_type_names)/sizeof(*force_type_names); ++f)
|
||||
{
|
||||
// ugly if ladder
|
||||
if (0 == f)
|
||||
{
|
||||
DICONSTANTFORCE diCF = {-10000};
|
||||
diCF.lMagnitude = DI_FFNOMINALMAX;
|
||||
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
||||
eff.lpvTypeSpecificParams = &diCF;
|
||||
}
|
||||
else if (1 == f)
|
||||
{
|
||||
eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
|
||||
}
|
||||
|
||||
LPDIRECTINPUTEFFECT pEffect;
|
||||
if (SUCCEEDED(device->CreateEffect(force_type_names[f].guid, &eff, &pEffect, NULL)))
|
||||
{
|
||||
m_state_out.push_back(EffectState(pEffect));
|
||||
|
||||
// ugly if ladder again :/
|
||||
if (0 == f)
|
||||
AddOutput(new ForceConstant(f, m_state_out.back()));
|
||||
else if (1 == f)
|
||||
AddOutput(new ForceRamp(f, m_state_out.back()));
|
||||
else
|
||||
AddOutput(new ForcePeriodic(f, m_state_out.back()));
|
||||
}
|
||||
}
|
||||
|
||||
// disable autocentering
|
||||
if (Outputs().size())
|
||||
{
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof( DIPROPDWORD );
|
||||
dipdw.diph.dwHeaderSize = sizeof( DIPROPHEADER );
|
||||
dipdw.diph.dwObj = 0;
|
||||
dipdw.diph.dwHow = DIPH_DEVICE;
|
||||
dipdw.dwData = DIPROPAUTOCENTER_OFF;
|
||||
device->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ForceFeedbackDevice::UpdateOutput()
|
||||
{
|
||||
size_t ok_count = 0;
|
||||
|
||||
DIEFFECT eff;
|
||||
ZeroMemory(&eff, sizeof(eff));
|
||||
eff.dwSize = sizeof(DIEFFECT);
|
||||
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
|
||||
|
||||
for (EffectState& state : m_state_out)
|
||||
{
|
||||
if (state.params)
|
||||
{
|
||||
if (state.size)
|
||||
{
|
||||
eff.cbTypeSpecificParams = state.size;
|
||||
eff.lpvTypeSpecificParams = state.params;
|
||||
// set params and start effect
|
||||
ok_count += SUCCEEDED(state.iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START));
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_count += SUCCEEDED(state.iface->Stop());
|
||||
}
|
||||
|
||||
state.params = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
++ok_count;
|
||||
}
|
||||
}
|
||||
|
||||
return (m_state_out.size() == ok_count);
|
||||
}
|
||||
|
||||
void ForceFeedbackDevice::ForceConstant::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
LONG &val = params.lMagnitude;
|
||||
if (val != new_val)
|
||||
{
|
||||
val = new_val;
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ForceFeedbackDevice::ForceRamp::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
if (params.lStart != new_val)
|
||||
{
|
||||
params.lStart = params.lEnd = new_val;
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ForceFeedbackDevice::ForcePeriodic::SetState(const ControlState state)
|
||||
{
|
||||
const DWORD new_val = DWORD(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
|
||||
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
ForceFeedbackDevice::Force<P>::Force(u8 index, EffectState& state)
|
||||
: m_index(index), m_state(state)
|
||||
{
|
||||
ZeroMemory(¶ms, sizeof(params));
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
std::string ForceFeedbackDevice::Force<P>::GetName() const
|
||||
{
|
||||
return force_type_names[m_index].name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _FORCEFEEDBACKDEVICE_H_
|
||||
#define _FORCEFEEDBACKDEVICE_H_
|
||||
|
||||
#include "../Device.h"
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <dinput.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace ciface
|
||||
{
|
||||
namespace ForceFeedback
|
||||
{
|
||||
|
||||
|
||||
class ForceFeedbackDevice : public Core::Device
|
||||
{
|
||||
private:
|
||||
struct EffectState
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Force : public Output
|
||||
{
|
||||
public:
|
||||
std::string GetName() const;
|
||||
Force(u8 index, EffectState& state);
|
||||
void SetState(ControlState state);
|
||||
private:
|
||||
const u8 m_index;
|
||||
EffectState& m_state;
|
||||
P params;
|
||||
};
|
||||
typedef Force<DICONSTANTFORCE> ForceConstant;
|
||||
typedef Force<DIRAMPFORCE> ForceRamp;
|
||||
typedef Force<DIPERIODIC> ForcePeriodic;
|
||||
|
||||
public:
|
||||
bool InitForceFeedback(const LPDIRECTINPUTDEVICE8, int cAxes);
|
||||
bool UpdateOutput();
|
||||
|
||||
virtual ~ForceFeedbackDevice();
|
||||
private:
|
||||
std::list<EffectState> m_state_out;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -50,6 +50,7 @@
|
||||
<ClCompile Include="ControllerInterface\DInput\DInputJoystick.cpp" />
|
||||
<ClCompile Include="ControllerInterface\DInput\DInputKeyboardMouse.cpp" />
|
||||
<ClCompile Include="ControllerInterface\ExpressionParser.cpp" />
|
||||
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp" />
|
||||
<ClCompile Include="ControllerInterface\SDL\SDL.cpp" />
|
||||
<ClCompile Include="ControllerInterface\XInput\XInput.cpp" />
|
||||
<ClCompile Include="InputConfig.cpp" />
|
||||
@ -67,6 +68,7 @@
|
||||
<ClInclude Include="ControllerInterface\DInput\DInputJoystick.h" />
|
||||
<ClInclude Include="ControllerInterface\DInput\DInputKeyboardMouse.h" />
|
||||
<ClInclude Include="ControllerInterface\ExpressionParser.h" />
|
||||
<ClInclude Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.h" />
|
||||
<ClInclude Include="ControllerInterface\SDL\SDL.h" />
|
||||
<ClInclude Include="ControllerInterface\XInput\XInput.h" />
|
||||
<ClInclude Include="GCPadStatus.h" />
|
||||
@ -86,4 +88,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="ControllerInterface">
|
||||
@ -13,6 +13,9 @@
|
||||
<Filter Include="ControllerInterface\XInput">
|
||||
<UniqueIdentifier>{07bad1aa-7e03-4f5c-ade2-a44857c5cbc3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\ForceFeedback">
|
||||
<UniqueIdentifier>{e10ce316-283c-4be0-848d-578dec2b6404}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ControllerEmu.cpp" />
|
||||
@ -44,6 +47,9 @@
|
||||
<Filter>ControllerInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp">
|
||||
<Filter>ControllerInterface\ForceFeedback</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ControllerEmu.h" />
|
||||
@ -76,8 +82,11 @@
|
||||
<Filter>ControllerInterface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.h">
|
||||
<Filter>ControllerInterface\ForceFeedback</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user