Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

695 lines
24 KiB

  1. //=========== Copyright Valve Corporation, All rights reserved. ===============//
  2. //
  3. // Purpose: Native Steam Controller Interface
  4. //=============================================================================//
  5. #include "inputsystem.h"
  6. #include "key_translation.h"
  7. #include "filesystem.h"
  8. #include "steam/isteamcontroller.h"
  9. #include "math.h"
  10. #ifndef UINT64_MAX
  11. const uint64 UINT64_MAX = 0xffffffffffffffff;
  12. #endif
  13. #if !defined( NO_STEAM )
  14. #include "steam/steam_api.h"
  15. #endif //NO_STEAM
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include <tier0/memdbgon.h>
  18. 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." );
  19. #define STEAMPAD_MAX_ANALOGSAMPLE_GYRO 32768
  20. #define STEAMPAD_MAX_ANALOGSAMPLE_TRIGGER 32768
  21. #define STEAMPAD_MAX_ANALOGSAMPLE_LEFT 32768
  22. #define STEAMPAD_MAX_ANALOGSAMPLE_RIGHT 32767
  23. #define STEAMPAD_MAX_ANALOGSAMPLE_DOWN 32768
  24. #define STEAMPAD_MAX_ANALOGSAMPLE_UP 32767
  25. #define STEAMPAD_MAX_ANALOGSAMPLE_MAX 32768
  26. #define STEAMPAD_ANALOG_SCALE_LEFT(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_LEFT/( float )( STEAMPAD_MAX_ANALOGSAMPLE_LEFT-(x) ) )
  27. #define STEAMPAD_ANALOG_SCALE_RIGHT(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_RIGHT/( float )( STEAMPAD_MAX_ANALOGSAMPLE_RIGHT-(x) ) )
  28. #define STEAMPAD_ANALOG_SCALE_DOWN(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_DOWN/( float )( STEAMPAD_MAX_ANALOGSAMPLE_DOWN-(x) ) )
  29. #define STEAMPAD_ANALOG_SCALE_UP(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_UP/( float )( STEAMPAD_MAX_ANALOGSAMPLE_UP-(x) ) )
  30. #define STEAMPAD_ANALOG_TRIGGER_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_TRIGGER * 0.5f ) )
  31. #define STEAMPAD_ANALOG_PAD_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.25f ) )
  32. #define STEAMPAD_ANALOG_GYRO_THRESHOLD ( ( int ) ( STEAMPAD_MAX_ANALOGSAMPLE_GYRO * 0.3f ) )
  33. #define STEAMPAD_DIGITAL_PAD_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.52f ) )
  34. #define STEAMPAD_AXIS_REPEAT_INTERVAL_START 0.6f
  35. #define STEAMPAD_AXIS_REPEAT_INTERVAL_END 0.05f
  36. #define STEAMPAD_AXIS_REPEAT_CURVE_TIME 1.75f
  37. #define PAD_ANALOG_BUTTON_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.285f ) )
  38. #define PAD_ANALOG_BUTTON_THRESHOLD_STRONG ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.68f ) )
  39. #define SQRT2 1.414213562
  40. // key translation
  41. typedef struct
  42. {
  43. uint64 steampadinput;
  44. ButtonCode_t steampadkey;
  45. } steampadInputTosteampadKey_t;
  46. static const int s_nSteamPadDeadZoneTable[] =
  47. {
  48. STEAMPAD_ANALOG_PAD_THRESHOLD, // LEFTPAD_AXIS_X
  49. STEAMPAD_ANALOG_PAD_THRESHOLD, // LEFTPAD_AXIS_Y
  50. STEAMPAD_ANALOG_PAD_THRESHOLD, // RIGHTPAD_AXIS_X
  51. STEAMPAD_ANALOG_PAD_THRESHOLD, // RIGHTPAD_AXIS_Y
  52. STEAMPAD_ANALOG_TRIGGER_THRESHOLD, //LEFT_TRIGGER_AXIS
  53. STEAMPAD_ANALOG_TRIGGER_THRESHOLD, //RIGHT_TRIGGER_AXIS
  54. STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_PITCH
  55. STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_ROLL
  56. STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_YAW
  57. };
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Counts the number of active gamepads connected
  60. //-----------------------------------------------------------------------------
  61. uint32 CInputSystem::GetNumSteamControllersConnected()
  62. {
  63. return m_unNumConnected;
  64. }
  65. struct SDigitalMenuAction
  66. {
  67. const char *strName;
  68. ButtonCode_t buttonCode;
  69. ControllerDigitalActionHandle_t handle;
  70. bool bState[STEAM_CONTROLLER_MAX_COUNT];
  71. bool bAwaitingDebounce[STEAM_CONTROLLER_MAX_COUNT];
  72. };
  73. static SDigitalMenuAction g_DigitalMenuActions[] = {
  74. { "menu_left", STEAMCONTROLLER_DPAD_LEFT, 0, { false }, { false } },
  75. { "menu_right", STEAMCONTROLLER_DPAD_RIGHT, 0, { false }, { false } },
  76. { "menu_up", STEAMCONTROLLER_DPAD_UP, 0, { false }, { false } },
  77. { "menu_down", STEAMCONTROLLER_DPAD_DOWN, 0, { false }, { false } },
  78. { "menu_cancel", STEAMCONTROLLER_B, 0, { false }, { false } },
  79. { "menu_select", STEAMCONTROLLER_A, 0, { false }, { false } },
  80. { "resume_esc", STEAMCONTROLLER_START, 0, { false }, { false } },
  81. { "cl_trigger_first_notification", STEAMCONTROLLER_F1, 0, { false }, { false } }, // Command is in the in-game action set (use for hitting accept/ok on dialogs)
  82. { "cl_decline_first_notification", STEAMCONTROLLER_F2, 0, { false }, { false } }, // Command is in the in-game action set (use for hitting cancel/decline on dialogs)
  83. { "menu_toggle_function", STEAMCONTROLLER_Y, 0, { false }, { false }, }, // Command is in the in-game HUD action set
  84. { "menu_alt_function", STEAMCONTROLLER_X, 0, { false }, { false } }, // Command is in the in-game HUD action set
  85. { "cancelselect", STEAMCONTROLLER_START, 0, { false }, { false } }, // Command is in the in-game action set
  86. { "toggleready", STEAMCONTROLLER_F4, 0, { false }, { false } }, // Command is in the in-game action set
  87. };
  88. struct SAnalogAction
  89. {
  90. const char *strName;
  91. JoystickAxis_t joystickAxisX, joystickAxisY;
  92. ControllerAnalogActionHandle_t handle;
  93. };
  94. struct SGameActionSet
  95. {
  96. const char *strName;
  97. GameActionSet_t eGameActionSet;
  98. ControllerActionSetHandle_t handle;
  99. };
  100. static SGameActionSet g_GameActionSets[] = {
  101. { "MenuControls", GAME_ACTION_SET_MENUCONTROLS, 0 },
  102. { "FPSControls", GAME_ACTION_SET_FPSCONTROLS, 0 },
  103. { "InGameHUDControls", GAME_ACTION_SET_IN_GAME_HUD, 0 },
  104. { "SpectatorControls", GAME_ACTION_SET_SPECTATOR, 0 },
  105. };
  106. // Table that maps a physical steam controller origin to the corresponding character in our icon font.
  107. // If the EControllerActionOrigin enum or the font changes, this table must be changed to match.
  108. static const wchar_t* g_MapSteamControllerOriginToIconFont[] = {
  109. L"", // k_EControllerActionOrigin_None
  110. L"A", // k_EControllerActionOrigin_A
  111. L"B", // k_EControllerActionOrigin_B
  112. L"X", // k_EControllerActionOrigin_X
  113. L"Y", // k_EControllerActionOrigin_Y
  114. L"2", // k_EControllerActionOrigin_LeftBumper
  115. L"3", // k_EControllerActionOrigin_RightBumper
  116. L"(", // k_EControllerActionOrigin_LeftGrip
  117. L")", // k_EControllerActionOrigin_RightGrip
  118. L"5", // k_EControllerActionOrigin_Start
  119. L"4", // k_EControllerActionOrigin_Back
  120. L"q", // k_EControllerActionOrigin_LeftPad_Touch
  121. L"w", // k_EControllerActionOrigin_LeftPad_Swipe
  122. L"e", // k_EControllerActionOrigin_LeftPad_Click
  123. L"a", // k_EControllerActionOrigin_LeftPad_DPadNorth
  124. L"s", // k_EControllerActionOrigin_LeftPad_DPadSouth
  125. L"d", // k_EControllerActionOrigin_LeftPad_DPadWest
  126. L"f", // k_EControllerActionOrigin_LeftPad_DPadEast
  127. L"y", // k_EControllerActionOrigin_RightPad_Touch
  128. L"u", // k_EControllerActionOrigin_RightPad_Swipe
  129. L"i", // k_EControllerActionOrigin_RightPad_Click
  130. L"h", // k_EControllerActionOrigin_RightPad_DPadNorth
  131. L"j", // k_EControllerActionOrigin_RightPad_DPadSouth
  132. L"k", // k_EControllerActionOrigin_RightPad_DPadWest
  133. L"l", // k_EControllerActionOrigin_RightPad_DEast
  134. L"z", // k_EControllerActionOrigin_LeftTrigger_Pull
  135. L"x", // k_EControllerActionOrigin_LeftTrigger_Click
  136. L"n", // k_EControllerActionOrigin_RightTrigger_Pull
  137. L"m", // k_EControllerActionOrigin_RightTrigger_Click
  138. L"C", // k_EControllerActionOrigin_LeftStick_Move
  139. L"V", // k_EControllerActionOrigin_LeftStick_Click
  140. L"7", // k_EControllerActionOrigin_LeftStick_DPadNorth
  141. L"8", // k_EControllerActionOrigin_LeftStick_DPadSouth
  142. L"9", // k_EControllerActionOrigin_LeftStick_DPadWest
  143. L"0", // k_EControllerActionOrigin_LeftStick_DPadEast
  144. L"6", // k_EControllerActionOrigin_Gyro_Move
  145. L"6", // k_EControllerActionOrigin_Gyro_Pitch
  146. L"6", // k_EControllerActionOrigin_Gyro_Yaw
  147. L"6", // k_EControllerActionOrigin_Gyro_Roll
  148. };
  149. // Table that maps a physical steam controller origin to a short description string for user display (only use this
  150. // if it's impractical to use the icon font).
  151. // If the EControllerActionOrigin enum changes, this table must be changed to match.
  152. static const wchar_t* g_MapSteamControllerOriginToDescription[] = {
  153. L"", // k_EControllerActionOrigin_None
  154. L"A", // k_EControllerActionOrigin_A
  155. L"B", // k_EControllerActionOrigin_B
  156. L"X", // k_EControllerActionOrigin_X
  157. L"Y", // k_EControllerActionOrigin_Y
  158. L"LB", // k_EControllerActionOrigin_LeftBumper
  159. L"RB", // k_EControllerActionOrigin_RightBumper
  160. L"LG", // k_EControllerActionOrigin_LeftGrip
  161. L"RG", // k_EControllerActionOrigin_RightGrip
  162. L"START", // k_EControllerActionOrigin_Start
  163. L"BACK", // k_EControllerActionOrigin_Back
  164. L"LPTOUCH", // k_EControllerActionOrigin_LeftPad_Touch
  165. L"LPSWIPE", // k_EControllerActionOrigin_LeftPad_Swipe
  166. L"LPCLICK", // k_EControllerActionOrigin_LeftPad_Click
  167. L"LPUP", // k_EControllerActionOrigin_LeftPad_DPadNorth
  168. L"LPDOWN", // k_EControllerActionOrigin_LeftPad_DPadSouth
  169. L"LPLEFT", // k_EControllerActionOrigin_LeftPad_DPadWest
  170. L"LPRIGHT", // k_EControllerActionOrigin_LeftPad_DPadEast
  171. L"RPTOUCH", // k_EControllerActionOrigin_RightPad_Touch
  172. L"RPSWIPE", // k_EControllerActionOrigin_RightPad_Swipe
  173. L"RPCLICK", // k_EControllerActionOrigin_RightPad_Click
  174. L"RPUP", // k_EControllerActionOrigin_RightPad_DPadNorth
  175. L"RPDOWN", // k_EControllerActionOrigin_RightPad_DPadSouth
  176. L"RPLEFT", // k_EControllerActionOrigin_RightPad_DPadWest
  177. L"RPRIGHT", // k_EControllerActionOrigin_RightPad_DEast
  178. L"LT", // k_EControllerActionOrigin_LeftTrigger_Pull
  179. L"LT", // k_EControllerActionOrigin_LeftTrigger_Click
  180. L"LT", // k_EControllerActionOrigin_RightTrigger_Pull
  181. L"LT", // k_EControllerActionOrigin_RightTrigger_Click
  182. L"LS", // k_EControllerActionOrigin_LeftStick_Move
  183. L"LSCLICK", // k_EControllerActionOrigin_LeftStick_Click
  184. L"LSUP", // k_EControllerActionOrigin_LeftStick_DPadNorth
  185. L"LSDOWN", // k_EControllerActionOrigin_LeftStick_DPadSouth
  186. L"LSLEFT", // k_EControllerActionOrigin_LeftStick_DPadWest
  187. L"LSRIGHT", // k_EControllerActionOrigin_LeftStick_DPadEast
  188. L"GYRO", // k_EControllerActionOrigin_Gyro_Move
  189. L"GYRO", // k_EControllerActionOrigin_Gyro_Pitch
  190. L"GYRO", // k_EControllerActionOrigin_Gyro_Yaw
  191. L"GYRO", // k_EControllerActionOrigin_Gyro_Roll
  192. };
  193. bool CInputSystem::InitializeSteamControllerActionSets()
  194. {
  195. auto psteamcontroller = g_pInputSystem->SteamControllerInterface();
  196. if ( !psteamcontroller )
  197. {
  198. return false;
  199. }
  200. bool bGotHandles = true;
  201. for ( int i = 0; i != ARRAYSIZE( g_DigitalMenuActions ); ++i )
  202. {
  203. g_DigitalMenuActions[i].handle = psteamcontroller->GetDigitalActionHandle( g_DigitalMenuActions[i].strName );
  204. bGotHandles = bGotHandles && ( g_DigitalMenuActions[i].handle != 0 );
  205. // Init the button state array
  206. for( int j = 0; j < STEAM_CONTROLLER_MAX_COUNT; j++ )
  207. {
  208. g_DigitalMenuActions[i].bState[j] = false;
  209. }
  210. }
  211. for ( int i = 0; i != ARRAYSIZE( g_GameActionSets ); ++i )
  212. {
  213. g_GameActionSets[i].handle = psteamcontroller->GetActionSetHandle( g_GameActionSets[i].strName );
  214. bGotHandles = bGotHandles && g_GameActionSets[i].handle;
  215. }
  216. return bGotHandles;
  217. }
  218. ConVar sc_debug_sets( "sc_debug_sets", "0", FCVAR_ARCHIVE, "Debugging" );
  219. void CInputSystem::PollSteamControllers( void )
  220. {
  221. // Make sure we've got the appropriate connections to Steam
  222. auto steamcontroller = SteamControllerInterface();
  223. if ( !steamcontroller )
  224. {
  225. return;
  226. }
  227. steamcontroller->RunFrame();
  228. uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
  229. m_unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
  230. if ( m_unNumConnected > 0 )
  231. {
  232. if ( !m_bSteamControllerActionsInitialized )
  233. {
  234. // Retry initialization of controller actions if we didn't acquire them all before for some reason.
  235. m_bSteamControllerActionsInitialized = m_bSteamController && InitializeSteamControllerActionSets();
  236. g_pInputSystem->ActivateSteamControllerActionSet( GAME_ACTION_SET_MENUCONTROLS );
  237. }
  238. if ( m_bSteamControllerActionsInitialized )
  239. {
  240. // If we successfully initialized all the actions, and we have a connected controller, then we're considered "active".
  241. m_bSteamControllerActive = true;
  242. // For each digital action
  243. for ( int i = 0; i != ARRAYSIZE( g_DigitalMenuActions ); ++i )
  244. {
  245. SDigitalMenuAction& action = g_DigitalMenuActions[i];
  246. // and for each controller
  247. for ( uint64 j = 0; j < m_unNumConnected; ++j )
  248. {
  249. // Get the action's current state
  250. ControllerDigitalActionData_t data = steamcontroller->GetDigitalActionData( nControllerHandles[j], action.handle );
  251. // We only care if the action is active
  252. if ( data.bActive )
  253. {
  254. action.bAwaitingDebounce[j] = action.bAwaitingDebounce[j] && data.bState;
  255. // If the action's state has changed
  256. if ( data.bState != action.bState[j] )
  257. {
  258. action.bState[j] = data.bState;
  259. // Press the key for the correct controller
  260. ButtonCode_t buttonCode = ButtonCodeToJoystickButtonCode( action.buttonCode, j );
  261. if ( action.bState[j] )
  262. {
  263. if ( !action.bAwaitingDebounce[j] )
  264. {
  265. PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
  266. }
  267. }
  268. else
  269. {
  270. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
  271. }
  272. }
  273. }
  274. }
  275. }
  276. }
  277. }
  278. else
  279. {
  280. // If no controllers are connected, unflag the active state.
  281. m_bSteamControllerActive = false;
  282. }
  283. }
  284. bool CInputSystem::GetRadialMenuStickValues( int nSlot, float &fX, float &fY )
  285. {
  286. fX = m_pRadialMenuStickVal[nSlot][0];
  287. fY = m_pRadialMenuStickVal[nSlot][1];
  288. return true;
  289. }
  290. bool CInputSystem::IsSteamControllerActive( void )
  291. {
  292. return m_bSteamControllerActive;
  293. }
  294. bool CInputSystem::InitializeSteamControllers()
  295. {
  296. m_flLastSteamControllerInput = -FLT_MAX;
  297. auto steamcontroller = SteamControllerInterface();
  298. if ( steamcontroller )
  299. {
  300. if ( !steamcontroller->Init() )
  301. {
  302. return false;
  303. }
  304. }
  305. else
  306. {
  307. return false;
  308. }
  309. for( int i=0; i<STEAM_CONTROLLER_MAX_COUNT; i++ )
  310. {
  311. m_pRadialMenuStickVal[i][0] = 0.0f;
  312. m_pRadialMenuStickVal[i][1] = 0.0f;
  313. }
  314. // We have to account for other joysticks prior to adding steam controllers
  315. // So we get the baseline number here when first initializing
  316. m_nJoystickBaseline = m_nJoystickCount;
  317. if ( steamcontroller )
  318. {
  319. uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
  320. m_unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
  321. steamcontroller->RunFrame();
  322. if ( m_unNumConnected > 0 )
  323. {
  324. for ( uint32 i = 0; i < m_unNumConnected; i++ )
  325. {
  326. if ( m_Device[i].m_nJoystickIndex == INVALID_USER_ID )
  327. {
  328. int nJoystickIndex = i;
  329. m_Device[i].m_nJoystickIndex = nJoystickIndex;
  330. m_Device[i].m_nHardwareIndex = i;
  331. }
  332. m_nControllerType[m_Device[i].m_nJoystickIndex] = INPUT_TYPE_STEAMCONTROLLER;
  333. }
  334. }
  335. return true;
  336. }
  337. return false;
  338. }
  339. ControllerActionSetHandle_t CInputSystem::GetActionSetHandle( GameActionSet_t eActionSet )
  340. {
  341. return g_GameActionSets[eActionSet].handle;
  342. }
  343. ControllerActionSetHandle_t CInputSystem::GetActionSetHandle( const char* szActionSet )
  344. {
  345. for ( int i = 0; i != ARRAYSIZE( g_GameActionSets ); ++i )
  346. {
  347. if ( !Q_strcmp( szActionSet, g_GameActionSets[i].strName ) )
  348. {
  349. return g_GameActionSets[i].handle;
  350. }
  351. }
  352. return 0;
  353. }
  354. void CInputSystem::ActivateSteamControllerActionSetForSlot( uint64 nSlot, GameActionSet_t eActionSet )
  355. {
  356. auto steamcontroller = SteamControllerInterface();
  357. bool bChangedActionSet = false;
  358. if ( steamcontroller )
  359. {
  360. if ( nSlot == STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS )
  361. {
  362. for ( int i = 0; i < STEAM_CONTROLLER_MAX_COUNT; i++ )
  363. {
  364. if ( m_currentActionSet[i] != eActionSet )
  365. {
  366. bChangedActionSet = true;
  367. m_currentActionSet[i] = eActionSet;
  368. }
  369. }
  370. steamcontroller->ActivateActionSet( STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS, g_GameActionSets[eActionSet].handle );
  371. }
  372. else
  373. {
  374. uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
  375. int unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
  376. if( nSlot < unNumConnected )
  377. {
  378. if ( m_currentActionSet[nSlot] != eActionSet )
  379. {
  380. bChangedActionSet = true;
  381. m_currentActionSet[nSlot] = eActionSet;
  382. }
  383. steamcontroller->ActivateActionSet( nControllerHandles[nSlot], g_GameActionSets[eActionSet].handle );
  384. }
  385. }
  386. }
  387. if ( bChangedActionSet )
  388. {
  389. // 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)
  390. for ( int i = 0; i < STEAM_CONTROLLER_MAX_COUNT; i++ )
  391. {
  392. for ( int j = 0; j != ARRAYSIZE( g_DigitalMenuActions ); ++j )
  393. {
  394. g_DigitalMenuActions[j].bAwaitingDebounce[i] = true;
  395. }
  396. }
  397. }
  398. }
  399. const int CInputSystem::GetSteamPadDeadZone( ESteamPadAxis axis )
  400. {
  401. int nDeadzone = s_nSteamPadDeadZoneTable[ axis ];
  402. // Do modifications if required here?
  403. return nDeadzone;
  404. }
  405. //-----------------------------------------------------------------------------
  406. // Purpose: Processes data for controller
  407. //-----------------------------------------------------------------------------
  408. void CInputSystem::ReadSteamController( int iIndex )
  409. {
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Purpose: Pulse haptic feedback
  413. //-----------------------------------------------------------------------------
  414. /* void CInputSystem::PulseHapticOnSteamController( uint32 nControllerIndex, ESteamControllerPad ePad, unsigned short durationMicroSec )
  415. {
  416. auto steamcontroller = SteamControllerInterface();
  417. if ( steamcontroller )
  418. {
  419. steamcontroller->TriggerHapticPulse( nControllerIndex, ePad, durationMicroSec );
  420. }
  421. }*/
  422. //-----------------------------------------------------------------------------
  423. // Purpose: Returns the controller State for a particular joystick slot
  424. //-----------------------------------------------------------------------------
  425. bool CInputSystem::GetControllerStateForSlot( int nSlot )
  426. {
  427. return false;
  428. }
  429. int CInputSystem::GetSteamControllerIndexForSlot( int nSlot )
  430. {
  431. for ( int i = 0; i < Q_ARRAYSIZE( m_Device ); i++ )
  432. {
  433. if ( m_Device[i].active && (int)m_Device[i].m_nJoystickIndex == nSlot )
  434. {
  435. return m_Device[i].m_nHardwareIndex;
  436. }
  437. }
  438. return -1;
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose: Post events, ignoring key repeats
  442. //-----------------------------------------------------------------------------
  443. void CInputSystem::PostKeyEvent( int iIndex, sKey_t sKey, int nSample )
  444. {
  445. // Rework of xbox code here :
  446. AnalogCode_t code = ANALOG_CODE_LAST;
  447. float value = 0.f;
  448. //int nMsgSlot = iIndex;
  449. int nMsgSlot = m_Device[iIndex].m_nJoystickIndex;
  450. int nSampleThreshold = 1;
  451. // Look for changes on the analog axes
  452. switch( sKey )
  453. {
  454. case SK_BUTTON_LPAD_LEFT:
  455. case SK_BUTTON_LPAD_RIGHT:
  456. {
  457. code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_X );
  458. value = ( sKey == SK_BUTTON_LPAD_LEFT ) ? -nSample : nSample;
  459. // Kind of a hack to horizontal values for menu selection items in Portal 2
  460. // The additional 5k helps accidental horizontals in menus.
  461. nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD ) + 5000;
  462. }
  463. break;
  464. case SK_BUTTON_LPAD_UP:
  465. case SK_BUTTON_LPAD_DOWN:
  466. {
  467. code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_Y );
  468. value = ( sKey == SK_BUTTON_LPAD_UP ) ? -nSample : nSample;
  469. nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD );
  470. }
  471. break;
  472. case SK_BUTTON_RPAD_LEFT:
  473. case SK_BUTTON_RPAD_RIGHT:
  474. {
  475. code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_U );
  476. value = ( sKey == SK_BUTTON_RPAD_LEFT ) ? -nSample : nSample;
  477. // Kind of a hack to horizontal values for menu selection items in Portal 2
  478. // The additional 5k helps accidental horizontals in menus.
  479. nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD ) + 5000;;
  480. }
  481. break;
  482. case SK_BUTTON_RPAD_UP:
  483. case SK_BUTTON_RPAD_DOWN:
  484. {
  485. code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_R );
  486. value = ( sKey == SK_BUTTON_RPAD_UP ) ? -nSample : nSample;
  487. nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD );
  488. }
  489. break;
  490. }
  491. // Store the analog event
  492. if ( ANALOG_CODE_LAST != code )
  493. {
  494. InputState_t &state = m_InputState[ m_bIsPolling ];
  495. state.m_pAnalogDelta[ code ] = ( int )( value - state.m_pAnalogValue[ code ] );
  496. state.m_pAnalogValue[ code ] = ( int )value;
  497. if ( state.m_pAnalogDelta[ code ] != 0 )
  498. {
  499. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, code, ( int )value, state.m_pAnalogDelta[ code ] );
  500. }
  501. }
  502. // store the key
  503. m_Device[iIndex].m_appSKeys[sKey].sample = nSample;
  504. if ( nSample > nSampleThreshold )
  505. {
  506. m_Device[iIndex].m_appSKeys[sKey].repeats++;
  507. }
  508. else
  509. {
  510. m_Device[iIndex].m_appSKeys[sKey].repeats = 0;
  511. nSample = 0;
  512. }
  513. if ( m_Device[iIndex].m_appSKeys[sKey].repeats > 1 )
  514. {
  515. // application cannot handle streaming keys
  516. // first keypress is the only edge trigger
  517. return;
  518. }
  519. // package the key
  520. ButtonCode_t buttonCode = SKeyToButtonCode( nMsgSlot, sKey );
  521. if ( nSample )
  522. {
  523. PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
  524. }
  525. else
  526. {
  527. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
  528. }
  529. }
  530. // Gets the action origin (i.e. which physical input) maps to the given virtual button for the given action set
  531. EControllerActionOrigin CInputSystem::GetSteamControllerActionOrigin( const char* action, GameActionSet_t action_set )
  532. {
  533. auto pSC = SteamControllerInterface();
  534. if ( pSC )
  535. {
  536. ControllerHandle_t hConnected[STEAM_CONTROLLER_MAX_COUNT];
  537. auto nConnected = pSC->GetConnectedControllers( hConnected );
  538. if ( nConnected == 0 )
  539. {
  540. return k_EControllerActionOrigin_None;
  541. }
  542. SGameActionSet* pActionSet = nullptr;
  543. for ( int i = 0; i < ARRAYSIZE( g_GameActionSets ); i++ )
  544. {
  545. if ( g_GameActionSets[i].eGameActionSet == action_set )
  546. {
  547. pActionSet = &g_GameActionSets[i];
  548. break;
  549. }
  550. }
  551. if ( pActionSet )
  552. {
  553. auto actionHandle = pSC->GetDigitalActionHandle( action );
  554. EControllerActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS];
  555. int nOrigins = pSC->GetDigitalActionOrigins( hConnected[0], pActionSet->handle, actionHandle, origins );
  556. if ( nOrigins > 0 )
  557. {
  558. return origins[0];
  559. }
  560. }
  561. }
  562. return k_EControllerActionOrigin_None;
  563. }
  564. // Gets the action origin (i.e. which physical input) maps to the given virtual button for the given action set
  565. EControllerActionOrigin CInputSystem::GetSteamControllerActionOrigin( const char* action, ControllerActionSetHandle_t action_set_handle )
  566. {
  567. auto pSC = SteamControllerInterface();
  568. if ( pSC && action_set_handle )
  569. {
  570. ControllerHandle_t hConnected[STEAM_CONTROLLER_MAX_COUNT];
  571. auto nConnected = pSC->GetConnectedControllers( hConnected );
  572. if ( nConnected == 0 )
  573. {
  574. return k_EControllerActionOrigin_None;
  575. }
  576. auto actionHandle = pSC->GetDigitalActionHandle( action );
  577. EControllerActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS];
  578. int nOrigins = pSC->GetDigitalActionOrigins( hConnected[0], action_set_handle, actionHandle, origins );
  579. if ( nOrigins > 0 )
  580. {
  581. return origins[0];
  582. }
  583. }
  584. return k_EControllerActionOrigin_None;
  585. }
  586. // Maps a Steam Controller action origin to a string (consisting of a single character) in our SC icon font
  587. const wchar_t* CInputSystem::GetSteamControllerFontCharacterForActionOrigin( EControllerActionOrigin origin )
  588. {
  589. if ( origin >= 0 && origin < ARRAYSIZE( g_MapSteamControllerOriginToIconFont ) )
  590. {
  591. return g_MapSteamControllerOriginToIconFont[origin];
  592. }
  593. else
  594. {
  595. return L"";
  596. }
  597. }
  598. // Maps a Steam Controller action origin to a short text string (e.g. "X", "LB", "LDOWN") describing the control.
  599. // Prefer to actually use the icon font wherever possible.
  600. const wchar_t* CInputSystem::GetSteamControllerDescriptionForActionOrigin( EControllerActionOrigin origin )
  601. {
  602. if ( origin >= 0 && origin < ARRAYSIZE( g_MapSteamControllerOriginToDescription ) )
  603. {
  604. return g_MapSteamControllerOriginToDescription[origin];
  605. }
  606. else
  607. {
  608. return L"";
  609. }
  610. }