732 lines
18 KiB
C++
732 lines
18 KiB
C++
//=============================================================================
|
|
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
|
|
//
|
|
// File: inputmanager.cpp
|
|
//
|
|
// Description: Implementation for the InputManager class.
|
|
//
|
|
// History: + Created -- TBJ
|
|
//
|
|
//=============================================================================
|
|
|
|
//========================================
|
|
// System Includes
|
|
//========================================
|
|
#include <string.h> // ::strcmp()
|
|
//FTech
|
|
#include <raddebugwatch.hpp>
|
|
#include <raddebug.hpp>
|
|
#include <radcontroller.hpp>
|
|
|
|
//========================================
|
|
// Project Includes
|
|
//========================================
|
|
#include <input/inputmanager.h>
|
|
#ifdef RAD_WIN32
|
|
#include <input/usercontrollerWin32.h>
|
|
#else
|
|
#include <input/usercontroller.h>
|
|
#endif
|
|
#include <input/button.h>
|
|
|
|
#include <main/game.h>
|
|
#include <main/platform.h>
|
|
|
|
#include <data/gamedatamanager.h>
|
|
|
|
#ifndef WORLD_BUILDER
|
|
#include <memory/srrmemory.h>
|
|
#else
|
|
#define MEMTRACK_PUSH_GROUP(x)
|
|
#define MEMTRACK_POP_GROUP(x)
|
|
#define GMA_PERSISTENT 0
|
|
#define GMA_DEFAULT 0
|
|
#endif
|
|
|
|
#ifdef RAD_PS2
|
|
#include <main/ps2platform.h>
|
|
#include <libmtap.h>
|
|
#endif
|
|
|
|
#if defined RAD_XBOX
|
|
|
|
InputManager::eButtonMap RESET_BUTTONS[] =
|
|
{
|
|
InputManager::Start,
|
|
InputManager::Select
|
|
};
|
|
|
|
const int NUM_RESET_BUTTONS = 2;
|
|
|
|
#else //GC handled in gcmanager and we don't do this on the PC
|
|
|
|
InputManager::eButtonMap RESET_BUTTONS[] =
|
|
{
|
|
InputManager::Start
|
|
};
|
|
|
|
const int NUM_RESET_BUTTONS = 0;
|
|
|
|
#endif
|
|
|
|
const unsigned int RESET_TIMEOUT = 2000;
|
|
|
|
//******************************************************************************
|
|
// Global Data, Local Data, Local Classes
|
|
//******************************************************************************
|
|
|
|
//
|
|
// Static pointer to instance of singleton.
|
|
//
|
|
InputManager* InputManager::spInstance = NULL;
|
|
|
|
|
|
//******************************************************************************
|
|
// Public Member Functions
|
|
//******************************************************************************
|
|
|
|
// Creates the InputManager.
|
|
// This is a singleton so only one instance is allowed.
|
|
InputManager* InputManager::CreateInstance()
|
|
{
|
|
MEMTRACK_PUSH_GROUP( "InputManager" );
|
|
|
|
rAssert( spInstance == NULL );
|
|
|
|
spInstance = new InputManager;
|
|
MEMTRACK_POP_GROUP("InputManager");
|
|
|
|
return spInstance;
|
|
}
|
|
|
|
// Access point for the InputManager singleton.
|
|
InputManager* InputManager::GetInstance()
|
|
{
|
|
rAssert( spInstance != NULL );
|
|
|
|
return spInstance;
|
|
}
|
|
|
|
// Destroy the InputManager.singleton
|
|
void InputManager::DestroyInstance()
|
|
{
|
|
rAssert( spInstance != NULL );
|
|
|
|
delete spInstance;
|
|
spInstance = NULL;
|
|
}
|
|
|
|
|
|
void InputManager::Init()
|
|
{
|
|
|
|
MEMTRACK_PUSH_GROUP( "InputManager" );
|
|
::radControllerInitialize( this, GMA_DEFAULT );
|
|
|
|
mxIControllerSystem2 = radControllerSystemGet();
|
|
|
|
#ifdef RAD_PS2
|
|
// On PS2, check for initial button pushes.
|
|
m_isProScanButtonsPressed = PS2Platform::GetInstance()->CheckForStartupButtons( );
|
|
rDebugPrintf( "Do Progressive scan: %s\n", m_isProScanButtonsPressed ? "yup" : "nope" );
|
|
#endif
|
|
|
|
unsigned int i = 0;
|
|
|
|
for ( i = 0; i < Input::MaxControllers; i++ )
|
|
{
|
|
// preallocate run time controller structure.
|
|
mControllerArray[ i ].Create(i);
|
|
}
|
|
#ifndef RAD_WIN32
|
|
mxIControllerSystem2->RegisterConnectionChangeCallback( this );
|
|
#endif
|
|
rDebugString( "Just created User controller system\n" );
|
|
|
|
EnumerateControllers( );
|
|
MEMTRACK_POP_GROUP("InputManager");
|
|
|
|
}
|
|
|
|
|
|
void InputManager::Update( unsigned int timeinms )
|
|
{
|
|
// update the button timestamp (so we can tell when buttons were pressed)
|
|
Button::Tick(timeinms);
|
|
|
|
::radControllerSystemService();
|
|
|
|
// if controllers have been disconnected, change the state
|
|
if(mConnectStateChanged)
|
|
{
|
|
mConnectStateChanged = false;
|
|
EnumerateControllers( );
|
|
}
|
|
|
|
unsigned int i = 0;
|
|
|
|
// update physical controllers
|
|
bool resetting = false;
|
|
for ( i = 0; i < Input::MaxControllers; i++ )
|
|
{
|
|
if(mControllerArray[i].IsConnected())
|
|
{
|
|
mControllerArray[i].Update(timeinms);
|
|
|
|
if ( mResetEnabled &&
|
|
NUM_RESET_BUTTONS > 0 &&
|
|
!resetting &&
|
|
mControllerArray[i].GetInputValueRT( RESET_BUTTONS[ 0 ] ) > 0.5f &&
|
|
mControllerArray[i].GetInputValueRT( RESET_BUTTONS[ 1 ] ) > 0.5f )
|
|
{
|
|
resetting = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef RAD_XBOX
|
|
if ( mResetEnabled )
|
|
{
|
|
if ( !resetting )
|
|
{
|
|
mResetTimeout = 0;
|
|
mIsResetting = false;
|
|
}
|
|
else if ( resetting && !mIsResetting )
|
|
{
|
|
mResetTimeout = RESET_TIMEOUT;
|
|
mIsResetting = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
// broadcast new game state if it has changed
|
|
if(mChangeGameState)
|
|
{
|
|
for ( i = 0; i < Input::MaxControllers; i++ )
|
|
{
|
|
// TC: Why does controller have to be connected for its game state to be updated?
|
|
// Having the 'if' conditional here causes a problem when the controller is
|
|
// disconnnected during a state when it's non-active.
|
|
//
|
|
// if(mControllerArray[i].IsConnected())
|
|
{
|
|
mControllerArray[i].SetGameState(mGameState);
|
|
}
|
|
}
|
|
mChangeGameState = false;
|
|
}
|
|
|
|
if ( mResetEnabled && mIsResetting && mResetTimeout >= 0 )
|
|
{
|
|
if ( mResetTimeout <= timeinms )
|
|
{
|
|
GetGame()->GetPlatform()->LaunchDashboard();
|
|
mResetTimeout = 0;
|
|
mIsResetting = false;
|
|
}
|
|
else
|
|
{
|
|
mResetTimeout -= timeinms;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void InputManager::OnControllerConnectionStatusChange( IRadController * pIController2 )
|
|
{
|
|
mConnectStateChanged = true;
|
|
}
|
|
|
|
bool InputManager::IsControllerInPort( int portnum ) const
|
|
{
|
|
rAssert(portnum < static_cast< int >( Input::MaxControllers ) );
|
|
return mControllerArray[portnum].IsConnected();
|
|
}
|
|
|
|
void InputManager::ToggleRumble( bool on )
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < Input::MaxControllers; ++i )
|
|
{
|
|
if ( mControllerArray[ i ].IsConnected() )
|
|
{
|
|
mControllerArray[ i ].SetRumble( on );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// InputManager::SetRumbleEnabled
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( bool isEnabled )
|
|
//
|
|
// Return: nothing
|
|
//
|
|
//=============================================================================
|
|
void InputManager::SetRumbleEnabled( bool isEnabled )
|
|
{
|
|
mIsRumbleEnabled = isEnabled;
|
|
}
|
|
|
|
void InputManager::SetRumbleForDevice( int controllerId, bool bRumbleOn )
|
|
{
|
|
if ( (unsigned int)controllerId < Input::MaxControllers)
|
|
{
|
|
mControllerArray[controllerId].SetRumble( bRumbleOn );
|
|
}
|
|
}
|
|
|
|
|
|
bool InputManager::IsRumbleOnForDevice( int controllerId ) const
|
|
{
|
|
if ( (unsigned int)controllerId < Input::MaxControllers)
|
|
{
|
|
return mControllerArray[controllerId].IsRumbleOn( );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void InputManager::TriggerRumblePulse( int controllerId )
|
|
{
|
|
if ( (unsigned int)controllerId < Input::MaxControllers)
|
|
{
|
|
mControllerArray[ controllerId ].PulseRumble();
|
|
}
|
|
}
|
|
|
|
// Returns the value of the input point 'inputIndex' owned by the controller at
|
|
// controllerIndex.
|
|
float InputManager::GetValue( unsigned int controllerIndex, unsigned int inputIndex ) const
|
|
{
|
|
rAssert( controllerIndex < Input::MaxControllers);
|
|
if ( controllerIndex < Input::MaxControllers)
|
|
{
|
|
return mControllerArray[ controllerIndex ].GetInputValue( inputIndex );
|
|
}
|
|
else
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
// Returns a const pointer to the controller at controller index.
|
|
UserController* InputManager::GetController( unsigned int controllerIndex )
|
|
{
|
|
rAssert( controllerIndex < Input::MaxControllers );
|
|
if ( controllerIndex < Input::MaxControllers )
|
|
{
|
|
return &mControllerArray[ controllerIndex ];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// Associate this device with a game object.
|
|
int InputManager::RegisterMappable( unsigned int index, Mappable *pMappable )
|
|
{
|
|
int handle = Input::INVALID_CONTROLLERID;
|
|
if ( index < Input::MaxControllers)
|
|
{
|
|
handle = mControllerArray[ index ].RegisterMappable( pMappable );
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
|
|
// Remove associations between this device and a game object.
|
|
void InputManager::UnregisterMappable( unsigned int index, int handle )
|
|
{
|
|
if ( handle > Input::INVALID_CONTROLLERID )
|
|
{
|
|
if ( index < Input::MaxControllers)
|
|
{
|
|
mControllerArray[ index ].UnregisterMappable( handle );
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputManager::UnregisterMappable( unsigned int index, Mappable* mappable)
|
|
{
|
|
mControllerArray[ index ].UnregisterMappable( mappable );
|
|
}
|
|
|
|
void InputManager::UnregisterMappable( Mappable *pMappable )
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < Input::MaxControllers; ++i )
|
|
{
|
|
mControllerArray[ i ].UnregisterMappable( pMappable );
|
|
}
|
|
}
|
|
|
|
|
|
void InputManager::LoadData( const GameDataByte* dataBuffer, unsigned int numBytes )
|
|
{
|
|
mIsRumbleEnabled = ( dataBuffer[ 0 ] != 0 );
|
|
}
|
|
|
|
void InputManager::SaveData( GameDataByte* dataBuffer, unsigned int numBytes )
|
|
{
|
|
dataBuffer[ 0 ] = mIsRumbleEnabled ? ~0 : 0;
|
|
}
|
|
|
|
void InputManager::ResetData()
|
|
{
|
|
//Rumble does not RESET. This is a TRC thing.
|
|
//mIsRumbleEnabled = true;
|
|
}
|
|
|
|
//******************************************************************************
|
|
// Private Member Functions
|
|
//******************************************************************************
|
|
|
|
InputManager::InputManager()
|
|
:
|
|
mGameState(Input::ACTIVE_ALL),
|
|
mChangeGameState(false),
|
|
mConnectStateChanged(false),
|
|
mIsRumbleEnabled(true),
|
|
mIsResetting(false),
|
|
mResetEnabled( false ),
|
|
m_isProScanButtonsPressed( false )
|
|
{
|
|
for( int i = 0; i < MAX_PLAYERS; i++ )
|
|
{
|
|
m_registeredControllerID[ i ] = -1;
|
|
}
|
|
|
|
GetGameDataManager()->RegisterGameData( this, 1, "Input Manager" );
|
|
#ifdef RAD_WIN32
|
|
m_pFEMouse = new FEMouse;
|
|
#endif
|
|
#ifdef RAD_PS2
|
|
mLastMultitapStatus[0] = mLastMultitapStatus[1] = 0;
|
|
mCurMultitapStatus[0] = mCurMultitapStatus[1] = 0;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
InputManager::~InputManager()
|
|
{
|
|
ReleaseAllControllers();
|
|
|
|
#ifndef RAD_WIN32
|
|
mxIControllerSystem2->UnRegisterConnectionChangeCallback( this );
|
|
#endif
|
|
::radControllerTerminate();
|
|
#ifdef RAD_WIN32
|
|
delete m_pFEMouse;
|
|
m_pFEMouse = NULL;
|
|
#endif
|
|
}
|
|
|
|
void InputManager::EnumerateControllers( void )
|
|
{
|
|
// on the console the controller device and all the mappables are
|
|
// preallocated. So we don't have to create new associations.
|
|
//
|
|
#ifndef RAD_WIN32
|
|
ref< IRadController > xIC2;
|
|
#else
|
|
ref< IRadController > radController[ NUM_CONTROLLERTYPES ];
|
|
#endif
|
|
|
|
ReleaseAllControllers( );
|
|
|
|
bool somethingPluggedIn0 = false;
|
|
bool somethingPluggedIn1 = false;
|
|
|
|
unsigned int slot = 0;
|
|
unsigned int port = 0;
|
|
for ( port = 0; port < Input::MaxPorts; ++port )
|
|
{
|
|
for ( slot = 0; slot < Input::MaxSlots; ++slot )
|
|
{
|
|
unsigned int i = port * Input::MaxSlots + slot;
|
|
|
|
char szLocation[ 256 ];
|
|
|
|
#if defined(RAD_XBOX) || defined( RAD_PS2 )
|
|
sprintf( szLocation, "Port%d\\Slot%d", port, slot );
|
|
#elif defined(RAD_WIN32)
|
|
char szJoystickLoc[ 256 ];
|
|
char szMouseLoc[ 256 ];
|
|
char szWheelLoc[ 256 ];
|
|
|
|
sprintf( szLocation, "Keyboard%d", 0);
|
|
sprintf( szJoystickLoc, "Joystick%d", i);
|
|
sprintf( szMouseLoc, "Mouse%d", i);
|
|
sprintf( szWheelLoc, "SteeringWheel%d", i);
|
|
#else //This is GC
|
|
sprintf( szLocation, "Channel%d", i );
|
|
#endif
|
|
|
|
#ifndef RAD_WIN32
|
|
xIC2 = mxIControllerSystem2->GetControllerAtLocation( szLocation );
|
|
#else
|
|
radController[KEYBOARD] = mxIControllerSystem2->GetControllerAtLocation( szLocation );
|
|
radController[GAMEPAD] = mxIControllerSystem2->GetControllerAtLocation( szJoystickLoc );
|
|
radController[MOUSE] = mxIControllerSystem2->GetControllerAtLocation( szMouseLoc );
|
|
radController[STEERINGWHEEL] = mxIControllerSystem2->GetControllerAtLocation( szWheelLoc );
|
|
|
|
//Check to see if the steering wheel is on controller 0.
|
|
|
|
#endif
|
|
|
|
//
|
|
// Grab the controller device associated with the foundation controller.
|
|
//
|
|
UserController* controller = &mControllerArray[ i ];
|
|
|
|
|
|
#ifdef RAD_WIN32
|
|
// One keyboard has to be present. (might want to change later)
|
|
if ( (radController[KEYBOARD] == NULL || !radController[KEYBOARD]->IsConnected( )) && (i == 0) )
|
|
{
|
|
controller->NotifyDisconnect( );
|
|
}
|
|
else
|
|
{
|
|
controller->Initialize( radController );
|
|
controller->NotifyConnect( );
|
|
controller->LoadControllerMappings( );
|
|
|
|
for( int i = 0; i < NUM_CONTROLLERTYPES; i++ )
|
|
{
|
|
radController[i] = NULL;
|
|
}
|
|
}
|
|
#else
|
|
if ( xIC2 == NULL || !xIC2->IsConnected( ) )
|
|
{
|
|
controller->NotifyDisconnect( );
|
|
}
|
|
else
|
|
{
|
|
#ifdef RAD_PS2
|
|
if(strcmp( "PsxDualShock2", xIC2->GetType() ) == 0 )
|
|
{
|
|
controller->Initialize( xIC2 );
|
|
controller->NotifyConnect( );
|
|
controller->LoadControllerMappings( );
|
|
controller->SetRumble( IsRumbleEnabled() );
|
|
}
|
|
xIC2 = NULL;
|
|
|
|
if ( port == 0 )
|
|
{
|
|
somethingPluggedIn0 = true;
|
|
}
|
|
else
|
|
{
|
|
somethingPluggedIn1 = true;
|
|
}
|
|
#else
|
|
controller->Initialize( xIC2 );
|
|
controller->NotifyConnect( );
|
|
controller->LoadControllerMappings( );
|
|
controller->SetRumble( IsRumbleEnabled() );
|
|
|
|
xIC2 = NULL;
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef RAD_PS2
|
|
|
|
//TEST THE MULTITAP STATUS
|
|
if ( somethingPluggedIn0 || somethingPluggedIn1 )
|
|
{
|
|
if ( somethingPluggedIn0 )
|
|
{
|
|
mLastMultitapStatus[0] = sceMtapGetConnection(0);
|
|
}
|
|
|
|
if ( somethingPluggedIn1 )
|
|
{
|
|
mLastMultitapStatus[1] = sceMtapGetConnection(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef RAD_PS2
|
|
unsigned int i;
|
|
for ( i = 0; i < Input::MaxUSB; ++i )
|
|
{
|
|
char szLocation[ 256 ];
|
|
sprintf( szLocation, "USB%d", i );
|
|
|
|
xIC2 = mxIControllerSystem2->GetControllerAtLocation( szLocation );
|
|
//
|
|
// Grab the controller device associated with the foundation controller.
|
|
//
|
|
UserController* controller = &mControllerArray[ Input::USB0 + i ];
|
|
|
|
if ( xIC2 == NULL || !xIC2->IsConnected( ) )
|
|
{
|
|
controller->NotifyDisconnect( );
|
|
}
|
|
else
|
|
{
|
|
if ( xIC2->IsConnected( ) && strcmp( xIC2->GetClassification(), "Wheel" ) == 0 )
|
|
{
|
|
// Initialize the controller. This will notify all observers of the
|
|
// controller being added.
|
|
|
|
controller->Initialize( xIC2 );
|
|
controller->NotifyConnect( );
|
|
controller->LoadControllerMappings( );
|
|
}
|
|
else
|
|
{
|
|
controller->NotifyDisconnect( );
|
|
}
|
|
xIC2 = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//#ifdef RAD_DEBUG
|
|
char connectionMap[128] = "Controller status changed (connection : ";
|
|
|
|
for( port = 0; port < Input::MaxPorts; port++)
|
|
{
|
|
for( slot = 0; slot < Input::MaxSlots; slot++)
|
|
{
|
|
int index = port * Input::MaxSlots + slot;
|
|
if(mControllerArray[ index ].IsConnected())
|
|
{
|
|
strcat(connectionMap, "x");
|
|
}
|
|
else
|
|
{
|
|
strcat(connectionMap, "o");
|
|
}
|
|
}
|
|
strcat(connectionMap," ");
|
|
}
|
|
#ifdef RAD_PS2
|
|
for(unsigned int i = (Input::MaxSlots * Input::MaxPorts); i < Input::MaxControllers; ++i )
|
|
{
|
|
if ( mControllerArray[i].IsConnected() )
|
|
{
|
|
strcat(connectionMap,"U");
|
|
}
|
|
else
|
|
{
|
|
strcat(connectionMap, "o");
|
|
}
|
|
}
|
|
#endif
|
|
strcat(connectionMap,")\n");
|
|
|
|
rReleaseString(connectionMap);
|
|
//#endif
|
|
}
|
|
|
|
void InputManager::ReleaseAllControllers( void )
|
|
{
|
|
unsigned int i = 0;
|
|
for ( i = 0; i < Input::MaxControllers; i++ )
|
|
{
|
|
mControllerArray[ i ].ReleaseRadController( );
|
|
}
|
|
}
|
|
|
|
|
|
void InputManager::SetGameState( Input::ActiveState state )
|
|
{
|
|
//
|
|
// The only way to get out of the animated cam input state is to set it
|
|
// to the DEACTIVE_ANIM_CAM state, which actually sends you to active all.
|
|
// Perhaps the input system should really be a stack?
|
|
//
|
|
if( mGameState == Input::ACTIVE_ANIM_CAM )
|
|
{
|
|
if( state == Input::DEACTIVE_ANIM_CAM )
|
|
{
|
|
state = Input::ACTIVE_ALL;
|
|
}
|
|
else
|
|
{
|
|
state = Input::ACTIVE_ANIM_CAM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( state == Input::DEACTIVE_ANIM_CAM )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
mChangeGameState = true;
|
|
mGameState = state;
|
|
}
|
|
|
|
Input::ActiveState InputManager::GetGameState() const
|
|
{
|
|
return static_cast<Input::ActiveState>(mGameState);
|
|
}
|
|
|
|
|
|
void
|
|
InputManager::RegisterControllerID( int playerID, int controllerID )
|
|
{
|
|
rAssert( playerID >= 0 && playerID < MAX_PLAYERS );
|
|
|
|
m_registeredControllerID[ playerID ] = controllerID;
|
|
|
|
rTunePrintf( "*** Registered Controller ID [%d] for Player %d ***\n",
|
|
controllerID, playerID + 1 );
|
|
}
|
|
|
|
void
|
|
InputManager::UnregisterControllerID( int playerID )
|
|
{
|
|
rAssert( playerID >= 0 && playerID < MAX_PLAYERS );
|
|
|
|
m_registeredControllerID[ playerID ] = -1;
|
|
}
|
|
|
|
void
|
|
InputManager::UnregisterAllControllerID()
|
|
{
|
|
for( int i = 0; i < MAX_PLAYERS; i++ )
|
|
{
|
|
UnregisterControllerID( i );
|
|
}
|
|
}
|
|
|
|
#ifdef RAD_WIN32
|
|
|
|
void InputManager::StartRumbleEffects()
|
|
{
|
|
for( int i = 0; i < MAX_PLAYERS; i++ )
|
|
{
|
|
SetRumbleForDevice(i, true);
|
|
}
|
|
}
|
|
|
|
void InputManager::StopRumbleEffects()
|
|
{
|
|
for( int i = 0; i < MAX_PLAYERS; i++ )
|
|
{
|
|
SetRumbleForDevice(i, false);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|