mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-09 23:59:27 +01:00
commit
9da6900595
@ -242,6 +242,7 @@ if(APPLE)
|
|||||||
find_library(IOK_LIBRARY IOKit)
|
find_library(IOK_LIBRARY IOKit)
|
||||||
find_library(QUICKTIME_LIBRARY QuickTime)
|
find_library(QUICKTIME_LIBRARY QuickTime)
|
||||||
find_library(WEBKIT_LIBRARY WebKit)
|
find_library(WEBKIT_LIBRARY WebKit)
|
||||||
|
find_library(FORCEFEEDBACK ForceFeedback)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
@ -141,6 +141,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||||||
${CORESERV_LIBRARY}
|
${CORESERV_LIBRARY}
|
||||||
${IOB_LIBRARY}
|
${IOB_LIBRARY}
|
||||||
${IOK_LIBRARY}
|
${IOK_LIBRARY}
|
||||||
|
${FORCEFEEDBACK}
|
||||||
)
|
)
|
||||||
if(wxWidgets_FOUND)
|
if(wxWidgets_FOUND)
|
||||||
list(APPEND LIBS
|
list(APPEND LIBS
|
||||||
|
@ -12,13 +12,15 @@ if(WIN32)
|
|||||||
ControllerInterface/DInput/DInputJoystick.cpp
|
ControllerInterface/DInput/DInputJoystick.cpp
|
||||||
ControllerInterface/DInput/DInputKeyboardMouse.cpp
|
ControllerInterface/DInput/DInputKeyboardMouse.cpp
|
||||||
ControllerInterface/SDL/SDL.cpp
|
ControllerInterface/SDL/SDL.cpp
|
||||||
ControllerInterface/XInput/XInput.cpp)
|
ControllerInterface/XInput/XInput.cpp
|
||||||
|
ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp)
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
set(SRCS ${SRCS}
|
set(SRCS ${SRCS}
|
||||||
ControllerInterface/OSX/OSX.mm
|
ControllerInterface/OSX/OSX.mm
|
||||||
ControllerInterface/OSX/OSXKeyboard.mm
|
ControllerInterface/OSX/OSXKeyboard.mm
|
||||||
ControllerInterface/OSX/OSXJoystick.mm
|
ControllerInterface/OSX/OSXJoystick.mm
|
||||||
ControllerInterface/SDL/SDL.cpp)
|
ControllerInterface/SDL/SDL.cpp
|
||||||
|
ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp)
|
||||||
elseif(X11_FOUND)
|
elseif(X11_FOUND)
|
||||||
set(SRCS ${SRCS}
|
set(SRCS ${SRCS}
|
||||||
ControllerInterface/SDL/SDL.cpp
|
ControllerInterface/SDL/SDL.cpp
|
||||||
|
@ -14,30 +14,6 @@ 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
|
|
||||||
{
|
|
||||||
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
|
#define DATA_BUFFER_SIZE 32
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -267,87 +243,11 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check for DIDC_FORCEFEEDBACK in devcaps?
|
// force feedback
|
||||||
|
|
||||||
// get supported ff effects
|
|
||||||
std::list<DIDEVICEOBJECTINSTANCE> objects;
|
std::list<DIDEVICEOBJECTINSTANCE> objects;
|
||||||
m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS);
|
if (SUCCEEDED(m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS)))
|
||||||
// got some ff axes or something
|
|
||||||
if ( objects.size() )
|
|
||||||
{
|
{
|
||||||
// temporary
|
InitForceFeedback(m_device, objects.size());
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearInputState();
|
ClearInputState();
|
||||||
@ -355,14 +255,6 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
|||||||
|
|
||||||
Joystick::~Joystick()
|
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->Unacquire();
|
||||||
m_device->Release();
|
m_device->Release();
|
||||||
}
|
}
|
||||||
@ -434,42 +326,6 @@ bool Joystick::UpdateInput()
|
|||||||
return SUCCEEDED(hr);
|
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
|
// get name
|
||||||
|
|
||||||
std::string Joystick::Button::GetName() const
|
std::string Joystick::Button::GetName() const
|
||||||
@ -507,12 +363,6 @@ std::string Joystick::Hat::GetName() const
|
|||||||
return tmpstr;
|
return tmpstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P>
|
|
||||||
std::string Joystick::Force<P>::GetName() const
|
|
||||||
{
|
|
||||||
return force_type_names[m_index].name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get / set state
|
// get / set state
|
||||||
|
|
||||||
ControlState Joystick::Axis::GetState() const
|
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);
|
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_
|
#define _CIFACE_DINPUT_JOYSTICK_H_
|
||||||
|
|
||||||
#include "../Device.h"
|
#include "../Device.h"
|
||||||
|
#include "../ForceFeedback/ForceFeedbackDevice.h"
|
||||||
#define DIRECTINPUT_VERSION 0x0800
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#define NOMINMAX
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <dinput.h>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
namespace ciface
|
namespace ciface
|
||||||
{
|
{
|
||||||
@ -18,18 +11,9 @@ namespace DInput
|
|||||||
|
|
||||||
void InitJoystick(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND hwnd);
|
void InitJoystick(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND hwnd);
|
||||||
|
|
||||||
class Joystick : public Core::Device
|
class Joystick : public ForceFeedback::ForceFeedbackDevice
|
||||||
{
|
{
|
||||||
private:
|
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
|
class Button : public Input
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -64,25 +48,8 @@ private:
|
|||||||
const u8 m_index, m_direction;
|
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:
|
public:
|
||||||
bool UpdateInput();
|
bool UpdateInput();
|
||||||
bool UpdateOutput();
|
|
||||||
|
|
||||||
void ClearInputState();
|
void ClearInputState();
|
||||||
|
|
||||||
@ -98,7 +65,6 @@ private:
|
|||||||
const unsigned int m_index;
|
const unsigned int m_index;
|
||||||
|
|
||||||
DIJOYSTATE m_state_in;
|
DIJOYSTATE m_state_in;
|
||||||
std::list<EffectState> m_state_out;
|
|
||||||
|
|
||||||
bool m_buffered;
|
bool m_buffered;
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,232 @@
|
|||||||
|
// 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>;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GUID guid;
|
||||||
|
const char* name;
|
||||||
|
} ForceType;
|
||||||
|
|
||||||
|
static const ForceType 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;
|
||||||
|
memset(&eff, 0, 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;
|
||||||
|
|
||||||
|
// initialize parameters
|
||||||
|
DICONSTANTFORCE diCF = { -10000 };
|
||||||
|
diCF.lMagnitude = DI_FFNOMINALMAX;
|
||||||
|
DIRAMPFORCE diRF = { 0 };
|
||||||
|
DIPERIODIC diPE = { 0 };
|
||||||
|
|
||||||
|
// doesn't seem needed
|
||||||
|
//DIENVELOPE env;
|
||||||
|
//eff.lpEnvelope = &env;
|
||||||
|
//ZeroMemory(&env, sizeof(env));
|
||||||
|
//env.dwSize = sizeof(env);
|
||||||
|
|
||||||
|
for (const ForceType& f : force_type_names)
|
||||||
|
{
|
||||||
|
if (f.guid == GUID_ConstantForce)
|
||||||
|
{
|
||||||
|
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
||||||
|
eff.lpvTypeSpecificParams = &diCF;
|
||||||
|
}
|
||||||
|
else if (f.guid == GUID_RampForce)
|
||||||
|
{
|
||||||
|
eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
|
||||||
|
eff.lpvTypeSpecificParams = &diRF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// all other forces need periodic parameters
|
||||||
|
eff.cbTypeSpecificParams = sizeof(DIPERIODIC);
|
||||||
|
eff.lpvTypeSpecificParams = &diPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LPDIRECTINPUTEFFECT pEffect;
|
||||||
|
if (SUCCEEDED(device->CreateEffect(f.guid, &eff, &pEffect, NULL)))
|
||||||
|
{
|
||||||
|
m_state_out.push_back(EffectState(pEffect));
|
||||||
|
|
||||||
|
if (f.guid == GUID_ConstantForce)
|
||||||
|
AddOutput(new ForceConstant(f.name, m_state_out.back()));
|
||||||
|
else if (f.guid == GUID_RampForce)
|
||||||
|
AddOutput(new ForceRamp(f.name, m_state_out.back()));
|
||||||
|
else
|
||||||
|
AddOutput(new ForcePeriodic(f.name, 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;
|
||||||
|
memset(&eff, 0, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
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(const char* name, EffectState& state)
|
||||||
|
: m_name(name), m_state(state)
|
||||||
|
{
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
std::string ForceFeedbackDevice::Force<P>::GetName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#ifndef _FORCEFEEDBACKDEVICE_H_
|
||||||
|
#define _FORCEFEEDBACKDEVICE_H_
|
||||||
|
|
||||||
|
#include "../Device.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define DIRECTINPUT_VERSION 0x0800
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <dinput.h>
|
||||||
|
#elif __APPLE__
|
||||||
|
#include "OSX/DirectInputAdapter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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(const char* name, EffectState& state);
|
||||||
|
void SetState(ControlState state);
|
||||||
|
private:
|
||||||
|
const char* m_name;
|
||||||
|
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
|
@ -0,0 +1,224 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The OS X Force Feedback API is very similar to the DirectInput API,
|
||||||
|
* but it is no longer object-oriented and all prefixes have been changed.
|
||||||
|
*
|
||||||
|
* Our implementation uses the Windows API names so we need to adapt
|
||||||
|
* for these differences on OS X.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DIRECTINPUTADAPTER_H_
|
||||||
|
#define _DIRECTINPUTADAPTER_H_
|
||||||
|
|
||||||
|
typedef LONG* LPLONG; // Missing type for ForceFeedback.h
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <ForceFeedback/ForceFeedback.h>
|
||||||
|
#include "DirectInputConstants.h" // Not stricty necessary
|
||||||
|
|
||||||
|
namespace ciface
|
||||||
|
{
|
||||||
|
namespace ForceFeedback
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Prototypes
|
||||||
|
class IUnknownImpl;
|
||||||
|
class FFEffectAdapter;
|
||||||
|
class FFDeviceAdapter;
|
||||||
|
|
||||||
|
// Structs
|
||||||
|
typedef FFCAPABILITIES DICAPABILITIES;
|
||||||
|
typedef FFCONDITION DICONDITION;
|
||||||
|
typedef FFCONSTANTFORCE DICONSTANTFORCE;
|
||||||
|
typedef FFCUSTOMFORCE DICUSTOMFORCE;
|
||||||
|
typedef FFEFFECT DIEFFECT;
|
||||||
|
typedef FFEFFESCAPE DIEFFESCAPE;
|
||||||
|
typedef FFENVELOPE DIENVELOPE;
|
||||||
|
typedef FFPERIODIC DIPERIODIC;
|
||||||
|
typedef FFRAMPFORCE DIRAMPFORCE;
|
||||||
|
|
||||||
|
// Other types
|
||||||
|
typedef CFUUIDRef GUID;
|
||||||
|
typedef FFDeviceAdapter* FFDeviceAdapterReference;
|
||||||
|
typedef FFEffectAdapter* FFEffectAdapterReference;
|
||||||
|
typedef FFDeviceAdapterReference LPDIRECTINPUTDEVICE8;
|
||||||
|
typedef FFEffectAdapterReference LPDIRECTINPUTEFFECT;
|
||||||
|
|
||||||
|
// Property structures
|
||||||
|
#define DIPH_DEVICE 0
|
||||||
|
|
||||||
|
typedef struct DIPROPHEADER {
|
||||||
|
DWORD dwSize;
|
||||||
|
DWORD dwHeaderSize;
|
||||||
|
DWORD dwObj;
|
||||||
|
DWORD dwHow;
|
||||||
|
} DIPROPHEADER, *LPDIPROPHEADER;
|
||||||
|
|
||||||
|
typedef struct DIPROPDWORD {
|
||||||
|
DIPROPHEADER diph;
|
||||||
|
DWORD dwData;
|
||||||
|
} DIPROPDWORD, *LPDIPROPDWORD;
|
||||||
|
|
||||||
|
class IUnknownImpl : public IUnknown
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::atomic<ULONG> m_cRef;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IUnknownImpl() : m_cRef(1) {}
|
||||||
|
virtual ~IUnknownImpl() {}
|
||||||
|
|
||||||
|
HRESULT QueryInterface(REFIID iid, LPVOID *ppv)
|
||||||
|
{
|
||||||
|
*ppv = NULL;
|
||||||
|
|
||||||
|
if (CFEqual(&iid, IUnknownUUID))
|
||||||
|
*ppv = this;
|
||||||
|
if (NULL == *ppv)
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
|
||||||
|
((IUnknown*)*ppv)->AddRef();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AddRef()
|
||||||
|
{
|
||||||
|
return ++m_cRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG Release()
|
||||||
|
{
|
||||||
|
if (--m_cRef == 0)
|
||||||
|
delete this;
|
||||||
|
|
||||||
|
return m_cRef;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FFEffectAdapter : public IUnknownImpl
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// Only used for destruction
|
||||||
|
FFDeviceObjectReference m_device;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FFEffectObjectReference m_effect;
|
||||||
|
|
||||||
|
FFEffectAdapter(FFDeviceObjectReference device, FFEffectObjectReference effect) : m_device(device), m_effect(effect) {}
|
||||||
|
~FFEffectAdapter() { FFDeviceReleaseEffect(m_device, m_effect); }
|
||||||
|
|
||||||
|
HRESULT Download()
|
||||||
|
{
|
||||||
|
return FFEffectDownload(m_effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Escape(FFEFFESCAPE *pFFEffectEscape)
|
||||||
|
{
|
||||||
|
return FFEffectEscape(m_effect, pFFEffectEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT GetEffectStatus(FFEffectStatusFlag *pFlags)
|
||||||
|
{
|
||||||
|
return FFEffectGetEffectStatus(m_effect, pFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT GetParameters(FFEFFECT *pFFEffect, FFEffectParameterFlag flags)
|
||||||
|
{
|
||||||
|
return FFEffectGetParameters(m_effect, pFFEffect, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SetParameters(FFEFFECT *pFFEffect, FFEffectParameterFlag flags)
|
||||||
|
{
|
||||||
|
return FFEffectSetParameters(m_effect, pFFEffect, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Start(UInt32 iterations, FFEffectStartFlag flags)
|
||||||
|
{
|
||||||
|
return FFEffectStart(m_effect, iterations, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Stop()
|
||||||
|
{
|
||||||
|
return FFEffectStop(m_effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Unload()
|
||||||
|
{
|
||||||
|
return FFEffectUnload(m_effect);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FFDeviceAdapter : public IUnknownImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FFDeviceObjectReference m_device;
|
||||||
|
|
||||||
|
FFDeviceAdapter(FFDeviceObjectReference device) : m_device(device) {}
|
||||||
|
~FFDeviceAdapter() { FFReleaseDevice(m_device); }
|
||||||
|
|
||||||
|
static HRESULT Create(io_service_t hidDevice, FFDeviceAdapterReference *pDeviceReference)
|
||||||
|
{
|
||||||
|
FFDeviceObjectReference ref;
|
||||||
|
|
||||||
|
HRESULT hr = FFCreateDevice(hidDevice, &ref);
|
||||||
|
if(SUCCEEDED(hr))
|
||||||
|
*pDeviceReference = new FFDeviceAdapter(ref);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CreateEffect(CFUUIDRef uuidRef, FFEFFECT *pEffectDefinition, FFEffectAdapterReference *pEffectReference, IUnknown *punkOuter)
|
||||||
|
{
|
||||||
|
FFEffectObjectReference ref;
|
||||||
|
|
||||||
|
HRESULT hr = FFDeviceCreateEffect(m_device, uuidRef, pEffectDefinition, &ref);
|
||||||
|
if(SUCCEEDED(hr))
|
||||||
|
*pEffectReference = new FFEffectAdapter(m_device, ref);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Escape(FFEFFESCAPE *pFFEffectEscape)
|
||||||
|
{
|
||||||
|
return FFDeviceEscape(m_device, pFFEffectEscape);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT GetForceFeedbackState(FFState *pFFState)
|
||||||
|
{
|
||||||
|
return FFDeviceGetForceFeedbackState(m_device, pFFState);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SendForceFeedbackCommand(FFCommandFlag flags)
|
||||||
|
{
|
||||||
|
return FFDeviceSendForceFeedbackCommand(m_device, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SetCooperativeLevel(void *taskIdentifier, FFCooperativeLevelFlag flags)
|
||||||
|
{
|
||||||
|
return FFDeviceSetCooperativeLevel(m_device, taskIdentifier, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SetProperty(FFProperty property, const LPDIPROPHEADER pdiph)
|
||||||
|
{
|
||||||
|
// There are only two properties supported
|
||||||
|
if (property != DIPROP_FFGAIN && property != DIPROP_AUTOCENTER)
|
||||||
|
return DIERR_UNSUPPORTED;
|
||||||
|
|
||||||
|
// And they are both device properties
|
||||||
|
if (pdiph->dwHow != DIPH_DEVICE)
|
||||||
|
return DIERR_INVALIDPARAM;
|
||||||
|
|
||||||
|
UInt32 value = ((const LPDIPROPDWORD)pdiph)->dwData;
|
||||||
|
return FFDeviceSetForceFeedbackProperty(m_device, property, &value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#ifndef _DIRECTINPUTCONSTANTS_H_
|
||||||
|
#define _DIRECTINPUTCONSTANTS_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define all constants from ForceFeedbackConstants.h with DirectInput prefixes.
|
||||||
|
*
|
||||||
|
* No effort was made to confirm if all definitions are actually supported by
|
||||||
|
* DirectInput, so some of these definitions may actually only exist on Mac OS X.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// UUIDs
|
||||||
|
#define GUID_ConstantForce kFFEffectType_ConstantForce_ID
|
||||||
|
#define GUID_CustomForce kFFEffectType_CustomForce_ID
|
||||||
|
#define GUID_Damper kFFEffectType_Damper_ID
|
||||||
|
#define GUID_Friction kFFEffectType_Friction_ID
|
||||||
|
#define GUID_Inertia kFFEffectType_Inertia_ID
|
||||||
|
#define GUID_RampForce kFFEffectType_RampForce_ID
|
||||||
|
#define GUID_SawtoothDown kFFEffectType_SawtoothDown_ID
|
||||||
|
#define GUID_SawtoothUp kFFEffectType_SawtoothUp_ID
|
||||||
|
#define GUID_Sine kFFEffectType_Sine_ID
|
||||||
|
#define GUID_Spring kFFEffectType_Spring_ID
|
||||||
|
#define GUID_Square kFFEffectType_Square_ID
|
||||||
|
#define GUID_Triangle kFFEffectType_Triangle_ID
|
||||||
|
|
||||||
|
// Miscellaneous
|
||||||
|
#define DI_DEGREES FF_DEGREES
|
||||||
|
#define DI_DOWNLOADSKIPPED FF_DOWNLOADSKIPPED
|
||||||
|
#define DI_EFFECTRESTARTED FF_EFFECTRESTARTED
|
||||||
|
#define DI_FALSE FF_FALSE
|
||||||
|
#define DI_FFNOMINALMAX FF_FFNOMINALMAX
|
||||||
|
#define DI_INFINITE FF_INFINITE
|
||||||
|
#define DI_OK FF_OK
|
||||||
|
#define DI_SECONDS FF_SECONDS
|
||||||
|
#define DI_TRUNCATED FF_TRUNCATED
|
||||||
|
#define DI_TRUNCATEDANDRESTARTED FF_TRUNCATEDANDRESTARTED
|
||||||
|
#define DIEFF_OBJECTOFFSETS FFEFF_OBJECTOFFSETS
|
||||||
|
#define DIERR_DEVICEFULL FFERR_DEVICEFULL
|
||||||
|
#define DIERR_DEVICENOTREG FFERR_DEVICENOTREG
|
||||||
|
#define DIERR_DEVICEPAUSED FFERR_DEVICEPAUSED
|
||||||
|
#define DIERR_DEVICERELEASED FFERR_DEVICERELEASED
|
||||||
|
#define DIERR_EFFECTPLAYING FFERR_EFFECTPLAYING
|
||||||
|
#define DIERR_EFFECTTYPEMISMATCH FFERR_EFFECTTYPEMISMATCH
|
||||||
|
#define DIERR_EFFECTTYPENOTSUPPORTED FFERR_EFFECTTYPENOTSUPPORTED
|
||||||
|
#define DIERR_GENERIC FFERR_GENERIC
|
||||||
|
#define DIERR_HASEFFECTS FFERR_HASEFFECTS
|
||||||
|
#define DIERR_INCOMPLETEEFFECT FFERR_INCOMPLETEEFFECT
|
||||||
|
#define DIERR_INTERNAL FFERR_INTERNAL
|
||||||
|
#define DIERR_INVALIDDOWNLOADID FFERR_INVALIDDOWNLOADID
|
||||||
|
#define DIERR_INVALIDPARAM FFERR_INVALIDPARAM
|
||||||
|
#define DIERR_MOREDATA FFERR_MOREDATA
|
||||||
|
#define DIERR_NOINTERFACE FFERR_NOINTERFACE
|
||||||
|
#define DIERR_NOTDOWNLOADED FFERR_NOTDOWNLOADED
|
||||||
|
#define DIERR_NOTINITIALIZED FFERR_NOTINITIALIZED
|
||||||
|
#define DIERR_OUTOFMEMORY FFERR_OUTOFMEMORY
|
||||||
|
#define DIERR_UNPLUGGED FFERR_UNPLUGGED
|
||||||
|
#define DIERR_UNSUPPORTED FFERR_UNSUPPORTED
|
||||||
|
#define DIERR_UNSUPPORTEDAXIS FFERR_UNSUPPORTEDAXIS
|
||||||
|
#define DIJOFS_X FFJOFS_X
|
||||||
|
#define DIJOFS_Y FFJOFS_Y
|
||||||
|
#define DIJOFS_Z FFJOFS_Z
|
||||||
|
|
||||||
|
// FFCapabilitiesEffectSubType
|
||||||
|
#define DICAP_ST_KINESTHETIC FFCAP_ST_KINESTHETIC
|
||||||
|
#define DICAP_ST_VIBRATION FFCAP_ST_VIBRATION
|
||||||
|
|
||||||
|
// FFCapabilitiesEffectType
|
||||||
|
#define DICAP_ET_CONSTANTFORCE FFCAP_ET_CONSTANTFORCE
|
||||||
|
#define DICAP_ET_RAMPFORCE FFCAP_ET_RAMPFORCE
|
||||||
|
#define DICAP_ET_SQUARE FFCAP_ET_SQUARE
|
||||||
|
#define DICAP_ET_SINE FFCAP_ET_SINE
|
||||||
|
#define DICAP_ET_TRIANGLE FFCAP_ET_TRIANGLE
|
||||||
|
#define DICAP_ET_SAWTOOTHUP FFCAP_ET_SAWTOOTHUP
|
||||||
|
#define DICAP_ET_SAWTOOTHDOWN FFCAP_ET_SAWTOOTHDOWN
|
||||||
|
#define DICAP_ET_SPRING FFCAP_ET_SPRING
|
||||||
|
#define DICAP_ET_DAMPER FFCAP_ET_DAMPER
|
||||||
|
#define DICAP_ET_INERTIA FFCAP_ET_INERTIA
|
||||||
|
#define DICAP_ET_FRICTION FFCAP_ET_FRICTION
|
||||||
|
#define DICAP_ET_CUSTOMFORCE FFCAP_ET_CUSTOMFORCE
|
||||||
|
|
||||||
|
// FFCommandFlag
|
||||||
|
#define DISFFC_RESET FFSFFC_RESET
|
||||||
|
#define DISFFC_STOPALL FFSFFC_STOPALL
|
||||||
|
#define DISFFC_PAUSE FFSFFC_PAUSE
|
||||||
|
#define DISFFC_CONTINUE FFSFFC_CONTINUE
|
||||||
|
#define DISFFC_SETACTUATORSON FFSFFC_SETACTUATORSON
|
||||||
|
#define DISFFC_SETACTUATORSOFF FFSFFC_SETACTUATORSOFF
|
||||||
|
|
||||||
|
// FFCooperativeLevelFlag
|
||||||
|
#define DISCL_EXCLUSIVE FFSCL_EXCLUSIVE
|
||||||
|
#define DISCL_NONEXCLUSIVE FFSCL_NONEXCLUSIVE
|
||||||
|
#define DISCL_FOREGROUND FFSCL_FOREGROUND
|
||||||
|
#define DISCL_BACKGROUND FFSCL_BACKGROUND
|
||||||
|
|
||||||
|
// FFCoordinateSystemFlag
|
||||||
|
#define DIEFF_CARTESIAN FFEFF_CARTESIAN
|
||||||
|
#define DIEFF_POLAR FFEFF_POLAR
|
||||||
|
#define DIEFF_SPHERICAL FFEFF_SPHERICAL
|
||||||
|
|
||||||
|
// FFEffectParameterFlag
|
||||||
|
#define DIEP_DURATION FFEP_DURATION
|
||||||
|
#define DIEP_SAMPLEPERIOD FFEP_SAMPLEPERIOD
|
||||||
|
#define DIEP_GAIN FFEP_GAIN
|
||||||
|
#define DIEP_TRIGGERBUTTON FFEP_TRIGGERBUTTON
|
||||||
|
#define DIEP_TRIGGERREPEATINTERVAL FFEP_TRIGGERREPEATINTERVAL
|
||||||
|
#define DIEP_AXES FFEP_AXES
|
||||||
|
#define DIEP_DIRECTION FFEP_DIRECTION
|
||||||
|
#define DIEP_ENVELOPE FFEP_ENVELOPE
|
||||||
|
#define DIEP_TYPESPECIFICPARAMS FFEP_TYPESPECIFICPARAMS
|
||||||
|
#define DIEP_STARTDELAY FFEP_STARTDELAY
|
||||||
|
#define DIEP_ALLPARAMS FFEP_ALLPARAMS
|
||||||
|
#define DIEP_START FFEP_START
|
||||||
|
#define DIEP_NORESTART FFEP_NORESTART
|
||||||
|
#define DIEP_NODOWNLOAD FFEP_NODOWNLOAD
|
||||||
|
#define DIEB_NOTRIGGER FFEB_NOTRIGGER
|
||||||
|
|
||||||
|
// FFEffectStartFlag
|
||||||
|
#define DIES_SOLO FFES_SOLO
|
||||||
|
#define DIES_NODOWNLOAD FFES_NODOWNLOAD
|
||||||
|
|
||||||
|
// FFEffectStatusFlag
|
||||||
|
#define DIEGES_NOTPLAYING FFEGES_NOTPLAYING
|
||||||
|
#define DIEGES_PLAYING FFEGES_PLAYING
|
||||||
|
#define DIEGES_EMULATED FFEGES_EMULATED
|
||||||
|
|
||||||
|
// FFProperty
|
||||||
|
#define DIPROP_FFGAIN FFPROP_FFGAIN
|
||||||
|
#define DIPROP_AUTOCENTER FFPROP_AUTOCENTER
|
||||||
|
// not defined in ForceFeedbackConstants.h
|
||||||
|
#define DIPROPAUTOCENTER_OFF 0
|
||||||
|
#define DIPROPAUTOCENTER_ON 1
|
||||||
|
|
||||||
|
// FFState
|
||||||
|
#define DIGFFS_EMPTY FFGFFS_EMPTY
|
||||||
|
#define DIGFFS_STOPPED FFGFFS_STOPPED
|
||||||
|
#define DIGFFS_PAUSED FFGFFS_PAUSED
|
||||||
|
#define DIGFFS_ACTUATORSON FFGFFS_ACTUATORSON
|
||||||
|
#define DIGFFS_ACTUATORSOFF FFGFFS_ACTUATORSOFF
|
||||||
|
#define DIGFFS_POWERON FFGFFS_POWERON
|
||||||
|
#define DIGFFS_POWEROFF FFGFFS_POWEROFF
|
||||||
|
#define DIGFFS_SAFETYSWITCHON FFGFFS_SAFETYSWITCHON
|
||||||
|
#define DIGFFS_SAFETYSWITCHOFF FFGFFS_SAFETYSWITCHOFF
|
||||||
|
#define DIGFFS_USERFFSWITCHON FFGFFS_USERFFSWITCHON
|
||||||
|
#define DIGFFS_USERFFSWITCHOFF FFGFFS_USERFFSWITCHOFF
|
||||||
|
#define DIGFFS_DEVICELOST FFGFFS_DEVICELOST
|
||||||
|
|
||||||
|
#endif
|
@ -1,13 +1,14 @@
|
|||||||
#include <IOKit/hid/IOHIDLib.h>
|
#include <IOKit/hid/IOHIDLib.h>
|
||||||
|
|
||||||
#include "../Device.h"
|
#include "../Device.h"
|
||||||
|
#include "../ForceFeedback/ForceFeedbackDevice.h"
|
||||||
|
|
||||||
namespace ciface
|
namespace ciface
|
||||||
{
|
{
|
||||||
namespace OSX
|
namespace OSX
|
||||||
{
|
{
|
||||||
|
|
||||||
class Joystick : public Core::Device
|
class Joystick : public ForceFeedback::ForceFeedbackDevice
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
class Button : public Input
|
class Button : public Input
|
||||||
@ -62,9 +63,9 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool UpdateInput();
|
bool UpdateInput();
|
||||||
bool UpdateOutput();
|
|
||||||
|
|
||||||
Joystick(IOHIDDeviceRef device, std::string name, int index);
|
Joystick(IOHIDDeviceRef device, std::string name, int index);
|
||||||
|
~Joystick();
|
||||||
|
|
||||||
std::string GetName() const;
|
std::string GetName() const;
|
||||||
std::string GetSource() const;
|
std::string GetSource() const;
|
||||||
@ -74,6 +75,8 @@ private:
|
|||||||
const IOHIDDeviceRef m_device;
|
const IOHIDDeviceRef m_device;
|
||||||
const std::string m_device_name;
|
const std::string m_device_name;
|
||||||
const int m_index;
|
const int m_index;
|
||||||
|
|
||||||
|
ForceFeedback::FFDeviceAdapterReference m_ff_device;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ Joystick::Joystick(IOHIDDeviceRef device, std::string name, int index)
|
|||||||
: m_device(device)
|
: m_device(device)
|
||||||
, m_device_name(name)
|
, m_device_name(name)
|
||||||
, m_index(index)
|
, m_index(index)
|
||||||
|
, m_ff_device(nullptr)
|
||||||
{
|
{
|
||||||
// Buttons
|
// Buttons
|
||||||
NSDictionary *buttonDict =
|
NSDictionary *buttonDict =
|
||||||
@ -71,6 +72,20 @@ Joystick::Joystick(IOHIDDeviceRef device, std::string name, int index)
|
|||||||
}
|
}
|
||||||
CFRelease(axes);
|
CFRelease(axes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force Feedback
|
||||||
|
FFCAPABILITIES ff_caps;
|
||||||
|
if (SUCCEEDED(ForceFeedback::FFDeviceAdapter::Create(IOHIDDeviceGetService(m_device), &m_ff_device)) &&
|
||||||
|
SUCCEEDED(FFDeviceGetForceFeedbackCapabilities(m_ff_device->m_device, &ff_caps)))
|
||||||
|
{
|
||||||
|
InitForceFeedback(m_ff_device, ff_caps.numFfAxes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Joystick::~Joystick()
|
||||||
|
{
|
||||||
|
if (m_ff_device)
|
||||||
|
m_ff_device->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Joystick::UpdateInput()
|
bool Joystick::UpdateInput()
|
||||||
@ -78,11 +93,6 @@ bool Joystick::UpdateInput()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Joystick::UpdateOutput()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Joystick::GetName() const
|
std::string Joystick::GetName() const
|
||||||
{
|
{
|
||||||
return m_device_name;
|
return m_device_name;
|
||||||
|
@ -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">
|
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
@ -50,6 +50,7 @@
|
|||||||
<ClCompile Include="ControllerInterface\DInput\DInputJoystick.cpp" />
|
<ClCompile Include="ControllerInterface\DInput\DInputJoystick.cpp" />
|
||||||
<ClCompile Include="ControllerInterface\DInput\DInputKeyboardMouse.cpp" />
|
<ClCompile Include="ControllerInterface\DInput\DInputKeyboardMouse.cpp" />
|
||||||
<ClCompile Include="ControllerInterface\ExpressionParser.cpp" />
|
<ClCompile Include="ControllerInterface\ExpressionParser.cpp" />
|
||||||
|
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp" />
|
||||||
<ClCompile Include="ControllerInterface\SDL\SDL.cpp" />
|
<ClCompile Include="ControllerInterface\SDL\SDL.cpp" />
|
||||||
<ClCompile Include="ControllerInterface\XInput\XInput.cpp" />
|
<ClCompile Include="ControllerInterface\XInput\XInput.cpp" />
|
||||||
<ClCompile Include="InputConfig.cpp" />
|
<ClCompile Include="InputConfig.cpp" />
|
||||||
@ -67,6 +68,7 @@
|
|||||||
<ClInclude Include="ControllerInterface\DInput\DInputJoystick.h" />
|
<ClInclude Include="ControllerInterface\DInput\DInputJoystick.h" />
|
||||||
<ClInclude Include="ControllerInterface\DInput\DInputKeyboardMouse.h" />
|
<ClInclude Include="ControllerInterface\DInput\DInputKeyboardMouse.h" />
|
||||||
<ClInclude Include="ControllerInterface\ExpressionParser.h" />
|
<ClInclude Include="ControllerInterface\ExpressionParser.h" />
|
||||||
|
<ClInclude Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.h" />
|
||||||
<ClInclude Include="ControllerInterface\SDL\SDL.h" />
|
<ClInclude Include="ControllerInterface\SDL\SDL.h" />
|
||||||
<ClInclude Include="ControllerInterface\XInput\XInput.h" />
|
<ClInclude Include="ControllerInterface\XInput\XInput.h" />
|
||||||
<ClInclude Include="GCPadStatus.h" />
|
<ClInclude Include="GCPadStatus.h" />
|
||||||
@ -86,4 +88,4 @@
|
|||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</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">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="ControllerInterface">
|
<Filter Include="ControllerInterface">
|
||||||
@ -13,6 +13,9 @@
|
|||||||
<Filter Include="ControllerInterface\XInput">
|
<Filter Include="ControllerInterface\XInput">
|
||||||
<UniqueIdentifier>{07bad1aa-7e03-4f5c-ade2-a44857c5cbc3}</UniqueIdentifier>
|
<UniqueIdentifier>{07bad1aa-7e03-4f5c-ade2-a44857c5cbc3}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="ControllerInterface\ForceFeedback">
|
||||||
|
<UniqueIdentifier>{e10ce316-283c-4be0-848d-578dec2b6404}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="ControllerEmu.cpp" />
|
<ClCompile Include="ControllerEmu.cpp" />
|
||||||
@ -44,6 +47,9 @@
|
|||||||
<Filter>ControllerInterface</Filter>
|
<Filter>ControllerInterface</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="stdafx.cpp" />
|
<ClCompile Include="stdafx.cpp" />
|
||||||
|
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp">
|
||||||
|
<Filter>ControllerInterface\ForceFeedback</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="ControllerEmu.h" />
|
<ClInclude Include="ControllerEmu.h" />
|
||||||
@ -76,8 +82,11 @@
|
|||||||
<Filter>ControllerInterface</Filter>
|
<Filter>ControllerInterface</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<ClInclude Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.h">
|
||||||
|
<Filter>ControllerInterface\ForceFeedback</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user