2312 lines
74 KiB
C++
2312 lines
74 KiB
C++
|
/****h* Steering.Wheel.SDK/SteeringWheelSDK[1.00.002]
|
||
|
* NAME
|
||
|
* Steering Wheel SDK
|
||
|
* COPYRIGHT
|
||
|
* The Logitech Steering Wheel SDK, including all accompanying
|
||
|
* documentation, is protected by intellectual property laws. All
|
||
|
* rights not expressly granted by Logitech are reserved.
|
||
|
* PURPOSE
|
||
|
* The Steering Wheel SDK is an addition to Microsoft's DirectInput
|
||
|
* in DirectX. It is aimed at driving games and enables to
|
||
|
* dramatically shorten development time and improve implementation
|
||
|
* quality for various types of game controllers (USB/gameport
|
||
|
* wheels/joysticks/game pads, FF enabled or not). The Steering Wheel
|
||
|
* SDK has been developed and tested for wheels and joysticks using
|
||
|
* the Logitech, Microsoft and Immersion drivers. It also works with
|
||
|
* Logitech rumble pads (it has not been tested with non-Logitech
|
||
|
* rumble pads). By using the Steering Wheel SDK you have the
|
||
|
* guarantee that all wheels and joysticks will function
|
||
|
* flawlessly. No more situations where force feedback in a game
|
||
|
* behaves very differently from one wheel/joystick to another, which
|
||
|
* in turn results in user frustration and product returns. The
|
||
|
* Steering Wheel SDK comes with a very intuitive and easy to use
|
||
|
* interface which enables to read the wheel/joystick's axes and
|
||
|
* buttons, and also to create all the force feedback effects that
|
||
|
* are necessary for a good and complete implementation. See the
|
||
|
* following files to get started:
|
||
|
* - readme.txt: tells you how to get started.
|
||
|
* - SampleInGameImplementation.cpp: shows line by line how to
|
||
|
* use the Steering Wheel SDK's interface to do a complete
|
||
|
* implementation for PC game controllers in your driving
|
||
|
* game. The idea is to develop support for the steering
|
||
|
* wheel. But if a user plugs in a joystick or game pad he can
|
||
|
* play as well and get force feedback or rumble. If a joystick
|
||
|
* is plugged in, all forces generated by the Steering Wheel
|
||
|
* SDK will be played on the X axis and there will be a
|
||
|
* constant spring on the Y axis.
|
||
|
* - SteeringWheelSDK.cpp: demonstrates force feedback
|
||
|
* effects. Just compile, run and plug in a FF wheel, joystick
|
||
|
* or rumble pad. See usage at top of SteeringWheelSDK.cpp.
|
||
|
* For more details see DirectInput documentation which is part of
|
||
|
* Microsoft's DirectX.
|
||
|
* AUTHOR
|
||
|
* Christophe Juncker (cj@wingmanteam.com)
|
||
|
******
|
||
|
*/
|
||
|
|
||
|
#include "LogiWheel.h"
|
||
|
#include "LogiWheelUtils.h"
|
||
|
|
||
|
using namespace LogitechSteeringWheel;
|
||
|
using namespace LogitechControllerInput;
|
||
|
|
||
|
DWORD g_forceActuatorsResetTriggered = 0xffffffff;
|
||
|
|
||
|
WNDPROC g_OldWheelWnd;
|
||
|
LRESULT CALLBACK WheelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/Wheel(ControllerInput*.controllerInput)
|
||
|
* NAME
|
||
|
* Wheel(ControllerInput* controllerInput) -- Does necessary
|
||
|
* initialization.
|
||
|
* INPUTS
|
||
|
* controllerInput - handle to instance of Controller Input SDK.
|
||
|
* SEE ALSO
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see an
|
||
|
* example.
|
||
|
******
|
||
|
*/
|
||
|
Wheel::Wheel(ControllerInput* controllerInput)
|
||
|
{
|
||
|
for (INT index_ = 0; index_ < LogitechSteeringWheel::LG_MAX_CONTROLLERS; index_++)
|
||
|
{
|
||
|
InitVars(index_);
|
||
|
}
|
||
|
|
||
|
_ASSERT(NULL != controllerInput);
|
||
|
if (NULL != controllerInput)
|
||
|
{
|
||
|
m_controllerInput = controllerInput;
|
||
|
m_controllerProperties = new ControllerProperties(controllerInput->GetGameHWnd());
|
||
|
|
||
|
//Replace the Window Procedure and Store the Old Window Procedure
|
||
|
g_OldWheelWnd = (WNDPROC)(LONG_PTR)GetWindowLongPtr(controllerInput->GetGameHWnd(), GWLP_WNDPROC);
|
||
|
SetWindowLongPtr(controllerInput->GetGameHWnd(), GWLP_WNDPROC, (__int3264)(LONG_PTR)WheelWindowProc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Wheel::~Wheel()
|
||
|
{
|
||
|
for (INT index_ = 0; index_ < LogitechSteeringWheel::LG_MAX_CONTROLLERS; index_++)
|
||
|
{
|
||
|
if (NULL != m_controllerForce[index_])
|
||
|
{
|
||
|
m_controllerForce[index_]->ReleaseEffects();
|
||
|
delete m_controllerForce[index_];
|
||
|
m_controllerForce[index_] = NULL;
|
||
|
}
|
||
|
|
||
|
// Turn off all LEDs
|
||
|
PlayLeds(index_, 0.0f, 1.0f, 2.0f);
|
||
|
}
|
||
|
|
||
|
if (NULL != m_controllerProperties)
|
||
|
{
|
||
|
delete m_controllerProperties;
|
||
|
m_controllerProperties = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID Wheel::InitVars(CONST INT index)
|
||
|
{
|
||
|
m_isAirborne[index] = FALSE;
|
||
|
m_damperWasPlaying[index] = FALSE;
|
||
|
m_springWasPlaying[index] = FALSE;
|
||
|
|
||
|
m_controllerForce[index] = NULL;
|
||
|
|
||
|
for (INT jj = 0; jj < LG_NUMBER_FORCE_EFFECTS; jj++)
|
||
|
{
|
||
|
m_wasPlayingBeforeAirborne[index][jj] = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/Update()
|
||
|
* NAME
|
||
|
* VOID Wheel::Update() -- keeps forces and controller connections up
|
||
|
* to date.
|
||
|
* NOTES
|
||
|
* Must be called every frame.
|
||
|
* SEE ALSO
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
VOID Wheel::Update()
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerProperties);
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
|
||
|
for (INT index_ = 0; index_ < LogitechSteeringWheel::LG_MAX_CONTROLLERS; index_++)
|
||
|
{
|
||
|
if (NULL != m_controllerInput && NULL != m_controllerProperties)
|
||
|
{
|
||
|
if (m_controllerInput->IsConnected(index_))
|
||
|
{
|
||
|
if (NULL == m_controllerForce[index_])
|
||
|
{
|
||
|
m_controllerForce[index_] = new ControllerForceManager();
|
||
|
_ASSERT(NULL != m_controllerForce[index_]);
|
||
|
if (NULL != m_controllerForce[index_])
|
||
|
{
|
||
|
m_controllerForce[index_]->SetDeviceHandle(m_controllerInput->GetDeviceHandle(index_));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (NULL != m_controllerForce[index_])
|
||
|
{
|
||
|
m_controllerForce[index_]->ReleaseEffects();
|
||
|
delete m_controllerForce[index_];
|
||
|
m_controllerForce[index_] = NULL;
|
||
|
|
||
|
InitVars(index_);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update controller properties
|
||
|
std::vector<DWORD> currentlyConnectedPIDs_;
|
||
|
for (INT index_ = 0; index_ < LogitechSteeringWheel::LG_MAX_CONTROLLERS; index_++)
|
||
|
{
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
if (m_controllerInput->IsConnected(index_))
|
||
|
{
|
||
|
currentlyConnectedPIDs_.push_back(m_controllerInput->GetProductID(index_));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != m_controllerProperties)
|
||
|
{
|
||
|
m_controllerProperties->Update(currentlyConnectedPIDs_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/IsConnected(INT.index)
|
||
|
* NAME
|
||
|
* BOOL IsConnected(INT index) -- Check if a game controller is
|
||
|
* connected at the specified index.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
* RETURN VALUE
|
||
|
* TRUE if a PC wheel/joystick/game pad is connected, FALSE otherwise.
|
||
|
* SEE ALSO
|
||
|
* IsConnected(INT.index,DeviceType.deviceType)
|
||
|
* IsConnected(INT.index,ManufacturerName.manufacturerName)
|
||
|
* IsConnected(INT.index,ModelName.modelName)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::IsConnected(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->IsConnected(index);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/IsConnected(INT.index,DeviceType.deviceType)
|
||
|
* NAME
|
||
|
* BOOL IsConnected(INT index, DeviceType deviceType) -- Check if a
|
||
|
* game controller is connected at the specified index.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* deviceType - type of the device to check for. Possible types are:
|
||
|
* - LG_DEVICE_TYPE_WHEEL
|
||
|
* - LG_DEVICE_TYPE_JOYSTICK
|
||
|
* - LG_DEVICE_TYPE_GAMEPAD
|
||
|
* RETURN VALUE
|
||
|
* TRUE if a PC controller of specified type is connected, FALSE
|
||
|
* otherwise.
|
||
|
* SEE ALSO
|
||
|
* IsConnected(INT.index)
|
||
|
* IsConnected(INT.index,ManufacturerName.manufacturerName)
|
||
|
* IsConnected(INT.index,ModelName.modelName)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::IsConnected(CONST INT index, CONST DeviceType deviceType)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->IsConnected(index, deviceType);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/IsConnected(INT.index,ManufacturerName.manufacturerName)
|
||
|
* NAME
|
||
|
* BOOL IsConnected(INT index, ManufacturerName manufacturerName) --
|
||
|
* Check if a game controller is connected at the specified index.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* manufacturerName - name of the manufacturer the device has been
|
||
|
* made by. Possible names are:
|
||
|
* - LG_MANUFACTURER_LOGITECH
|
||
|
* - LG_MANUFACTURER_MICROSOFT
|
||
|
* - LG_MANUFACTURER_OTHER
|
||
|
|
||
|
* RETURN VALUE
|
||
|
* TRUE if a PC controller of specified manufacturer is connected,
|
||
|
* FALSE otherwise.
|
||
|
* SEE ALSO
|
||
|
* IsConnected(INT.index)
|
||
|
* IsConnected(INT.index,DeviceType.deviceType)
|
||
|
* IsConnected(INT.index,ModelName.modelName)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::IsConnected(CONST INT index, CONST ManufacturerName manufacturerName)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->IsConnected(index, manufacturerName);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/IsConnected(INT.index,ModelName.modelName)
|
||
|
* NAME
|
||
|
* BOOL IsConnected(INT index, ModelName modelName) -- Check if a game
|
||
|
* controller is connected at the specified index.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* modelName - name of the model of the device. Possible models are:
|
||
|
* - LG_MODEL_G27
|
||
|
* - LG_MODEL_G25
|
||
|
* - LG_MODEL_MOMO_RACING
|
||
|
* - LG_MODEL_MOMO_FORCE
|
||
|
* - LG_MODEL_DRIVING_FORCE_PRO
|
||
|
* - LG_MODEL_DRIVING_FORCE
|
||
|
* - LG_MODEL_NASCAR_RACING_WHEEL
|
||
|
* - LG_MODEL_FORMULA_FORCE
|
||
|
* - LG_MODEL_FORMULA_FORCE_GP
|
||
|
* - LG_MODEL_FORCE_3D_PRO
|
||
|
* - LG_MODEL_EXTREME_3D_PRO
|
||
|
* - LG_MODEL_FREEDOM_24
|
||
|
* - LG_MODEL_ATTACK_3
|
||
|
* - LG_MODEL_FORCE_3D
|
||
|
* - LG_MODEL_STRIKE_FORCE_3D
|
||
|
* - LG_MODEL_RUMBLEPAD
|
||
|
* - LG_MODEL_RUMBLEPAD_2
|
||
|
* - LG_MODEL_CORDLESS_RUMBLEPAD_2
|
||
|
* - LG_MODEL_CORDLESS_GAMEPAD
|
||
|
* - LG_MODEL_DUAL_ACTION_GAMEPAD
|
||
|
* - LG_MODEL_PRECISION_GAMEPAD_2
|
||
|
* - LG_MODEL_CHILLSTREAM
|
||
|
* RETURN VALUE
|
||
|
* TRUE if specific PC controller is connected, FALSE otherwise.
|
||
|
* SEE ALSO
|
||
|
* IsConnected(INT.index)
|
||
|
* IsConnected(INT.index,DeviceType.deviceType)
|
||
|
* IsConnected(INT.index,ManufacturerName.manufacturerName)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::IsConnected(CONST INT index, CONST ModelName modelName)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->IsConnected(index, modelName);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/GetState(INT.index)
|
||
|
* NAME
|
||
|
* DIJOYSTATE2* GetState(INT index) -- Get the state of the
|
||
|
* controller.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first game controller connected. Index 1 to the second game
|
||
|
* controller.
|
||
|
* RETURN VALUE
|
||
|
* DIJOYSTATE2 structure containing the device's positional
|
||
|
* information for axes, POVs and buttons.
|
||
|
* SEE ALSO
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
DIJOYSTATE2* Wheel::GetState(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->GetStateDInput(index);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/GetFriendlyProductName(INT.index)
|
||
|
* NAME
|
||
|
* LPCTSTR GetFriendlyProductName(INT index) -- Get the device's
|
||
|
* friendly product name.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first game controller connected. Index 1 to the second game
|
||
|
* controller.
|
||
|
* RETURN VALUE
|
||
|
* Device friendly product name.
|
||
|
* SEE ALSO
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
LPCTSTR Wheel::GetFriendlyProductName(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->GetFriendlyProductName(index);
|
||
|
}
|
||
|
|
||
|
return _T("");
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/ButtonTriggered(INT.index,INT.buttonNbr)
|
||
|
* NAME
|
||
|
* BOOL ButtonTriggered(INT index, INT buttonNbr) -- Check if a
|
||
|
* certain button was triggered.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* buttonNbr - the number of the button that we want to
|
||
|
* check. Possible numbers are: 0 to 127.
|
||
|
* RETURN VALUE
|
||
|
* TRUE if the button was triggered, FALSE otherwise.
|
||
|
* SEE ALSO
|
||
|
* ButtonIsPressed(INT.index,INT.buttonNbr)
|
||
|
* ButtonReleased(INT.index,INT.buttonNbr)
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::ButtonTriggered(CONST INT index, CONST INT buttonNbr)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->ButtonTriggered(index, buttonNbr);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/ButtonReleased(INT.index,INT.buttonNbr)
|
||
|
* NAME
|
||
|
* BOOL ButtonReleased(INT index, INT buttonNbr) -- Check if a certain
|
||
|
* button was released.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* buttonNbr - the number of the button that we want to
|
||
|
* check. Possible numbers are: 0 to 127.
|
||
|
* RETURN VALUE
|
||
|
* TRUE if the button was released, FALSE otherwise.
|
||
|
* SEE ALSO
|
||
|
* ButtonIsPressed(INT.index,INT.buttonNbr)
|
||
|
* ButtonTriggered(INT.index,INT.buttonNbr)
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::ButtonReleased(CONST INT index, CONST INT buttonNbr)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->ButtonReleased(index, buttonNbr);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/ButtonIsPressed(INT.index,INT.buttonNbr)
|
||
|
* NAME
|
||
|
* BOOL ButtonIsPressed(INT index, INT buttonNbr) -- Check if a
|
||
|
* certain button is being pressed.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* buttonNbr - the number of the button that we want to
|
||
|
* check. Possible numbers are: 0 to 127.
|
||
|
* RETURN VALUE
|
||
|
* TRUE if the button is being pressed, FALSE otherwise.
|
||
|
* SEE ALSO
|
||
|
* ButtonReleased(INT.index,INT.buttonNbr)
|
||
|
* ButtonTriggered(INT.index,INT.buttonNbr)
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::ButtonIsPressed(CONST INT index, CONST INT buttonNbr)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->ButtonIsPressed(index, buttonNbr);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/SetPreferredControllerProperties(ControllerPropertiesData.properties)
|
||
|
* NAME
|
||
|
* HRESULT SetPreferredControllerProperties(ControllerPropertiesData
|
||
|
* properties) -- set preferred wheel properties.
|
||
|
* INPUTS
|
||
|
* properties - structure containing all the fields to be set.
|
||
|
* RETURN VALUE
|
||
|
* E_INVALIDARG if argument is wrong (individual settings out of
|
||
|
* bounds).
|
||
|
* E_FAIL if Logitech Gaming Software is older than 5.03.
|
||
|
* S_OK otherwise.
|
||
|
* NOTES
|
||
|
* This function merely sets the game's preference. The Steering Wheel
|
||
|
* SDK will attempt to set the wheel's settings when necessary.
|
||
|
* SEE ALSO
|
||
|
* GetCurrentControllerProperties(INT.index,ControllerPropertiesData&.properties)
|
||
|
* GetShifterMode(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::SetPreferredControllerProperties(CONST ControllerPropertiesData properties)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerProperties);
|
||
|
|
||
|
HRESULT ret_ = E_FAIL;
|
||
|
|
||
|
if (NULL != m_controllerProperties)
|
||
|
{
|
||
|
ret_ = m_controllerProperties->SetPreferred(properties);
|
||
|
g_forceActuatorsResetTriggered = GetTickCount();
|
||
|
}
|
||
|
|
||
|
return ret_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/GetCurrentControllerProperties(INT.index,ControllerPropertiesData&.properties)
|
||
|
* NAME
|
||
|
* BOOL GetCurrentControllerProperties(INT index,
|
||
|
* ControllerPropertiesData& properties) -- get current properties.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller.
|
||
|
* properties - structure to receive current properties.
|
||
|
* RETURN VALUE
|
||
|
* TRUE if current value was received from Logitech driver.
|
||
|
* FALSE if function failed or current value is default value.
|
||
|
* NOTES
|
||
|
* Function will fail and return default properties if user has older
|
||
|
* than 5.03 Logitech Gaming Software installed.
|
||
|
* SEE ALSO
|
||
|
* SetPreferredControllerProperties(ControllerPropertiesData.properties)
|
||
|
* GetShifterMode(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::GetCurrentControllerProperties(CONST INT index, ControllerPropertiesData& properties)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerProperties);
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
|
||
|
if (NULL != m_controllerProperties && NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerProperties->GetCurrent(m_controllerInput->GetProductID(index), properties);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/GetShifterMode(INT.index)
|
||
|
* NAME
|
||
|
* INT GetShifterMode(INT index) -- get current shifter mode (gated or
|
||
|
* sequential).
|
||
|
* INPUTS
|
||
|
* index - index of the game controller.
|
||
|
* RETURN VALUE
|
||
|
* 1 if shifter is gated
|
||
|
* 0 if shifter is sequential
|
||
|
* -1 if unknown
|
||
|
* SEE ALSO
|
||
|
* SetPreferredControllerProperties(ControllerPropertiesData.properties)
|
||
|
* GetCurrentControllerProperties(INT.index,ControllerPropertiesData&.properties)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see an
|
||
|
* example.
|
||
|
******
|
||
|
*/
|
||
|
INT Wheel::GetShifterMode(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerProperties);
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
|
||
|
if (NULL != m_controllerProperties && NULL != m_controllerInput)
|
||
|
{
|
||
|
if (IsConnected(index, LG_MODEL_G25))
|
||
|
{
|
||
|
return m_controllerProperties->GetShifterMode(m_controllerInput->GetDeviceHandle(index));
|
||
|
}
|
||
|
else if (IsConnected(index, LG_MODEL_G27))
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayLeds(INT.index,FLOAT.currentRPM,FLOAT.rpmFirstLedTurnsOn,FLOAT.rpmRedLine)
|
||
|
* NAME
|
||
|
* HRESULT PlayLeds(INT index, FLOAT currentRPM, FLOAT
|
||
|
* rpmFirstLedTurnsOn, FLOAT rpmRedLine) -- play LEDs on G27.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller.
|
||
|
* currentRPM - current RPM.
|
||
|
* rpmFirstLedTurnsOn - RPM when first LEDs are to turn on.
|
||
|
* rpmRedLine - just below this RPM, all LEDs will be on. Just above,
|
||
|
* all LEDs will start flashing.
|
||
|
* SEE ALSO
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayLeds(CONST INT index, CONST FLOAT currentRPM, CONST FLOAT rpmFirstLedTurnsOn, CONST FLOAT rpmRedLine)
|
||
|
{
|
||
|
if (NULL == m_controllerInput)
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
LPDIRECTINPUTDEVICE8 deviceHandle_ = m_controllerInput->GetDeviceHandle(index);
|
||
|
if (NULL == deviceHandle_)
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
return m_leds.Play(deviceHandle_, currentRPM, rpmFirstLedTurnsOn, rpmRedLine);
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/HasForceFeedback(INT.index)
|
||
|
* NAME
|
||
|
* BOOL HasForceFeedback(INT index) -- Check if a game controller has
|
||
|
* force feedback.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
* RETURN VALUE
|
||
|
* TRUE if the specified device can do force feedback, FALSE
|
||
|
* otherwise.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::HasForceFeedback(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->HasForceFeedback(index);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/IsPlaying(INT.index,ForceType.forceType)
|
||
|
* NAME
|
||
|
* BOOL IsPlaying(INT index, ForceType forceType) -- check if a
|
||
|
* certain force effect is currently playing.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller that we want to check. Index
|
||
|
* 0 corresponds to the first game controller connected. Index 1 to
|
||
|
* the second game controller.
|
||
|
*
|
||
|
* forceType - the type of the force that we want to check to see if
|
||
|
* it is playing. Possible types are:
|
||
|
* - LG_FORCE_SPRING
|
||
|
* - LG_FORCE_CONSTANT
|
||
|
* - LG_FORCE_DAMPER
|
||
|
* - LG_FORCE_SIDE_COLLISION
|
||
|
* - LG_FORCE_FRONTAL_COLLISION
|
||
|
* - LG_FORCE_DIRT_ROAD
|
||
|
* - LG_FORCE_BUMPY_ROAD
|
||
|
* - LG_FORCE_SLIPPERY_ROAD
|
||
|
* - LG_FORCE_SURFACE_EFFECT
|
||
|
* - LG_FORCE_CAR_AIRBORNE
|
||
|
* RETURN VALUE
|
||
|
* TRUE if the force is playing, FALSE otherwise.
|
||
|
******
|
||
|
*/
|
||
|
BOOL Wheel::IsPlaying(CONST INT index, CONST ForceType forceType)
|
||
|
{
|
||
|
if (!IsConnected(index))
|
||
|
return FALSE;
|
||
|
|
||
|
if (!HasForceFeedback(index))
|
||
|
return FALSE;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL != m_controllerForce[index])
|
||
|
{
|
||
|
if (forceType == LG_FORCE_CAR_AIRBORNE)
|
||
|
{
|
||
|
return m_isAirborne[index];
|
||
|
}
|
||
|
|
||
|
return m_controllerForce[index]->IsPlaying(forceType);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/GenerateNonLinearValues(INT.index,INT.nonLinCoeff)
|
||
|
* NAME
|
||
|
* HRESULT GenerateNonLinearValues(int index, int nonLinCoeff) --
|
||
|
* Generate non-linear values for the game controller's axis.
|
||
|
* FUNCTION
|
||
|
* Gaming wheels/joysticks/game pads have very different behavior from
|
||
|
* real steering wheels. The reason for single-turn wheels is that
|
||
|
* they only do up to three quarters of a turn lock to lock, compared
|
||
|
* to about 3 turns for a real car.
|
||
|
* This directly affects the steering ratio (15:1 to 20:1 for a real
|
||
|
* car, but only 4:1 for a gaming wheel!). Joysticks and game pads
|
||
|
* have a much shorter range of movement than a real steering wheel as
|
||
|
* well.
|
||
|
* Because of this very short steering ratio or short range, the
|
||
|
* gaming wheel/joystick/game pad will feel highly sensitive which may
|
||
|
* make game play very difficult.
|
||
|
* Especially it may be difficult to drive in a straight line at speed
|
||
|
* (tendency to swerve back and forth).
|
||
|
* One way to get around this problem is to use a sensitivity
|
||
|
* curve. This is a curve that defines the sensitivity of the game
|
||
|
* controller depending on speed. This type of curve is usually used
|
||
|
* for game pads to make up for their low physical range. The result
|
||
|
* of applying such a curve is that at high speed the car's wheels
|
||
|
* will physically turn less than if the car is moving very slowly.
|
||
|
* For example the car's wheels may turn 60 degrees lock to lock at
|
||
|
* low speed but only 10 degrees lock to lock at higher speeds. If
|
||
|
* you calculate the resulting steering ratio for 10 degrees lock to
|
||
|
* lock you find that if you use a steering wheel that turns 180
|
||
|
* degrees lock to lock the ratio is equal to 180/10 = 18, which
|
||
|
* corresponds to a real car's steering ratio.
|
||
|
* If the sensitivity curve has been implemented for the
|
||
|
* wheel/joystick, adding a non-linear curve probably is not
|
||
|
* necessary. But you may find that even after applying a sensitivity
|
||
|
* curve, the car still feels a little twitchy on a straight line when
|
||
|
* driving fast. This may be because in your game you need more than
|
||
|
* 10 degrees lock to lock even at high speeds. Or maybe the car is
|
||
|
* moving at very high speeds where even a normal steering ratio is
|
||
|
* not good enough to eliminate high sensitivity.
|
||
|
* The best way at this point is to add a non-linear curve on top of
|
||
|
* the sensitivity curve.
|
||
|
* The effect of the non-linear curve with positive nonLinCoeff is
|
||
|
* that around center position the wheel/joystick will be less
|
||
|
* sensitive. Yet at locked position left or right the car's wheels
|
||
|
* will turn the same amount of degrees as without the non-linear
|
||
|
* response curve. Therefore the car will become more controllable on
|
||
|
* a straight line and game-play will be improved.
|
||
|
* There can sometimes be cases where the wheel does not feel
|
||
|
* sensitive enough. In that case it is possible to add a non-linear
|
||
|
* curve with the inverse effect (makes the steering more sensitive
|
||
|
* around center position) by using negative values for
|
||
|
* nonLinCoeff. This method lets you define a non-linearity
|
||
|
* coefficient which will determine how strongly non-linear the curve
|
||
|
* will be. When running the method it will generate a mapping table
|
||
|
* in the form of an array. For each of the 1024 entries in this array
|
||
|
* there will be a corresponding non-linear value which can be used as
|
||
|
* the wheel/joystick's axis position instead of the original
|
||
|
* value. See Sample_In-game_Implementation.cs for an example.
|
||
|
* INPUTS
|
||
|
* index - index to which the concerned game controller is connected.
|
||
|
* Index 0 corresponds to the first game controller connected. Index 1
|
||
|
* to the second game controller.
|
||
|
*
|
||
|
* nonLinCoeff - value representing how much non-linearity should be
|
||
|
* applied. Range is -100 to 100. 0 = linear curve, 100 = maximum
|
||
|
* non-linear curve with less sensitivity around center, -100 =
|
||
|
* maximum non-linearity with more sensitivity around center position.
|
||
|
* RETURN VALUE
|
||
|
* S_OK if successful, E_FAIL otherwise.
|
||
|
* SEE ALSO
|
||
|
* GetNonLinearValue(INT.index,INT.inputValue)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::GenerateNonLinearValues(CONST INT index, CONST INT nonLinCoeff)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->GenerateNonLinearValues(index, nonLinCoeff);
|
||
|
}
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/GetNonLinearValue(INT.index,INT.inputValue)
|
||
|
* NAME
|
||
|
* INT GetNonLinearValue(INT index, INT inputValue) -- Get a
|
||
|
* non-linear value from a table previously generated. This can be
|
||
|
* used for the response of a steering wheel.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first game controller connected. Index 1 to the second game
|
||
|
* controller.
|
||
|
*
|
||
|
* inputValue - value between -32768 and 32767 corresponding to
|
||
|
* original value of an axis.
|
||
|
* RETURN VALUE
|
||
|
* Value between -32768 and 32767 corresponding to the level of
|
||
|
* non-linearity previously set with GenerateNonLinearValues(...).
|
||
|
* SEE ALSO
|
||
|
* GenerateNonLinearValues(INT.index,INT.nonLinCoeff)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see an
|
||
|
* example.
|
||
|
******
|
||
|
*/
|
||
|
INT Wheel::GetNonLinearValue(CONST INT index, CONST INT inputValue)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL != m_controllerInput)
|
||
|
{
|
||
|
return m_controllerInput->GetNonLinearValue(index, inputValue);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlaySpringForce(INT.index,INT.offsetPercentage,INT.saturationPercentage,INT.coefficientPercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlaySpringForce(INT index, INT offsetPercentage, INT
|
||
|
* saturationPercentage, INT coefficientPercentage) -- Play the spring
|
||
|
* force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* offsetPercentage - Specifies the center of the spring force effect.
|
||
|
* Valid range is -100 to 100. Specifying 0 centers the spring. Any
|
||
|
* values outside this range are silently clamped.
|
||
|
*
|
||
|
* saturationPercentage - Specify the level of saturation of the
|
||
|
* spring force effect. The saturation stays constant after a certain
|
||
|
* deflection from the center of the spring. It is comparable to a
|
||
|
* magnitude. Valid ranges are 0 to 100. Any value higher than 100 is
|
||
|
* silently clamped.
|
||
|
*
|
||
|
* coefficientPercentage - Specify the slope of the effect strength
|
||
|
* increase relative to the amount of deflection from the center of
|
||
|
* the condition. Higher values mean that the saturation level is
|
||
|
* reached sooner. Valid ranges are -100 to 100. Any value outside
|
||
|
* the valid range is silently clamped.
|
||
|
* NOTES
|
||
|
* The dynamic spring force gets played on the X axis. If a joystick
|
||
|
* is connected, all forces generated by the Steering Wheel SDK will be
|
||
|
* played on the X axis. And in addition there will be a constant
|
||
|
* spring on the Y axis.
|
||
|
* SEE ALSO
|
||
|
* StopSpringForce(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlaySpringForce(CONST INT index, CONST INT offsetPercentage, CONST INT saturationPercentage, CONST INT coefficientPercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, or slippery force is playing, do nothing.
|
||
|
if (HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE
|
||
|
|| IsPlaying(index, LG_FORCE_SLIPPERY_ROAD))
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If connected device is a gamepad, do not play the force. A spring
|
||
|
// force with variable offset results in annoying constant vibration
|
||
|
// for the gamepad, so let's not play it.
|
||
|
if (m_controllerInput->IsConnected(index, LG_DEVICE_TYPE_GAMEPAD))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
SpringForceParams params_;
|
||
|
params_.m_diCondition[0].lOffset = Utils::FromPercentage(offsetPercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_diCondition[0].dwPositiveSaturation = Utils::FromPercentage(saturationPercentage, 0, 100, 0, DI_FFNOMINALMAX);
|
||
|
params_.m_diCondition[0].dwNegativeSaturation = params_.m_diCondition[0].dwPositiveSaturation;
|
||
|
params_.m_diCondition[0].lPositiveCoefficient = Utils::FromPercentage(coefficientPercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_diCondition[0].lNegativeCoefficient = params_.m_diCondition[0].lPositiveCoefficient;
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
// Direction for spring parameters is different for Microsoft joystick
|
||
|
// Also offset needs to be reversed for Microsoft joystick...
|
||
|
if (IsConnected(index, LG_DEVICE_TYPE_JOYSTICK) && IsConnected(index, LG_MANUFACTURER_MICROSOFT))
|
||
|
{
|
||
|
params_.m_diCondition[0].lOffset = -params_.m_diCondition[0].lOffset;
|
||
|
params_.m_rglDirection[0] = 0;
|
||
|
params_.m_rglDirection[1] = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
params_.m_rglDirection[0] = 1;
|
||
|
params_.m_rglDirection[1] = 0;
|
||
|
}
|
||
|
|
||
|
LogiSpringForce* force_ = (LogiSpringForce*)m_controllerForce[index]->GetForce(LG_FORCE_SPRING);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (m_controllerForce[index]->GetForce(LG_FORCE_SPRING)->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diCondition[0].lOffset != force_->GetCurrentForceParams().m_diCondition[0].lOffset
|
||
|
|| params_.m_diCondition[0].dwPositiveSaturation != force_->GetCurrentForceParams().m_diCondition[0].dwPositiveSaturation
|
||
|
|| params_.m_diCondition[0].lPositiveCoefficient != force_->GetCurrentForceParams().m_diCondition[0].lPositiveCoefficient)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
{
|
||
|
hr_ = force_->Start();
|
||
|
}
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopSpringForce(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopSpringForce(INT index) -- Stop the spring force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlaySpringForce(INT.index,INT.offsetPercentage,INT.saturationPercentage,INT.coefficientPercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopSpringForce(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_SPRING)->Stop();
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayConstantForce(INT.index,INT.magnitudePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlayConstantForce(INT index, INT magnitudePercentage) --
|
||
|
* Play the constant force.
|
||
|
* FUNCTION
|
||
|
* A constant force works best when continuously updated with a value
|
||
|
* tied to the physics engine.
|
||
|
* Tie the steering wheel/joystick to the car's physics engine via a
|
||
|
* vector force. This will create a centering spring effect, a sliding
|
||
|
* effect, a feeling for the car's inertia, and depending on the
|
||
|
* physics engine it should also give side collisions (wheel/joystick
|
||
|
* jerks in the opposite way of the wall the car just touched).
|
||
|
* The vector force could for example be calculated from the lateral
|
||
|
* force measured at the front tires. This vector force should be 0
|
||
|
* when at a stop or driving straight. When driving through a turn or
|
||
|
* when driving on a banked surface the vector force should have a
|
||
|
* magnitude that grows in a proportional way.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* magnitudePercentage - Specifies the magnitude of the constant force
|
||
|
* effect. A negative value reverses the direction of the force.
|
||
|
* Valid ranges for magnitudePercentage are -100 to 100. Any values
|
||
|
* outside the valid range are silently clamped.
|
||
|
* SEE ALSO
|
||
|
* StopConstantForce(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayConstantForce(CONST INT index, CONST INT magnitudePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If connected device is a gamepad, do not play the force. Since
|
||
|
// the constant force is usually tied to the physics and
|
||
|
// constantly playing in game it results in annoying constant
|
||
|
// vibration for the gamepad, so let's not play it.
|
||
|
if (m_controllerInput->IsConnected(index, LG_DEVICE_TYPE_GAMEPAD))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ConstantForceParams params_;
|
||
|
params_.m_diConstantForce.lMagnitude = Utils::FromPercentage(magnitudePercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
LogiConstantForce* force_ = (LogiConstantForce*)m_controllerForce[index]->GetForce(LG_FORCE_CONSTANT);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diConstantForce.lMagnitude != force_->GetCurrentForceParams().m_diConstantForce.lMagnitude)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
// For older Formula Force wheel, force a Start twice or
|
||
|
// else it doesn't work correctly.
|
||
|
if (IsConnected(index, LG_MODEL_FORMULA_FORCE))
|
||
|
{
|
||
|
hr_ = force_->Start();
|
||
|
hr_ = force_->Start();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopConstantForce(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopConstantForce(INT index) -- stop the constant force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlayConstantForce(INT.index,INT.magnitudePercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopConstantForce(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_CONSTANT)->Stop();
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayDamperForce(INT.index,INT.coefficientPercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlayDamperForce(INT index, INT coefficientPercentage) --
|
||
|
* Play the damper force.
|
||
|
* FUNCTION
|
||
|
* Simulate surfaces that are hard to turn on (mud, car at a stop) or
|
||
|
* slippery surfaces (snow, ice).
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* coefficientPercentage - specify the slope of the effect strength
|
||
|
* increase relative to the amount of deflection from the center of
|
||
|
* the condition. Higher values mean that the saturation level is
|
||
|
* reached sooner. Valid ranges are -100 to 100. Any value outside
|
||
|
* the valid range is silently clamped. -100 simulates a very slippery
|
||
|
* effect, +100 makes the wheel/joystick very hard to move, simulating
|
||
|
* the car at a stop or in mud.
|
||
|
* SEE ALSO
|
||
|
* StopDamperForce(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayDamperForce(CONST INT index, CONST INT coefficientPercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do
|
||
|
// nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE
|
||
|
|| m_controllerForce[index]->IsPlaying(LG_FORCE_SLIPPERY_ROAD))
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
DamperForceParams params_;
|
||
|
params_.m_diCondition[0].lPositiveCoefficient = Utils::FromPercentage(coefficientPercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_diCondition[0].lNegativeCoefficient = params_.m_diCondition[0].lPositiveCoefficient;
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
// Direction for damper parameters is different for Microsoft
|
||
|
// joystick
|
||
|
if (IsConnected(index, LG_DEVICE_TYPE_JOYSTICK) && IsConnected(index, LG_MANUFACTURER_MICROSOFT))
|
||
|
{
|
||
|
params_.m_rglDirection[0] = 0;
|
||
|
params_.m_rglDirection[1] = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
params_.m_rglDirection[0] = 1;
|
||
|
params_.m_rglDirection[1] = 0;
|
||
|
}
|
||
|
|
||
|
LogiDamperForce* force_ = (LogiDamperForce*)m_controllerForce[index]->GetForce(LG_FORCE_DAMPER);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diCondition[0].lPositiveCoefficient != force_->GetCurrentForceParams().m_diCondition[0].lPositiveCoefficient)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
{
|
||
|
hr_ = force_->Start();
|
||
|
}
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopDamperForce(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopDamperForce(INT index) -- stop the damper force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlayDamperForce(INT.index,INT.coefficientPercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopDamperForce(CONST INT index)
|
||
|
{
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_DAMPER)->Stop();
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlaySideCollisionForce(INT.index,INT.magnitudePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlaySideCollisionForce(INT index, INT magnitudePercentage)
|
||
|
* -- play a side collision force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* magnitudePercentage - Specifies the magnitude of the side collision
|
||
|
* force effect. A negative value reverses the direction of the force.
|
||
|
* Valid ranges for magnitudePercentage are -100 to 100. Any values
|
||
|
* outside the valid range are silently clamped.
|
||
|
* NOTES
|
||
|
* If you are already using a constant force tied to a vector force
|
||
|
* from the physics engine, then you may not need to add side
|
||
|
* collisions since depending on your physics engine the side
|
||
|
* collisions may automatically be taken care of by the constant
|
||
|
* force.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlaySideCollisionForce(CONST INT index, CONST INT magnitudePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If 2 collisions back to back, second weaker collision might overwrite first one, so add their magnitudes.
|
||
|
static DWORD timeAtSideCollision_ = 0;
|
||
|
static INT combinedMagnitudePercentage_ = 0;
|
||
|
|
||
|
DWORD currentTime_ = GetTickCount();
|
||
|
|
||
|
if (currentTime_ - timeAtSideCollision_ > LG_COLLISION_EFFECT_DURATION)
|
||
|
{
|
||
|
combinedMagnitudePercentage_ = magnitudePercentage;
|
||
|
timeAtSideCollision_ = currentTime_;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
combinedMagnitudePercentage_ = min(combinedMagnitudePercentage_ + magnitudePercentage, 100);
|
||
|
}
|
||
|
|
||
|
SideCollisionEffectParams params_;
|
||
|
params_.m_diConstantForce.lMagnitude = Utils::FromPercentage(combinedMagnitudePercentage_, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
LogiSideCollisionEffect* force_ = (LogiSideCollisionEffect*)m_controllerForce[index]->GetForce(LG_FORCE_SIDE_COLLISION);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diConstantForce.lMagnitude != force_->GetCurrentForceParams().m_diConstantForce.lMagnitude)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
// For older Formula Force wheel, we need to stop the force before re-starting it.
|
||
|
if (IsConnected(index, LG_MODEL_FORMULA_FORCE))
|
||
|
{
|
||
|
hr_ = force_->Stop();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayFrontalCollisionForce(INT.index,INT.magnitudePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlayFrontalCollisionForce(INT index, INT
|
||
|
* magnitudePercentage) -- Play a frontal collision force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* magnitudePercentage - specifies the magnitude of the frontal
|
||
|
* collision force effect. Valid ranges for magnitudePercentage are 0
|
||
|
* to 100. Values higher than 100 are silently clamped.
|
||
|
* SEE ALSO
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayFrontalCollisionForce(CONST INT index, CONST INT magnitudePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If 2 collisions back to back, second weaker collision might overwrite first one, so add their magnitudes.
|
||
|
static DWORD timeAtFrontalCollision_ = 0;
|
||
|
static INT combinedMagnitudePercentage_ = 0;
|
||
|
|
||
|
DWORD currentTime_ = GetTickCount();
|
||
|
|
||
|
if (currentTime_ - timeAtFrontalCollision_ > LG_COLLISION_EFFECT_DURATION)
|
||
|
{
|
||
|
combinedMagnitudePercentage_ = magnitudePercentage;
|
||
|
timeAtFrontalCollision_ = currentTime_;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
combinedMagnitudePercentage_ = min(combinedMagnitudePercentage_ + magnitudePercentage, 100);
|
||
|
}
|
||
|
|
||
|
FrontalCollisionEffectParams params_;
|
||
|
params_.m_diPeriodic.dwMagnitude = Utils::FromPercentage(combinedMagnitudePercentage_, 0, 100, 0, DI_FFNOMINALMAX);
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
LogiFrontalCollisionEffect* force_ = (LogiFrontalCollisionEffect*)m_controllerForce[index]->GetForce(LG_FORCE_FRONTAL_COLLISION);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diPeriodic.dwMagnitude != force_->GetCurrentForceParams().m_diPeriodic.dwMagnitude)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
// For older Formula Force wheel, we need to stop the force before re-starting it.
|
||
|
if (IsConnected(index, LG_MODEL_FORMULA_FORCE))
|
||
|
{
|
||
|
hr_ = force_->Stop();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayDirtRoadEffect(INT.index,INT.magnitudePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlayDirtRoadEffect(INT index, INT magnitudePercentage) --
|
||
|
* Play a surface effect that feels like driving on a dirt road.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* magnitudePercentage - Specifies the magnitude of the dirt road
|
||
|
* effect. Valid ranges for magnitudePercentage are 0 to 100. Values
|
||
|
* higher than 100 are silently clamped.
|
||
|
* SEE ALSO
|
||
|
* StopDirtRoadEffect(INT.index)
|
||
|
* PlaySurfaceEffect(INT.index,PeriodicType.type,INT.magnitude,INT.period)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayDirtRoadEffect(CONST INT index, CONST INT magnitudePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If older Formula Force wheel, don't play periodic effect cause it gets all screwy.
|
||
|
if (IsConnected(index, LG_MODEL_FORMULA_FORCE))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
DirtRoadEffectParams params_;
|
||
|
params_.m_diPeriodic.dwMagnitude = Utils::FromPercentage(magnitudePercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
LogiDirtRoadEffect* force_ = (LogiDirtRoadEffect*)m_controllerForce[index]->GetForce(LG_FORCE_DIRT_ROAD);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diPeriodic.dwMagnitude != force_->GetCurrentForceParams().m_diPeriodic.dwMagnitude)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr_ = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopDirtRoadEffect(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopDirtRoadEffect(INT index) -- stop the dirt road effect.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlayDirtRoadEffect(INT.index,INT.magnitudePercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopDirtRoadEffect(CONST INT index)
|
||
|
{
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_DIRT_ROAD)->Stop();
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayBumpyRoadEffect(INT.index,INT.magnitudePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlayBumpyRoadEffect(INT index, INT magnitudePercentage) --
|
||
|
* Play a surface effect that feels like driving on a bumpy road (like
|
||
|
* on cobblestones for example).
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* magnitudePercentage - Specifies the magnitude of the bumpy road
|
||
|
* effect. Valid ranges for magnitudePercentage are 0 to 100. Values
|
||
|
* higher than 100 are silently clamped.
|
||
|
* SEE ALSO
|
||
|
* StopBumpyRoadEffect(INT.index)
|
||
|
* PlaySurfaceEffect(INT.index,PeriodicType.type,INT.magnitudePercentage,INT.period)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayBumpyRoadEffect(CONST INT index, CONST INT magnitudePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
BumpyRoadEffectParams params_;
|
||
|
params_.m_diPeriodic.dwMagnitude = Utils::FromPercentage(magnitudePercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
LogiBumpyRoadEffect* force_ = (LogiBumpyRoadEffect*)m_controllerForce[index]->GetForce(LG_FORCE_BUMPY_ROAD);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diPeriodic.dwMagnitude != force_->GetCurrentForceParams().m_diPeriodic.dwMagnitude)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr_ = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopBumpyRoadEffect(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopBumpyRoadEffect(INT index) -- stop the bumpy road
|
||
|
* effect.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlayBumpyRoadEffect(INT.index,INT.magnitudePercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopBumpyRoadEffect(CONST INT index)
|
||
|
{
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_BUMPY_ROAD)->Stop();
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlaySlipperyRoadEffect(INT.index,INT.magnitudePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlaySlipperyRoadEffect(INT index, INT magnitudePercentage)
|
||
|
* -- Play a slippery road effect (snow, ice).
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* magnitudePercentage - Specifies the magnitude of the slippery road
|
||
|
* effect. Valid ranges for magnitudePercentage are 0 to 100. 100
|
||
|
* corresponds to the most slippery effect.
|
||
|
* SEE ALSO
|
||
|
* StopSlipperyRoadEffect(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlaySlipperyRoadEffect(CONST INT index, CONST INT magnitudePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (IsPlaying(index, LG_FORCE_SPRING))
|
||
|
{
|
||
|
StopSpringForce(index);
|
||
|
m_springWasPlaying[index] = TRUE;
|
||
|
}
|
||
|
|
||
|
if (IsPlaying(index, LG_FORCE_DAMPER))
|
||
|
{
|
||
|
StopDamperForce(index);
|
||
|
m_damperWasPlaying[index] = TRUE;
|
||
|
}
|
||
|
|
||
|
SlipperyRoadEffectParams params_;
|
||
|
params_.m_diCondition[0].lPositiveCoefficient = -Utils::FromPercentage(magnitudePercentage, 0, 100, 0, DI_FFNOMINALMAX);
|
||
|
params_.m_diCondition[0].lNegativeCoefficient = params_.m_diCondition[0].lPositiveCoefficient;
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
// Direction for damper parameters is different for Microsoft joystick
|
||
|
if (IsConnected(index, LG_DEVICE_TYPE_JOYSTICK) && IsConnected(index, LG_MANUFACTURER_MICROSOFT))
|
||
|
{
|
||
|
params_.m_rglDirection[0] = 0;
|
||
|
params_.m_rglDirection[1] = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
params_.m_rglDirection[0] = 1;
|
||
|
params_.m_rglDirection[1] = 0;
|
||
|
}
|
||
|
|
||
|
LogiSlipperyRoadEffect* force_ = (LogiSlipperyRoadEffect*)m_controllerForce[index]->GetForce(LG_FORCE_SLIPPERY_ROAD);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diCondition[0].lPositiveCoefficient != force_->GetCurrentForceParams().m_diCondition[0].lPositiveCoefficient)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopSlipperyRoadEffect(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopSlipperyRoadEffect(INT index) -- stop the slippery road
|
||
|
* effect.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlaySlipperyRoadEffect(INT.index,INT.magnitudePercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopSlipperyRoadEffect(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_;
|
||
|
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (FAILED(hr_ = m_controllerForce[index]->GetForce(LG_FORCE_SLIPPERY_ROAD)->Stop()))
|
||
|
return hr_;
|
||
|
|
||
|
if (m_springWasPlaying[index] == TRUE)
|
||
|
{
|
||
|
PlaySpringForce(index);
|
||
|
m_springWasPlaying[index] = FALSE;
|
||
|
}
|
||
|
|
||
|
if (m_damperWasPlaying[index] == TRUE)
|
||
|
{
|
||
|
PlayDamperForce(index);
|
||
|
m_damperWasPlaying[index] = FALSE;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlaySurfaceEffect(INT.index,PeriodicType.type,INT.magnitudePercentage,INT.period)
|
||
|
* NAME
|
||
|
* HRESULT PlaySurfaceEffect(INT index, PeriodicType type, INT
|
||
|
* magnitudePercentage, INT period) -- play any type of rumble to
|
||
|
* simulate surface effects.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
*
|
||
|
* type - Specifies the type of force effect. Can be one of the
|
||
|
* following values:
|
||
|
* - PeriodicType.LG_TYPE_SINE
|
||
|
* - PeriodicType.LG_TYPE_SQUARE
|
||
|
*
|
||
|
* magnitudePercentage - Specifies the magnitude of the surface
|
||
|
* effect. Valid ranges for magnitudePercentage are 0 to 100. Values
|
||
|
* higher than 100 are silently clamped.
|
||
|
*
|
||
|
* period - Specifies the period of the periodic force effect. The
|
||
|
* value is the duration for one full cycle of the periodic function
|
||
|
* measured in milliseconds. A good range of values for the period is
|
||
|
* 20 ms (sand) to 120 ms (wooden bridge or cobblestones). For a
|
||
|
* surface effect the period should not be any bigger than 150 ms.
|
||
|
* SEE ALSO
|
||
|
* StopSurfaceEffect(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlaySurfaceEffect(CONST INT index, CONST PeriodicType type, CONST INT magnitudePercentage, CONST INT period)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If older Formula Force wheel, don't play periodic effect cause
|
||
|
// it gets all screwy.
|
||
|
if (IsConnected(index, LG_MODEL_FORMULA_FORCE))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
SurfaceEffectParams params_;
|
||
|
params_.m_diPeriodic.dwMagnitude = Utils::FromPercentage(magnitudePercentage, -100, 100, -DI_FFNOMINALMAX, DI_FFNOMINALMAX);
|
||
|
params_.m_diPeriodic.dwPeriod = period * 1000;
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
switch(type)
|
||
|
{
|
||
|
case LG_TYPE_SINE:
|
||
|
params_.m_type = &GUID_Sine;
|
||
|
break;
|
||
|
case LG_TYPE_SQUARE:
|
||
|
params_.m_type = &GUID_Square;
|
||
|
break;
|
||
|
case LG_TYPE_TRIANGLE:
|
||
|
params_.m_type = &GUID_Triangle;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
LogiSurfaceEffect* force_ = (LogiSurfaceEffect*)m_controllerForce[index]->GetForce(LG_FORCE_SURFACE_EFFECT);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if type different, unload force, create new one
|
||
|
if (params_.m_type != force_->GetCurrentForceParams().m_type)
|
||
|
{
|
||
|
if FAILED(hr_ = force_->Unload())
|
||
|
LOGIWHEELTRACE(_T("PlaySurfaceEffect; Failed to unload force\n"));
|
||
|
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else if (params_.m_diPeriodic.dwMagnitude != force_->GetCurrentForceParams().m_diPeriodic.dwMagnitude
|
||
|
|| params_.m_diPeriodic.dwPeriod != force_->GetCurrentForceParams().m_diPeriodic.dwPeriod
|
||
|
|| params_.m_diPeriodic.lOffset != force_->GetCurrentForceParams().m_diPeriodic.lOffset)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr_ = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopSurfaceEffect(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopSurfaceEffect(INT index) -- stop the surface effect.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlaySurfaceEffect(INT.index,PeriodicType.type,INT.magnitudePercentage,INT.period)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopSurfaceEffect(CONST INT index)
|
||
|
{
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_SURFACE_EFFECT)->Stop();
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlayCarAirborne(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT PlayCarAirborne(INT index) -- play an effect that simulates
|
||
|
* a car that is airborne or where the front wheels do not touch the
|
||
|
* ground.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* StopCarAirborne(INT.index)
|
||
|
* SampleInGameImplementation.cpp or SteeringWheelSDKDemo.cpp to see
|
||
|
* an example.
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlayCarAirborne(CONST INT index)
|
||
|
{
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (m_isAirborne[index] == FALSE)
|
||
|
{
|
||
|
m_isAirborne[index] = TRUE;
|
||
|
|
||
|
if (IsPlaying(index, LG_FORCE_SPRING))
|
||
|
{
|
||
|
StopSpringForce(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_SPRING] = TRUE;
|
||
|
}
|
||
|
if (IsPlaying(index, LG_FORCE_CONSTANT))
|
||
|
{
|
||
|
StopConstantForce(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_CONSTANT] = TRUE;
|
||
|
}
|
||
|
if (IsPlaying(index, LG_FORCE_DAMPER))
|
||
|
{
|
||
|
StopDamperForce(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_DAMPER] = TRUE;
|
||
|
}
|
||
|
if (IsPlaying(index, LG_FORCE_DIRT_ROAD))
|
||
|
{
|
||
|
StopDirtRoadEffect(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_DIRT_ROAD] = TRUE;
|
||
|
}
|
||
|
if (IsPlaying(index, LG_FORCE_BUMPY_ROAD))
|
||
|
{
|
||
|
StopBumpyRoadEffect(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_BUMPY_ROAD] = TRUE;
|
||
|
}
|
||
|
if (IsPlaying(index, LG_FORCE_SLIPPERY_ROAD))
|
||
|
{
|
||
|
StopSlipperyRoadEffect(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_SLIPPERY_ROAD] = TRUE;
|
||
|
}
|
||
|
if (IsPlaying(index, LG_FORCE_SURFACE_EFFECT))
|
||
|
{
|
||
|
StopSurfaceEffect(index);
|
||
|
m_wasPlayingBeforeAirborne[index][LG_FORCE_SURFACE_EFFECT] = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopCarAirborne(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopCarAirborne(INT index) -- stop the car airborne effect
|
||
|
* and resume any forces that were playing before the car was
|
||
|
* airborne.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller. Index 0 corresponds to the
|
||
|
* first wheel/joystick connected. Index 1 to the second
|
||
|
* wheel/joystick.
|
||
|
* SEE ALSO
|
||
|
* PlayCarAirborne(INT.index)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopCarAirborne(CONST INT index)
|
||
|
{
|
||
|
m_isAirborne[index] = FALSE;
|
||
|
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_SPRING] == TRUE)
|
||
|
{
|
||
|
PlaySpringForce(index);
|
||
|
}
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_CONSTANT] == TRUE)
|
||
|
{
|
||
|
PlayConstantForce(index);
|
||
|
}
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_DAMPER] == TRUE)
|
||
|
{
|
||
|
PlayDamperForce(index);
|
||
|
}
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_DIRT_ROAD] == TRUE)
|
||
|
{
|
||
|
PlayDirtRoadEffect(index);
|
||
|
}
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_BUMPY_ROAD] == TRUE)
|
||
|
{
|
||
|
PlayBumpyRoadEffect(index);
|
||
|
}
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_SLIPPERY_ROAD] == TRUE)
|
||
|
{
|
||
|
PlaySlipperyRoadEffect(index);
|
||
|
}
|
||
|
if (m_wasPlayingBeforeAirborne[index][LG_FORCE_SURFACE_EFFECT] == TRUE)
|
||
|
{
|
||
|
PlaySurfaceEffect(index);
|
||
|
}
|
||
|
|
||
|
// re-initialize variables
|
||
|
for (INT jj = 0; jj < LG_NUMBER_FORCE_EFFECTS; jj++)
|
||
|
{
|
||
|
m_wasPlayingBeforeAirborne[index][jj] = FALSE;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/PlaySoftstopForce(INT.index,INT.usableRangePercentage)
|
||
|
* NAME
|
||
|
* HRESULT PlaySoftstopForce(INT index, INT usableRangePercentage) --
|
||
|
* Play a spring force that acts like a soft stop in order to limit a
|
||
|
* wheel's range.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller.
|
||
|
*
|
||
|
* usableRangePercentage - Specifies the deadband in percentage of the
|
||
|
* softstop force effect.
|
||
|
* SEE ALSO
|
||
|
* StopSoftstopForce(INT.index)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::PlaySoftstopForce(CONST INT index, CONST INT usableRangePercentage)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
SoftstopForceParams params_;
|
||
|
params_.m_diCondition[0].lDeadBand = Utils::FromPercentage(usableRangePercentage, 0, 100, 0, DI_FFNOMINALMAX);
|
||
|
params_.m_numFFAxes = m_controllerInput->GetNumberFFAxesDInput(index);
|
||
|
|
||
|
LogiSoftstopForce* force_ = (LogiSoftstopForce*)m_controllerForce[index]->GetForce(LG_FORCE_SOFTSTOP);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
{
|
||
|
hr_ = force_->CreateEffect(params_);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params_.m_diCondition[0].lDeadBand != force_->GetCurrentForceParams().m_diCondition[0].lDeadBand)
|
||
|
{
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
/****f* Steering.Wheel.SDK/StopSoftstopForce(INT.index)
|
||
|
* NAME
|
||
|
* HRESULT StopSoftstopForce(INT index) -- stop the "softstop" spring
|
||
|
* force.
|
||
|
* INPUTS
|
||
|
* index - index of the game controller.
|
||
|
* SEE ALSO
|
||
|
* PlaySoftstopForce(INT.index,INT.usableRangePercentage)
|
||
|
******
|
||
|
*/
|
||
|
HRESULT Wheel::StopSoftstopForce(CONST INT index)
|
||
|
{
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
return m_controllerForce[index]->GetForce(LG_FORCE_SOFTSTOP)->Stop();
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlaySpringForce(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE
|
||
|
|| m_controllerForce[index]->IsPlaying(LG_FORCE_SLIPPERY_ROAD))
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LogiSpringForce* force_ = (LogiSpringForce*)m_controllerForce[index]->GetForce(LG_FORCE_SPRING);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
SpringForceParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlayConstantForce(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do
|
||
|
// nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LogiConstantForce* force_ = (LogiConstantForce*)m_controllerForce[index]->GetForce(LG_FORCE_CONSTANT);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
ConstantForceParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlayDamperForce(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, or
|
||
|
// slippery road playing do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE
|
||
|
|| m_controllerForce[index]->IsPlaying(LG_FORCE_SLIPPERY_ROAD))
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LogiDamperForce* force_ = (LogiDamperForce*)m_controllerForce[index]->GetForce(LG_FORCE_DAMPER);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
DamperForceParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlayDirtRoadEffect(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LogiDirtRoadEffect* force_ = (LogiDirtRoadEffect*)m_controllerForce[index]->GetForce(LG_FORCE_DIRT_ROAD);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
DirtRoadEffectParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlayBumpyRoadEffect(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// If older Formula Force wheel, don't play periodic effect cause
|
||
|
// it gets all screwy.
|
||
|
if (IsConnected(index, LG_MODEL_FORMULA_FORCE))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
LogiBumpyRoadEffect* force_ = (LogiBumpyRoadEffect*)m_controllerForce[index]->GetForce(LG_FORCE_BUMPY_ROAD);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
BumpyRoadEffectParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlaySlipperyRoadEffect(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LogiSlipperyRoadEffect* force_ = (LogiSlipperyRoadEffect*)m_controllerForce[index]->GetForce(LG_FORCE_SLIPPERY_ROAD);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
SlipperyRoadEffectParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
HRESULT Wheel::PlaySurfaceEffect(CONST INT index)
|
||
|
{
|
||
|
HRESULT hr_ = E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerForce[index]);
|
||
|
if (NULL == m_controllerForce[index])
|
||
|
return E_FAIL;
|
||
|
|
||
|
_ASSERT(NULL != m_controllerInput);
|
||
|
if (NULL == m_controllerInput)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If no controller connected, or no ff, or car airborne, do nothing.
|
||
|
if (m_controllerInput->HasForceFeedback(index) == FALSE
|
||
|
|| m_isAirborne[index] == TRUE)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LogiSurfaceEffect* force_ = (LogiSurfaceEffect*)m_controllerForce[index]->GetForce(LG_FORCE_SURFACE_EFFECT);
|
||
|
|
||
|
_ASSERT(NULL != force_);
|
||
|
if (NULL == force_)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (force_->GetEffectHandle()== NULL)
|
||
|
return E_FAIL;
|
||
|
|
||
|
SurfaceEffectParams params_ = force_->GetCurrentForceParams();
|
||
|
hr_ = force_->SetParameters(params_);
|
||
|
|
||
|
if (!force_->IsPlaying())
|
||
|
hr_ = force_->Start();
|
||
|
|
||
|
return hr_;
|
||
|
}
|
||
|
|
||
|
LRESULT CALLBACK WheelWindowProc(HWND hwnd, UINT message,
|
||
|
WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
BOOL activateValue_ = FALSE;
|
||
|
|
||
|
DEV_BROADCAST_HDR* pHeader_ = NULL;
|
||
|
|
||
|
switch (message)
|
||
|
{
|
||
|
case WM_ACTIVATEAPP:
|
||
|
activateValue_ = static_cast<BOOL>(wParam);
|
||
|
if (activateValue_)
|
||
|
{
|
||
|
g_forceActuatorsResetTriggered = GetTickCount();
|
||
|
}
|
||
|
/*else
|
||
|
{
|
||
|
}*/
|
||
|
break;
|
||
|
case WM_DEVICECHANGE:
|
||
|
switch (wParam)
|
||
|
{
|
||
|
case DBT_DEVICEARRIVAL:
|
||
|
//LOGICONTROLLERTRACE(_T("DBT_DEVICEARRIVAL\n"));
|
||
|
pHeader_ = (DEV_BROADCAST_HDR*)lParam;
|
||
|
if (pHeader_)
|
||
|
{
|
||
|
if (pHeader_->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
||
|
{
|
||
|
g_forceActuatorsResetTriggered = GetTickCount();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case DBT_DEVICEREMOVECOMPLETE:
|
||
|
//LOGICONTROLLERTRACE(_T("DBT_DEVICEREMOVECOMPLETE\n"));
|
||
|
|
||
|
pHeader_ = (DEV_BROADCAST_HDR*)lParam;
|
||
|
if (pHeader_)
|
||
|
{
|
||
|
if (pHeader_->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
||
|
{
|
||
|
g_forceActuatorsResetTriggered = GetTickCount();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return CallWindowProc (g_OldWheelWnd, hwnd, message, wParam, lParam);
|
||
|
}
|