diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /inputsystem/steamcontroller.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'inputsystem/steamcontroller.cpp')
| -rw-r--r-- | inputsystem/steamcontroller.cpp | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/inputsystem/steamcontroller.cpp b/inputsystem/steamcontroller.cpp new file mode 100644 index 0000000..007ccec --- /dev/null +++ b/inputsystem/steamcontroller.cpp @@ -0,0 +1,695 @@ +//=========== 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""; + } +} |