1
0
mirror of synced 2024-07-03 01:20:35 +00:00
G940LEDControl/LogitechSDK/SteeringWheel/Src/LogiWheel.cpp

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);
}