mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 14:16:50 +00:00
696 lines
24 KiB
C++
696 lines
24 KiB
C++
//=========== Copyright Valve Corporation, All rights reserved. ===============//
|
|
//
|
|
// Purpose: Native Steam Controller Interface
|
|
//=============================================================================//
|
|
#include "inputsystem.h"
|
|
#include "key_translation.h"
|
|
#include "filesystem.h"
|
|
#include "steam/isteamcontroller.h"
|
|
#include "math.h"
|
|
|
|
#ifndef UINT64_MAX
|
|
const uint64 UINT64_MAX = 0xffffffffffffffff;
|
|
#endif
|
|
|
|
#if !defined( NO_STEAM )
|
|
#include "steam/steam_api.h"
|
|
#endif //NO_STEAM
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include <tier0/memdbgon.h>
|
|
|
|
ConVar sc_joystick_map( "sc_joystick_map", "1", FCVAR_ARCHIVE, "How to map the analog joystick deadzone and extents 0 = Scaled Cross, 1 = Concentric Mapping to Square." );
|
|
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_GYRO 32768
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_TRIGGER 32768
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_LEFT 32768
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_RIGHT 32767
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_DOWN 32768
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_UP 32767
|
|
#define STEAMPAD_MAX_ANALOGSAMPLE_MAX 32768
|
|
#define STEAMPAD_ANALOG_SCALE_LEFT(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_LEFT/( float )( STEAMPAD_MAX_ANALOGSAMPLE_LEFT-(x) ) )
|
|
#define STEAMPAD_ANALOG_SCALE_RIGHT(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_RIGHT/( float )( STEAMPAD_MAX_ANALOGSAMPLE_RIGHT-(x) ) )
|
|
#define STEAMPAD_ANALOG_SCALE_DOWN(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_DOWN/( float )( STEAMPAD_MAX_ANALOGSAMPLE_DOWN-(x) ) )
|
|
#define STEAMPAD_ANALOG_SCALE_UP(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_UP/( float )( STEAMPAD_MAX_ANALOGSAMPLE_UP-(x) ) )
|
|
|
|
|
|
#define STEAMPAD_ANALOG_TRIGGER_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_TRIGGER * 0.5f ) )
|
|
#define STEAMPAD_ANALOG_PAD_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.25f ) )
|
|
#define STEAMPAD_ANALOG_GYRO_THRESHOLD ( ( int ) ( STEAMPAD_MAX_ANALOGSAMPLE_GYRO * 0.3f ) )
|
|
#define STEAMPAD_DIGITAL_PAD_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.52f ) )
|
|
|
|
#define STEAMPAD_AXIS_REPEAT_INTERVAL_START 0.6f
|
|
#define STEAMPAD_AXIS_REPEAT_INTERVAL_END 0.05f
|
|
#define STEAMPAD_AXIS_REPEAT_CURVE_TIME 1.75f
|
|
|
|
#define PAD_ANALOG_BUTTON_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.285f ) )
|
|
#define PAD_ANALOG_BUTTON_THRESHOLD_STRONG ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.68f ) )
|
|
|
|
#define SQRT2 1.414213562
|
|
|
|
// key translation
|
|
typedef struct
|
|
{
|
|
uint64 steampadinput;
|
|
ButtonCode_t steampadkey;
|
|
} steampadInputTosteampadKey_t;
|
|
|
|
static const int s_nSteamPadDeadZoneTable[] =
|
|
{
|
|
STEAMPAD_ANALOG_PAD_THRESHOLD, // LEFTPAD_AXIS_X
|
|
STEAMPAD_ANALOG_PAD_THRESHOLD, // LEFTPAD_AXIS_Y
|
|
STEAMPAD_ANALOG_PAD_THRESHOLD, // RIGHTPAD_AXIS_X
|
|
STEAMPAD_ANALOG_PAD_THRESHOLD, // RIGHTPAD_AXIS_Y
|
|
STEAMPAD_ANALOG_TRIGGER_THRESHOLD, //LEFT_TRIGGER_AXIS
|
|
STEAMPAD_ANALOG_TRIGGER_THRESHOLD, //RIGHT_TRIGGER_AXIS
|
|
STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_PITCH
|
|
STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_ROLL
|
|
STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_YAW
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Counts the number of active gamepads connected
|
|
//-----------------------------------------------------------------------------
|
|
uint32 CInputSystem::GetNumSteamControllersConnected()
|
|
{
|
|
return m_unNumConnected;
|
|
}
|
|
|
|
struct SDigitalMenuAction
|
|
{
|
|
const char *strName;
|
|
ButtonCode_t buttonCode;
|
|
ControllerDigitalActionHandle_t handle;
|
|
bool bState[STEAM_CONTROLLER_MAX_COUNT];
|
|
bool bAwaitingDebounce[STEAM_CONTROLLER_MAX_COUNT];
|
|
};
|
|
|
|
static SDigitalMenuAction g_DigitalMenuActions[] = {
|
|
{ "menu_left", STEAMCONTROLLER_DPAD_LEFT, 0, { false }, { false } },
|
|
{ "menu_right", STEAMCONTROLLER_DPAD_RIGHT, 0, { false }, { false } },
|
|
{ "menu_up", STEAMCONTROLLER_DPAD_UP, 0, { false }, { false } },
|
|
{ "menu_down", STEAMCONTROLLER_DPAD_DOWN, 0, { false }, { false } },
|
|
{ "menu_cancel", STEAMCONTROLLER_B, 0, { false }, { false } },
|
|
{ "menu_select", STEAMCONTROLLER_A, 0, { false }, { false } },
|
|
{ "resume_esc", STEAMCONTROLLER_START, 0, { false }, { false } },
|
|
{ "cl_trigger_first_notification", STEAMCONTROLLER_F1, 0, { false }, { false } }, // Command is in the in-game action set (use for hitting accept/ok on dialogs)
|
|
{ "cl_decline_first_notification", STEAMCONTROLLER_F2, 0, { false }, { false } }, // Command is in the in-game action set (use for hitting cancel/decline on dialogs)
|
|
{ "menu_toggle_function", STEAMCONTROLLER_Y, 0, { false }, { false }, }, // Command is in the in-game HUD action set
|
|
{ "menu_alt_function", STEAMCONTROLLER_X, 0, { false }, { false } }, // Command is in the in-game HUD action set
|
|
{ "cancelselect", STEAMCONTROLLER_START, 0, { false }, { false } }, // Command is in the in-game action set
|
|
{ "toggleready", STEAMCONTROLLER_F4, 0, { false }, { false } }, // Command is in the in-game action set
|
|
};
|
|
|
|
struct SAnalogAction
|
|
{
|
|
const char *strName;
|
|
JoystickAxis_t joystickAxisX, joystickAxisY;
|
|
ControllerAnalogActionHandle_t handle;
|
|
};
|
|
|
|
struct SGameActionSet
|
|
{
|
|
const char *strName;
|
|
GameActionSet_t eGameActionSet;
|
|
ControllerActionSetHandle_t handle;
|
|
};
|
|
static SGameActionSet g_GameActionSets[] = {
|
|
{ "MenuControls", GAME_ACTION_SET_MENUCONTROLS, 0 },
|
|
{ "FPSControls", GAME_ACTION_SET_FPSCONTROLS, 0 },
|
|
{ "InGameHUDControls", GAME_ACTION_SET_IN_GAME_HUD, 0 },
|
|
{ "SpectatorControls", GAME_ACTION_SET_SPECTATOR, 0 },
|
|
};
|
|
|
|
|
|
// Table that maps a physical steam controller origin to the corresponding character in our icon font.
|
|
// If the EControllerActionOrigin enum or the font changes, this table must be changed to match.
|
|
static const wchar_t* g_MapSteamControllerOriginToIconFont[] = {
|
|
L"", // k_EControllerActionOrigin_None
|
|
L"A", // k_EControllerActionOrigin_A
|
|
L"B", // k_EControllerActionOrigin_B
|
|
L"X", // k_EControllerActionOrigin_X
|
|
L"Y", // k_EControllerActionOrigin_Y
|
|
L"2", // k_EControllerActionOrigin_LeftBumper
|
|
L"3", // k_EControllerActionOrigin_RightBumper
|
|
L"(", // k_EControllerActionOrigin_LeftGrip
|
|
L")", // k_EControllerActionOrigin_RightGrip
|
|
L"5", // k_EControllerActionOrigin_Start
|
|
L"4", // k_EControllerActionOrigin_Back
|
|
L"q", // k_EControllerActionOrigin_LeftPad_Touch
|
|
L"w", // k_EControllerActionOrigin_LeftPad_Swipe
|
|
L"e", // k_EControllerActionOrigin_LeftPad_Click
|
|
L"a", // k_EControllerActionOrigin_LeftPad_DPadNorth
|
|
L"s", // k_EControllerActionOrigin_LeftPad_DPadSouth
|
|
L"d", // k_EControllerActionOrigin_LeftPad_DPadWest
|
|
L"f", // k_EControllerActionOrigin_LeftPad_DPadEast
|
|
L"y", // k_EControllerActionOrigin_RightPad_Touch
|
|
L"u", // k_EControllerActionOrigin_RightPad_Swipe
|
|
L"i", // k_EControllerActionOrigin_RightPad_Click
|
|
L"h", // k_EControllerActionOrigin_RightPad_DPadNorth
|
|
L"j", // k_EControllerActionOrigin_RightPad_DPadSouth
|
|
L"k", // k_EControllerActionOrigin_RightPad_DPadWest
|
|
L"l", // k_EControllerActionOrigin_RightPad_DEast
|
|
L"z", // k_EControllerActionOrigin_LeftTrigger_Pull
|
|
L"x", // k_EControllerActionOrigin_LeftTrigger_Click
|
|
L"n", // k_EControllerActionOrigin_RightTrigger_Pull
|
|
L"m", // k_EControllerActionOrigin_RightTrigger_Click
|
|
L"C", // k_EControllerActionOrigin_LeftStick_Move
|
|
L"V", // k_EControllerActionOrigin_LeftStick_Click
|
|
L"7", // k_EControllerActionOrigin_LeftStick_DPadNorth
|
|
L"8", // k_EControllerActionOrigin_LeftStick_DPadSouth
|
|
L"9", // k_EControllerActionOrigin_LeftStick_DPadWest
|
|
L"0", // k_EControllerActionOrigin_LeftStick_DPadEast
|
|
L"6", // k_EControllerActionOrigin_Gyro_Move
|
|
L"6", // k_EControllerActionOrigin_Gyro_Pitch
|
|
L"6", // k_EControllerActionOrigin_Gyro_Yaw
|
|
L"6", // k_EControllerActionOrigin_Gyro_Roll
|
|
};
|
|
|
|
// Table that maps a physical steam controller origin to a short description string for user display (only use this
|
|
// if it's impractical to use the icon font).
|
|
// If the EControllerActionOrigin enum changes, this table must be changed to match.
|
|
static const wchar_t* g_MapSteamControllerOriginToDescription[] = {
|
|
L"", // k_EControllerActionOrigin_None
|
|
L"A", // k_EControllerActionOrigin_A
|
|
L"B", // k_EControllerActionOrigin_B
|
|
L"X", // k_EControllerActionOrigin_X
|
|
L"Y", // k_EControllerActionOrigin_Y
|
|
L"LB", // k_EControllerActionOrigin_LeftBumper
|
|
L"RB", // k_EControllerActionOrigin_RightBumper
|
|
L"LG", // k_EControllerActionOrigin_LeftGrip
|
|
L"RG", // k_EControllerActionOrigin_RightGrip
|
|
L"START", // k_EControllerActionOrigin_Start
|
|
L"BACK", // k_EControllerActionOrigin_Back
|
|
L"LPTOUCH", // k_EControllerActionOrigin_LeftPad_Touch
|
|
L"LPSWIPE", // k_EControllerActionOrigin_LeftPad_Swipe
|
|
L"LPCLICK", // k_EControllerActionOrigin_LeftPad_Click
|
|
L"LPUP", // k_EControllerActionOrigin_LeftPad_DPadNorth
|
|
L"LPDOWN", // k_EControllerActionOrigin_LeftPad_DPadSouth
|
|
L"LPLEFT", // k_EControllerActionOrigin_LeftPad_DPadWest
|
|
L"LPRIGHT", // k_EControllerActionOrigin_LeftPad_DPadEast
|
|
L"RPTOUCH", // k_EControllerActionOrigin_RightPad_Touch
|
|
L"RPSWIPE", // k_EControllerActionOrigin_RightPad_Swipe
|
|
L"RPCLICK", // k_EControllerActionOrigin_RightPad_Click
|
|
L"RPUP", // k_EControllerActionOrigin_RightPad_DPadNorth
|
|
L"RPDOWN", // k_EControllerActionOrigin_RightPad_DPadSouth
|
|
L"RPLEFT", // k_EControllerActionOrigin_RightPad_DPadWest
|
|
L"RPRIGHT", // k_EControllerActionOrigin_RightPad_DEast
|
|
L"LT", // k_EControllerActionOrigin_LeftTrigger_Pull
|
|
L"LT", // k_EControllerActionOrigin_LeftTrigger_Click
|
|
L"LT", // k_EControllerActionOrigin_RightTrigger_Pull
|
|
L"LT", // k_EControllerActionOrigin_RightTrigger_Click
|
|
L"LS", // k_EControllerActionOrigin_LeftStick_Move
|
|
L"LSCLICK", // k_EControllerActionOrigin_LeftStick_Click
|
|
L"LSUP", // k_EControllerActionOrigin_LeftStick_DPadNorth
|
|
L"LSDOWN", // k_EControllerActionOrigin_LeftStick_DPadSouth
|
|
L"LSLEFT", // k_EControllerActionOrigin_LeftStick_DPadWest
|
|
L"LSRIGHT", // k_EControllerActionOrigin_LeftStick_DPadEast
|
|
L"GYRO", // k_EControllerActionOrigin_Gyro_Move
|
|
L"GYRO", // k_EControllerActionOrigin_Gyro_Pitch
|
|
L"GYRO", // k_EControllerActionOrigin_Gyro_Yaw
|
|
L"GYRO", // k_EControllerActionOrigin_Gyro_Roll
|
|
};
|
|
|
|
|
|
bool CInputSystem::InitializeSteamControllerActionSets()
|
|
{
|
|
auto psteamcontroller = g_pInputSystem->SteamControllerInterface();
|
|
if ( !psteamcontroller )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool bGotHandles = true;
|
|
|
|
for ( int i = 0; i != ARRAYSIZE( g_DigitalMenuActions ); ++i )
|
|
{
|
|
g_DigitalMenuActions[i].handle = psteamcontroller->GetDigitalActionHandle( g_DigitalMenuActions[i].strName );
|
|
bGotHandles = bGotHandles && ( g_DigitalMenuActions[i].handle != 0 );
|
|
|
|
// Init the button state array
|
|
for( int j = 0; j < STEAM_CONTROLLER_MAX_COUNT; j++ )
|
|
{
|
|
g_DigitalMenuActions[i].bState[j] = false;
|
|
}
|
|
}
|
|
|
|
for ( int i = 0; i != ARRAYSIZE( g_GameActionSets ); ++i )
|
|
{
|
|
g_GameActionSets[i].handle = psteamcontroller->GetActionSetHandle( g_GameActionSets[i].strName );
|
|
bGotHandles = bGotHandles && g_GameActionSets[i].handle;
|
|
}
|
|
|
|
return bGotHandles;
|
|
}
|
|
|
|
ConVar sc_debug_sets( "sc_debug_sets", "0", FCVAR_ARCHIVE, "Debugging" );
|
|
|
|
void CInputSystem::PollSteamControllers( void )
|
|
{
|
|
// Make sure we've got the appropriate connections to Steam
|
|
auto steamcontroller = SteamControllerInterface();
|
|
if ( !steamcontroller )
|
|
{
|
|
return;
|
|
}
|
|
|
|
steamcontroller->RunFrame();
|
|
|
|
uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
|
|
m_unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
|
|
|
|
if ( m_unNumConnected > 0 )
|
|
{
|
|
if ( !m_bSteamControllerActionsInitialized )
|
|
{
|
|
// Retry initialization of controller actions if we didn't acquire them all before for some reason.
|
|
m_bSteamControllerActionsInitialized = m_bSteamController && InitializeSteamControllerActionSets();
|
|
g_pInputSystem->ActivateSteamControllerActionSet( GAME_ACTION_SET_MENUCONTROLS );
|
|
}
|
|
|
|
if ( m_bSteamControllerActionsInitialized )
|
|
{
|
|
// If we successfully initialized all the actions, and we have a connected controller, then we're considered "active".
|
|
m_bSteamControllerActive = true;
|
|
|
|
// For each digital action
|
|
for ( int i = 0; i != ARRAYSIZE( g_DigitalMenuActions ); ++i )
|
|
{
|
|
SDigitalMenuAction& action = g_DigitalMenuActions[i];
|
|
|
|
// and for each controller
|
|
for ( uint64 j = 0; j < m_unNumConnected; ++j )
|
|
{
|
|
|
|
// Get the action's current state
|
|
ControllerDigitalActionData_t data = steamcontroller->GetDigitalActionData( nControllerHandles[j], action.handle );
|
|
|
|
// We only care if the action is active
|
|
if ( data.bActive )
|
|
{
|
|
action.bAwaitingDebounce[j] = action.bAwaitingDebounce[j] && data.bState;
|
|
|
|
// If the action's state has changed
|
|
if ( data.bState != action.bState[j] )
|
|
{
|
|
action.bState[j] = data.bState;
|
|
|
|
// Press the key for the correct controller
|
|
ButtonCode_t buttonCode = ButtonCodeToJoystickButtonCode( action.buttonCode, j );
|
|
|
|
if ( action.bState[j] )
|
|
{
|
|
if ( !action.bAwaitingDebounce[j] )
|
|
{
|
|
PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If no controllers are connected, unflag the active state.
|
|
m_bSteamControllerActive = false;
|
|
}
|
|
}
|
|
|
|
bool CInputSystem::GetRadialMenuStickValues( int nSlot, float &fX, float &fY )
|
|
{
|
|
fX = m_pRadialMenuStickVal[nSlot][0];
|
|
fY = m_pRadialMenuStickVal[nSlot][1];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CInputSystem::IsSteamControllerActive( void )
|
|
{
|
|
return m_bSteamControllerActive;
|
|
}
|
|
|
|
bool CInputSystem::InitializeSteamControllers()
|
|
{
|
|
m_flLastSteamControllerInput = -FLT_MAX;
|
|
auto steamcontroller = SteamControllerInterface();
|
|
if ( steamcontroller )
|
|
{
|
|
if ( !steamcontroller->Init() )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for( int i=0; i<STEAM_CONTROLLER_MAX_COUNT; i++ )
|
|
{
|
|
m_pRadialMenuStickVal[i][0] = 0.0f;
|
|
m_pRadialMenuStickVal[i][1] = 0.0f;
|
|
}
|
|
|
|
// We have to account for other joysticks prior to adding steam controllers
|
|
// So we get the baseline number here when first initializing
|
|
m_nJoystickBaseline = m_nJoystickCount;
|
|
if ( steamcontroller )
|
|
{
|
|
uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
|
|
m_unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
|
|
steamcontroller->RunFrame();
|
|
|
|
if ( m_unNumConnected > 0 )
|
|
{
|
|
for ( uint32 i = 0; i < m_unNumConnected; i++ )
|
|
{
|
|
if ( m_Device[i].m_nJoystickIndex == INVALID_USER_ID )
|
|
{
|
|
int nJoystickIndex = i;
|
|
m_Device[i].m_nJoystickIndex = nJoystickIndex;
|
|
m_Device[i].m_nHardwareIndex = i;
|
|
}
|
|
m_nControllerType[m_Device[i].m_nJoystickIndex] = INPUT_TYPE_STEAMCONTROLLER;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ControllerActionSetHandle_t CInputSystem::GetActionSetHandle( GameActionSet_t eActionSet )
|
|
{
|
|
return g_GameActionSets[eActionSet].handle;
|
|
}
|
|
|
|
ControllerActionSetHandle_t CInputSystem::GetActionSetHandle( const char* szActionSet )
|
|
{
|
|
for ( int i = 0; i != ARRAYSIZE( g_GameActionSets ); ++i )
|
|
{
|
|
if ( !Q_strcmp( szActionSet, g_GameActionSets[i].strName ) )
|
|
{
|
|
return g_GameActionSets[i].handle;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void CInputSystem::ActivateSteamControllerActionSetForSlot( uint64 nSlot, GameActionSet_t eActionSet )
|
|
{
|
|
auto steamcontroller = SteamControllerInterface();
|
|
bool bChangedActionSet = false;
|
|
|
|
if ( steamcontroller )
|
|
{
|
|
if ( nSlot == STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS )
|
|
{
|
|
for ( int i = 0; i < STEAM_CONTROLLER_MAX_COUNT; i++ )
|
|
{
|
|
if ( m_currentActionSet[i] != eActionSet )
|
|
{
|
|
bChangedActionSet = true;
|
|
m_currentActionSet[i] = eActionSet;
|
|
}
|
|
}
|
|
|
|
steamcontroller->ActivateActionSet( STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS, g_GameActionSets[eActionSet].handle );
|
|
}
|
|
else
|
|
{
|
|
uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
|
|
int unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
|
|
|
|
if( nSlot < unNumConnected )
|
|
{
|
|
if ( m_currentActionSet[nSlot] != eActionSet )
|
|
{
|
|
bChangedActionSet = true;
|
|
m_currentActionSet[nSlot] = eActionSet;
|
|
}
|
|
|
|
steamcontroller->ActivateActionSet( nControllerHandles[nSlot], g_GameActionSets[eActionSet].handle );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bChangedActionSet )
|
|
{
|
|
// If we changed action set, then flag everything for a debounce (meaning we demand to see an unpressed state before we'll register a pressed one)
|
|
for ( int i = 0; i < STEAM_CONTROLLER_MAX_COUNT; i++ )
|
|
{
|
|
for ( int j = 0; j != ARRAYSIZE( g_DigitalMenuActions ); ++j )
|
|
{
|
|
g_DigitalMenuActions[j].bAwaitingDebounce[i] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const int CInputSystem::GetSteamPadDeadZone( ESteamPadAxis axis )
|
|
{
|
|
int nDeadzone = s_nSteamPadDeadZoneTable[ axis ];
|
|
|
|
// Do modifications if required here?
|
|
|
|
return nDeadzone;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Processes data for controller
|
|
//-----------------------------------------------------------------------------
|
|
void CInputSystem::ReadSteamController( int iIndex )
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Pulse haptic feedback
|
|
//-----------------------------------------------------------------------------
|
|
/* void CInputSystem::PulseHapticOnSteamController( uint32 nControllerIndex, ESteamControllerPad ePad, unsigned short durationMicroSec )
|
|
{
|
|
auto steamcontroller = SteamControllerInterface();
|
|
if ( steamcontroller )
|
|
{
|
|
steamcontroller->TriggerHapticPulse( nControllerIndex, ePad, durationMicroSec );
|
|
}
|
|
}*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Returns the controller State for a particular joystick slot
|
|
//-----------------------------------------------------------------------------
|
|
bool CInputSystem::GetControllerStateForSlot( int nSlot )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int CInputSystem::GetSteamControllerIndexForSlot( int nSlot )
|
|
{
|
|
for ( int i = 0; i < Q_ARRAYSIZE( m_Device ); i++ )
|
|
{
|
|
if ( m_Device[i].active && (int)m_Device[i].m_nJoystickIndex == nSlot )
|
|
{
|
|
return m_Device[i].m_nHardwareIndex;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Post events, ignoring key repeats
|
|
//-----------------------------------------------------------------------------
|
|
void CInputSystem::PostKeyEvent( int iIndex, sKey_t sKey, int nSample )
|
|
{
|
|
// Rework of xbox code here :
|
|
|
|
AnalogCode_t code = ANALOG_CODE_LAST;
|
|
float value = 0.f;
|
|
//int nMsgSlot = iIndex;
|
|
int nMsgSlot = m_Device[iIndex].m_nJoystickIndex;
|
|
int nSampleThreshold = 1;
|
|
|
|
// Look for changes on the analog axes
|
|
switch( sKey )
|
|
{
|
|
case SK_BUTTON_LPAD_LEFT:
|
|
case SK_BUTTON_LPAD_RIGHT:
|
|
{
|
|
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_X );
|
|
value = ( sKey == SK_BUTTON_LPAD_LEFT ) ? -nSample : nSample;
|
|
// Kind of a hack to horizontal values for menu selection items in Portal 2
|
|
// The additional 5k helps accidental horizontals in menus.
|
|
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD ) + 5000;
|
|
}
|
|
break;
|
|
|
|
case SK_BUTTON_LPAD_UP:
|
|
case SK_BUTTON_LPAD_DOWN:
|
|
{
|
|
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_Y );
|
|
value = ( sKey == SK_BUTTON_LPAD_UP ) ? -nSample : nSample;
|
|
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD );
|
|
}
|
|
break;
|
|
|
|
case SK_BUTTON_RPAD_LEFT:
|
|
case SK_BUTTON_RPAD_RIGHT:
|
|
{
|
|
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_U );
|
|
value = ( sKey == SK_BUTTON_RPAD_LEFT ) ? -nSample : nSample;
|
|
// Kind of a hack to horizontal values for menu selection items in Portal 2
|
|
// The additional 5k helps accidental horizontals in menus.
|
|
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD ) + 5000;;
|
|
}
|
|
break;
|
|
|
|
case SK_BUTTON_RPAD_UP:
|
|
case SK_BUTTON_RPAD_DOWN:
|
|
{
|
|
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_R );
|
|
value = ( sKey == SK_BUTTON_RPAD_UP ) ? -nSample : nSample;
|
|
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Store the analog event
|
|
if ( ANALOG_CODE_LAST != code )
|
|
{
|
|
InputState_t &state = m_InputState[ m_bIsPolling ];
|
|
state.m_pAnalogDelta[ code ] = ( int )( value - state.m_pAnalogValue[ code ] );
|
|
state.m_pAnalogValue[ code ] = ( int )value;
|
|
if ( state.m_pAnalogDelta[ code ] != 0 )
|
|
{
|
|
PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, code, ( int )value, state.m_pAnalogDelta[ code ] );
|
|
}
|
|
}
|
|
|
|
// store the key
|
|
m_Device[iIndex].m_appSKeys[sKey].sample = nSample;
|
|
if ( nSample > nSampleThreshold )
|
|
{
|
|
m_Device[iIndex].m_appSKeys[sKey].repeats++;
|
|
}
|
|
else
|
|
{
|
|
m_Device[iIndex].m_appSKeys[sKey].repeats = 0;
|
|
nSample = 0;
|
|
}
|
|
|
|
if ( m_Device[iIndex].m_appSKeys[sKey].repeats > 1 )
|
|
{
|
|
// application cannot handle streaming keys
|
|
// first keypress is the only edge trigger
|
|
return;
|
|
}
|
|
|
|
// package the key
|
|
ButtonCode_t buttonCode = SKeyToButtonCode( nMsgSlot, sKey );
|
|
if ( nSample )
|
|
{
|
|
PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
|
|
}
|
|
else
|
|
{
|
|
PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
|
|
}
|
|
}
|
|
|
|
// Gets the action origin (i.e. which physical input) maps to the given virtual button for the given action set
|
|
EControllerActionOrigin CInputSystem::GetSteamControllerActionOrigin( const char* action, GameActionSet_t action_set )
|
|
{
|
|
auto pSC = SteamControllerInterface();
|
|
if ( pSC )
|
|
{
|
|
ControllerHandle_t hConnected[STEAM_CONTROLLER_MAX_COUNT];
|
|
auto nConnected = pSC->GetConnectedControllers( hConnected );
|
|
if ( nConnected == 0 )
|
|
{
|
|
return k_EControllerActionOrigin_None;
|
|
}
|
|
|
|
SGameActionSet* pActionSet = nullptr;
|
|
for ( int i = 0; i < ARRAYSIZE( g_GameActionSets ); i++ )
|
|
{
|
|
if ( g_GameActionSets[i].eGameActionSet == action_set )
|
|
{
|
|
pActionSet = &g_GameActionSets[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pActionSet )
|
|
{
|
|
auto actionHandle = pSC->GetDigitalActionHandle( action );
|
|
EControllerActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS];
|
|
int nOrigins = pSC->GetDigitalActionOrigins( hConnected[0], pActionSet->handle, actionHandle, origins );
|
|
if ( nOrigins > 0 )
|
|
{
|
|
return origins[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
return k_EControllerActionOrigin_None;
|
|
}
|
|
|
|
// Gets the action origin (i.e. which physical input) maps to the given virtual button for the given action set
|
|
EControllerActionOrigin CInputSystem::GetSteamControllerActionOrigin( const char* action, ControllerActionSetHandle_t action_set_handle )
|
|
{
|
|
auto pSC = SteamControllerInterface();
|
|
if ( pSC && action_set_handle )
|
|
{
|
|
ControllerHandle_t hConnected[STEAM_CONTROLLER_MAX_COUNT];
|
|
auto nConnected = pSC->GetConnectedControllers( hConnected );
|
|
if ( nConnected == 0 )
|
|
{
|
|
return k_EControllerActionOrigin_None;
|
|
}
|
|
|
|
auto actionHandle = pSC->GetDigitalActionHandle( action );
|
|
EControllerActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS];
|
|
int nOrigins = pSC->GetDigitalActionOrigins( hConnected[0], action_set_handle, actionHandle, origins );
|
|
if ( nOrigins > 0 )
|
|
{
|
|
return origins[0];
|
|
}
|
|
}
|
|
|
|
return k_EControllerActionOrigin_None;
|
|
}
|
|
|
|
// Maps a Steam Controller action origin to a string (consisting of a single character) in our SC icon font
|
|
const wchar_t* CInputSystem::GetSteamControllerFontCharacterForActionOrigin( EControllerActionOrigin origin )
|
|
{
|
|
if ( origin >= 0 && origin < ARRAYSIZE( g_MapSteamControllerOriginToIconFont ) )
|
|
{
|
|
return g_MapSteamControllerOriginToIconFont[origin];
|
|
}
|
|
else
|
|
{
|
|
return L"";
|
|
}
|
|
}
|
|
|
|
// Maps a Steam Controller action origin to a short text string (e.g. "X", "LB", "LDOWN") describing the control.
|
|
// Prefer to actually use the icon font wherever possible.
|
|
const wchar_t* CInputSystem::GetSteamControllerDescriptionForActionOrigin( EControllerActionOrigin origin )
|
|
{
|
|
if ( origin >= 0 && origin < ARRAYSIZE( g_MapSteamControllerOriginToDescription ) )
|
|
{
|
|
return g_MapSteamControllerOriginToDescription[origin];
|
|
}
|
|
else
|
|
{
|
|
return L"";
|
|
}
|
|
}
|