Counter Strike : Global Offensive Source Code
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.

2500 lines
72 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "inputsystem.h"
  7. #include "key_translation.h"
  8. #include "inputsystem/ButtonCode.h"
  9. #include "inputsystem/AnalogCode.h"
  10. #include "tier0/etwprof.h"
  11. #include "tier1/convar.h"
  12. #include "filesystem.h"
  13. #include "platforminputdevice.h"
  14. #ifdef _PS3
  15. #include <vjobs_interface.h>
  16. #endif
  17. #ifdef PLATFORM_OSX
  18. #include <Carbon/Carbon.h>
  19. #include "materialsystem/imaterialsystem.h"
  20. #endif
  21. #if defined( INCLUDE_SCALEFORM )
  22. #include "scaleformui/scaleformui.h"
  23. #endif
  24. // NOTE: This has to be the last file included!
  25. #include "tier0/memdbgon.h"
  26. #if defined( INCLUDE_SCALEFORM )
  27. IScaleformUI* g_pScaleformUI = NULL;
  28. #endif
  29. #if defined( USE_SDL )
  30. #include "SDL.h"
  31. static void initKeymap(void);
  32. #endif
  33. ConVar joy_xcontroller_found( "joy_xcontroller_found", "1", FCVAR_NONE, "Automatically set to 1 if an xcontroller has been detected." );
  34. ConVar joy_deadzone_mode( "joy_deadzone_mode", "0", FCVAR_NONE, "0 => Cross-shaped deadzone (default), 1 => Square deadzone." );
  35. ConVar pc_fake_controller( "pc_fake_controller", "0", FCVAR_DEVELOPMENTONLY, "" );
  36. ConVar dev_force_selected_device( "dev_force_selected_device", "0", FCVAR_DEVELOPMENTONLY, "" );
  37. //-----------------------------------------------------------------------------
  38. // Singleton instance
  39. //-----------------------------------------------------------------------------
  40. static CInputSystem g_InputSystem;
  41. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CInputSystem, IInputSystem,
  42. INPUTSYSTEM_INTERFACE_VERSION, g_InputSystem );
  43. #ifdef _PS3
  44. IVJobs * g_pVJobs = NULL;
  45. #endif
  46. #if defined( WIN32 ) && !defined( _X360 )
  47. typedef BOOL (WINAPI *RegisterRawInputDevices_t)
  48. (
  49. PCRAWINPUTDEVICE pRawInputDevices,
  50. UINT uiNumDevices,
  51. UINT cbSize
  52. );
  53. typedef UINT (WINAPI *GetRawInputData_t)
  54. (
  55. HRAWINPUT hRawInput,
  56. UINT uiCommand,
  57. LPVOID pData,
  58. PUINT pcbSize,
  59. UINT cbSizeHeader
  60. );
  61. RegisterRawInputDevices_t pfnRegisterRawInputDevices;
  62. GetRawInputData_t pfnGetRawInputData;
  63. #endif
  64. extern int countBits( uint32 iValue );
  65. //-----------------------------------------------------------------------------
  66. // Constructor, destructor
  67. //-----------------------------------------------------------------------------
  68. CInputSystem::CInputSystem()
  69. {
  70. m_nLastPollTick = m_nLastSampleTick = m_StartupTimeTick = 0;
  71. m_ChainedWndProc = 0;
  72. m_hAttachedHWnd = 0;
  73. m_hEvent = NULL;
  74. m_bEnabled = true;
  75. m_bPumpEnabled = true;
  76. m_bIsPolling = false;
  77. m_bIsInGame = false;
  78. m_JoysticksEnabled.ClearAllFlags();
  79. m_nJoystickCount = 0;
  80. m_nJoystickBaseline = 0;
  81. m_nPollCount = 0;
  82. m_uiMouseWheel = 0;
  83. m_bXController = false;
  84. m_bRawInputSupported = false;
  85. m_bIMEComposing = false;
  86. m_nUIEventClientCount = 0;
  87. m_hLastIMEHWnd = NULL;
  88. m_hCurrentCaptureWnd = PLAT_WINDOW_INVALID;
  89. m_bCursorVisible = true;
  90. m_hCursor = INPUT_CURSOR_HANDLE_INVALID;
  91. m_bMotionControllerActive = false;
  92. m_qMotionControllerOrientation.Init();
  93. m_fMotionControllerPosX = 0.0f;
  94. m_fMotionControllerPosY = 0.0f;
  95. m_nMotionControllerStatus = INPUT_DEVICE_MC_STATE_CAMERA_NOT_CONNECTED;
  96. m_nMotionControllerStatusFlags = 0;
  97. // This is B.S., must be a compile-time assert with valid expression:
  98. // Assert( (MAX_JOYSTICKS + 7) >> 3 << sizeof(unsigned short) );
  99. #if !defined( _CERT ) && !defined(LINUX)
  100. V_memset( m_press_x360_buttons, 0, sizeof( m_press_x360_buttons ) );
  101. #endif
  102. #ifdef _PS3
  103. m_pPS3CellNoPadDataHook = NULL;
  104. m_pPS3CellPadDataHook = NULL;
  105. m_PS3KeyboardConnected = false;
  106. m_PS3MouseConnected = false;
  107. #endif
  108. m_pXInputDLL = NULL;
  109. m_pRawInputDLL = NULL;
  110. for ( int i = 0; i < Q_ARRAYSIZE(m_nControllerType); i++)
  111. {
  112. m_nControllerType[i] = INPUT_TYPE_GENERIC_JOYSTICK;
  113. }
  114. InitPlatfromInputDeviceInfo();
  115. }
  116. #if defined( USE_SDL )
  117. void CInputSystem::DisableHardwareCursor( )
  118. {
  119. m_pLauncherMgr->SetMouseVisible(false);
  120. }
  121. void CInputSystem::EnableHardwareCursor( )
  122. {
  123. m_pLauncherMgr->SetMouseVisible(true);
  124. }
  125. #endif
  126. CInputSystem::~CInputSystem()
  127. {
  128. if ( m_pXInputDLL )
  129. {
  130. Sys_UnloadModule( m_pXInputDLL );
  131. m_pXInputDLL = NULL;
  132. }
  133. if ( m_pRawInputDLL )
  134. {
  135. Sys_UnloadModule( m_pRawInputDLL );
  136. m_pRawInputDLL = NULL;
  137. }
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Initialization
  141. //-----------------------------------------------------------------------------
  142. InitReturnVal_t CInputSystem::Init()
  143. {
  144. InitReturnVal_t nRetVal = BaseClass::Init();
  145. if ( nRetVal != INIT_OK )
  146. return nRetVal;
  147. m_StartupTimeTick = Plat_MSTime();
  148. #if !defined( PLATFORM_POSIX )
  149. if ( IsPC() )
  150. {
  151. m_uiMouseWheel = RegisterWindowMessage( "MSWHEEL_ROLLMSG" );
  152. }
  153. m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  154. if ( !m_hEvent )
  155. return INIT_FAILED;
  156. #endif
  157. ButtonCode_InitKeyTranslationTable();
  158. ButtonCode_UpdateScanCodeLayout();
  159. joy_xcontroller_found.SetValue( 0 );
  160. #if !defined( _GAMECONSOLE )
  161. if ( IsPC() )
  162. {
  163. #if !defined( PLATFORM_POSIX )
  164. m_pXInputDLL = Sys_LoadModule( "XInput1_3.dll" );
  165. if ( m_pXInputDLL )
  166. {
  167. InitializeXDevices();
  168. }
  169. #endif
  170. if ( !m_nJoystickCount )
  171. {
  172. // Didn't find any XControllers. See if we can find other joysticks.
  173. InitializeJoysticks();
  174. }
  175. else
  176. {
  177. m_bXController = true;
  178. }
  179. if ( m_bXController )
  180. joy_xcontroller_found.SetValue( 1 );
  181. }
  182. #elif defined( _GAMECONSOLE )
  183. if ( IsGameConsole() )
  184. {
  185. InitializeXDevices();
  186. m_bXController = true;
  187. joy_xcontroller_found.SetValue( 1 );
  188. }
  189. #endif
  190. InitCursors();
  191. m_bRawInputSupported = false;
  192. #if defined( LINUX )
  193. m_bRawInputSupported = true;
  194. #elif defined( WIN32 ) && !defined( _X360 )
  195. // Check if this version of windows supports raw mouse input (later than win2k)
  196. CSysModule *m_pRawInputDLL = Sys_LoadModule( "USER32.dll" );
  197. if ( m_pRawInputDLL )
  198. {
  199. pfnRegisterRawInputDevices = (RegisterRawInputDevices_t)GetProcAddress( (HMODULE)m_pRawInputDLL, "RegisterRawInputDevices" );
  200. pfnGetRawInputData = (GetRawInputData_t)GetProcAddress( (HMODULE)m_pRawInputDLL, "GetRawInputData" );
  201. if ( pfnRegisterRawInputDevices && pfnGetRawInputData )
  202. m_bRawInputSupported = true;
  203. }
  204. #endif
  205. #if defined( USE_SDL )
  206. initKeymap();
  207. #endif
  208. m_unNumSteamControllerConnected = 0;
  209. m_bSteamController = InitializeSteamControllers();
  210. return INIT_OK;
  211. }
  212. bool CInputSystem::Connect( CreateInterfaceFn factory )
  213. {
  214. if ( !BaseClass::Connect( factory ) )
  215. return false;
  216. #if defined( INCLUDE_SCALEFORM )
  217. g_pScaleformUI = (IScaleformUI*)factory( SCALEFORMUI_INTERFACE_VERSION, NULL );
  218. #endif
  219. #ifdef _PS3
  220. g_pVJobs = ( IVJobs* )factory( VJOBS_INTERFACE_VERSION, NULL );
  221. #endif
  222. #if defined( USE_SDL )
  223. m_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL );
  224. #elif defined( OSX )
  225. m_pLauncherMgr = (ILauncherMgr *)factory( COCOAMGR_INTERFACE_VERSION, NULL );
  226. #endif
  227. return true;
  228. }
  229. #ifdef _PS3
  230. extern void PS3_XInputShutdown();
  231. #endif
  232. #ifdef _PS3
  233. void CInputSystem::SetPS3CellPadDataHook( BCellPadDataHook_t hookFunc )
  234. {
  235. m_pPS3CellPadDataHook = hookFunc;
  236. }
  237. void CInputSystem::SetPS3CellPadNoDataHook( BCellPadNoDataHook_t hookFunc )
  238. {
  239. m_pPS3CellNoPadDataHook = hookFunc;
  240. }
  241. #endif
  242. //-----------------------------------------------------------------------------
  243. // Shutdown
  244. //-----------------------------------------------------------------------------
  245. void CInputSystem::Shutdown()
  246. {
  247. #if !defined( PLATFORM_POSIX )
  248. if ( m_hEvent != NULL )
  249. {
  250. CloseHandle( m_hEvent );
  251. m_hEvent = NULL;
  252. }
  253. #endif
  254. ShutdownCursors();
  255. BaseClass::Shutdown();
  256. #ifdef _PS3
  257. PS3_XInputShutdown();
  258. #endif
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Sleep until input
  262. //-----------------------------------------------------------------------------
  263. void CInputSystem::SleepUntilInput( int nMaxSleepTimeMS )
  264. {
  265. #if defined( USE_SDL ) || defined( OSX )
  266. m_pLauncherMgr->WaitUntilUserInput( nMaxSleepTimeMS );
  267. #elif defined( _WIN32 )
  268. if ( nMaxSleepTimeMS < 0 )
  269. {
  270. nMaxSleepTimeMS = INFINITE;
  271. }
  272. MsgWaitForMultipleObjects( 1, &m_hEvent, FALSE, nMaxSleepTimeMS, QS_ALLEVENTS );
  273. #elif defined( _PS3 )
  274. // no-op
  275. #else
  276. #warning "need a SleepUntilInput impl"
  277. #endif
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Tells the input system to generate UI-related events, defined
  281. //-----------------------------------------------------------------------------
  282. void CInputSystem::AddUIEventListener()
  283. {
  284. ++m_nUIEventClientCount;
  285. }
  286. void CInputSystem::RemoveUIEventListener()
  287. {
  288. --m_nUIEventClientCount;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Returns the currently attached window
  292. //-----------------------------------------------------------------------------
  293. PlatWindow_t CInputSystem::GetAttachedWindow() const
  294. {
  295. return (PlatWindow_t)m_hAttachedHWnd;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Callback to call into our class
  299. //-----------------------------------------------------------------------------
  300. #if !defined( PLATFORM_POSIX )
  301. static LRESULT CALLBACK InputSystemWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  302. {
  303. return g_InputSystem.WindowProc( hwnd, uMsg, wParam, lParam );
  304. }
  305. #endif
  306. //-----------------------------------------------------------------------------
  307. // Hooks input listening up to a window
  308. //-----------------------------------------------------------------------------
  309. void CInputSystem::AttachToWindow( void* hWnd )
  310. {
  311. Assert( m_hAttachedHWnd == 0 );
  312. if ( m_hAttachedHWnd )
  313. {
  314. Warning( "CInputSystem::AttachToWindow: Cannot attach to two windows at once!\n" );
  315. return;
  316. }
  317. #if defined ( USE_SDL )
  318. #elif defined( PLATFORM_OSX )
  319. #elif defined( PLATFORM_WINDOWS )
  320. #if defined( PLATFORM_X360 ) //GetWindowLongPtrW/SetWindowLongPtrW don't exist on the 360
  321. m_ChainedWndProc = (WNDPROC)GetWindowLongPtr( (HWND)hWnd, GWLP_WNDPROC );
  322. SetWindowLongPtr( (HWND)hWnd, GWLP_WNDPROC, (LONG_PTR)InputSystemWindowProc );
  323. #else
  324. m_ChainedWndProc = (WNDPROC)GetWindowLongPtrW( (HWND)hWnd, GWLP_WNDPROC );
  325. SetWindowLongPtrW( (HWND)hWnd, GWLP_WNDPROC, (LONG_PTR)InputSystemWindowProc );
  326. // register to read raw mouse input
  327. #if !defined(HID_USAGE_PAGE_GENERIC)
  328. #define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01)
  329. #endif
  330. #if !defined(HID_USAGE_GENERIC_MOUSE)
  331. #define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02)
  332. #endif
  333. RAWINPUTDEVICE Rid[1];
  334. Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
  335. Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
  336. Rid[0].dwFlags = RIDEV_INPUTSINK;
  337. Rid[0].hwndTarget = (HWND)hWnd; // g_InputSystem.m_hAttachedHWnd; // GetHhWnd;
  338. ::RegisterRawInputDevices(Rid, ARRAYSIZE(Rid), sizeof(Rid[0]));
  339. #endif
  340. #elif defined( _PS3 )
  341. #else
  342. #error
  343. #endif
  344. m_hAttachedHWnd = (HWND)hWnd;
  345. #if defined( WIN32 ) && !defined( _X360 )
  346. // register to read raw mouse input
  347. #if !defined(HID_USAGE_PAGE_GENERIC)
  348. #define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01)
  349. #endif
  350. #if !defined(HID_USAGE_GENERIC_MOUSE)
  351. #define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02)
  352. #endif
  353. if ( m_bRawInputSupported )
  354. {
  355. RAWINPUTDEVICE Rid[1];
  356. Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
  357. Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
  358. Rid[0].dwFlags = RIDEV_INPUTSINK;
  359. Rid[0].hwndTarget = g_InputSystem.m_hAttachedHWnd; // GetHhWnd;
  360. pfnRegisterRawInputDevices(Rid, ARRAYSIZE(Rid), sizeof(Rid[0]));
  361. }
  362. #endif
  363. // New window, clear input state
  364. ClearInputState( true );
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Unhooks input listening from a window
  368. //-----------------------------------------------------------------------------
  369. void CInputSystem::DetachFromWindow( )
  370. {
  371. if ( !m_hAttachedHWnd )
  372. return;
  373. ResetInputState();
  374. #if !defined( PLATFORM_POSIX )
  375. if ( m_ChainedWndProc )
  376. {
  377. SetWindowLongPtrW( m_hAttachedHWnd, GWLP_WNDPROC, (LONG_PTR)m_ChainedWndProc );
  378. m_ChainedWndProc = 0;
  379. }
  380. #endif
  381. m_hAttachedHWnd = 0;
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Enables/disables input
  385. //-----------------------------------------------------------------------------
  386. void CInputSystem::EnableInput( bool bEnable )
  387. {
  388. m_bEnabled = bEnable;
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Enables/disables the inputsystem windows message pump
  392. //-----------------------------------------------------------------------------
  393. void CInputSystem::EnableMessagePump( bool bEnable )
  394. {
  395. m_bPumpEnabled = bEnable;
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Clears the input state, doesn't generate key-up messages
  399. //-----------------------------------------------------------------------------
  400. void CInputSystem::ClearInputState( bool bPurgeState )
  401. {
  402. for ( int i = 0; i < INPUT_STATE_COUNT; ++i )
  403. {
  404. InputState_t& state = m_InputState[i];
  405. state.m_ButtonState.ClearAll();
  406. memset( state.m_pAnalogDelta, 0, ANALOG_CODE_LAST * sizeof(int) );
  407. memset( state.m_pAnalogValue, 0, ANALOG_CODE_LAST * sizeof(int) );
  408. memset( state.m_ButtonPressedTick, 0, BUTTON_CODE_LAST * sizeof(int) );
  409. memset( state.m_ButtonReleasedTick, 0, BUTTON_CODE_LAST * sizeof(int) );
  410. if ( bPurgeState )
  411. {
  412. state.m_Events.Purge();
  413. state.m_bDirty = false;
  414. }
  415. }
  416. memset( m_appXKeys, 0, XUSER_MAX_COUNT * XK_MAX_KEYS * sizeof(appKey_t) );
  417. m_mouseRawAccumX = m_mouseRawAccumY = 0;
  418. m_flLastControllerPollTime = 0;
  419. }
  420. //-----------------------------------------------------------------------------
  421. // Resets the input state
  422. //-----------------------------------------------------------------------------
  423. void CInputSystem::ResetInputState()
  424. {
  425. ReleaseAllButtons();
  426. ZeroAnalogState( 0, ANALOG_CODE_LAST - 1 );
  427. ClearInputState( false );
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Convert back + forth between ButtonCode/AnalogCode + strings
  431. //-----------------------------------------------------------------------------
  432. const char *CInputSystem::ButtonCodeToString( ButtonCode_t code ) const
  433. {
  434. return ButtonCode_ButtonCodeToString( code, m_bXController );
  435. }
  436. const char *CInputSystem::AnalogCodeToString( AnalogCode_t code ) const
  437. {
  438. return AnalogCode_AnalogCodeToString( code );
  439. }
  440. ButtonCode_t CInputSystem::StringToButtonCode( const char *pString ) const
  441. {
  442. return ButtonCode_StringToButtonCode( pString, true );
  443. }
  444. AnalogCode_t CInputSystem::StringToAnalogCode( const char *pString ) const
  445. {
  446. return AnalogCode_StringToAnalogCode( pString );
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Convert back + forth between virtual codes + button codes
  450. // FIXME: This is a temporary piece of code
  451. //-----------------------------------------------------------------------------
  452. ButtonCode_t CInputSystem::VirtualKeyToButtonCode( int nVirtualKey ) const
  453. {
  454. return ButtonCode_VirtualKeyToButtonCode( nVirtualKey );
  455. }
  456. int CInputSystem::ButtonCodeToVirtualKey( ButtonCode_t code ) const
  457. {
  458. return ButtonCode_ButtonCodeToVirtualKey( code );
  459. }
  460. ButtonCode_t CInputSystem::XKeyToButtonCode( int nPort, int nXKey ) const
  461. {
  462. if ( m_bXController )
  463. return ButtonCode_XKeyToButtonCode( nPort, nXKey );
  464. return KEY_NONE;
  465. }
  466. ButtonCode_t CInputSystem::ScanCodeToButtonCode( int lParam ) const
  467. {
  468. return ButtonCode_ScanCodeToButtonCode( lParam );
  469. }
  470. ButtonCode_t CInputSystem::SKeyToButtonCode( int nPort, int nXKey ) const
  471. {
  472. return ButtonCode_SKeyToButtonCode( nPort, nXKey );
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Post an event to the queue
  476. //-----------------------------------------------------------------------------
  477. void CInputSystem::PostEvent( int nType, int nTick, int nData, int nData2, int nData3 )
  478. {
  479. InputState_t &state = m_InputState[ m_bIsPolling ];
  480. int i = state.m_Events.AddToTail();
  481. InputEvent_t &event = state.m_Events[i];
  482. event.m_nType = nType;
  483. event.m_nTick = nTick;
  484. event.m_nData = nData;
  485. event.m_nData2 = nData2;
  486. event.m_nData3 = nData3;
  487. state.m_bDirty = true;
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Post an button press event to the queue
  491. //-----------------------------------------------------------------------------
  492. void CInputSystem::PostButtonPressedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode )
  493. {
  494. InputState_t &state = m_InputState[ m_bIsPolling ];
  495. if ( !state.m_ButtonState.IsBitSet( scanCode ) )
  496. {
  497. // Update button state
  498. state.m_ButtonState.Set( scanCode );
  499. state.m_ButtonPressedTick[ scanCode ] = nTick;
  500. // Add this event to the app-visible event queue
  501. PostEvent( nType, nTick, scanCode, virtualCode );
  502. if ( IsGameConsole() && ShouldGenerateUIEvents() && IsJoystickCode( scanCode ) )
  503. {
  504. // xboxissue - as yet input hasn't been made aware of analog inputs or ports
  505. // so just digital produce a key typed message
  506. PostEvent( IE_KeyCodeTyped, nTick, scanCode );
  507. }
  508. }
  509. }
  510. //-----------------------------------------------------------------------------
  511. // Post an button release event to the queue
  512. //-----------------------------------------------------------------------------
  513. void CInputSystem::PostButtonReleasedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode )
  514. {
  515. InputState_t &state = m_InputState[ m_bIsPolling ];
  516. if ( state.m_ButtonState.IsBitSet( scanCode ) )
  517. {
  518. // Update button state
  519. state.m_ButtonState.Clear( scanCode );
  520. state.m_ButtonReleasedTick[ scanCode ] = nTick;
  521. // Add this event to the app-visible event queue
  522. PostEvent( nType, nTick, scanCode, virtualCode );
  523. }
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: Pass Joystick button events through the engine's window procs
  527. //-----------------------------------------------------------------------------
  528. void CInputSystem::ProcessEvent( UINT uMsg, WPARAM wParam, LPARAM lParam )
  529. {
  530. #if !defined( PLATFORM_POSIX )
  531. // To prevent subtle input timing bugs, all button events must be fed
  532. // through the window proc once per frame, same as the keyboard and mouse.
  533. HWND hWnd = GetFocus();
  534. WNDPROC windowProc = (WNDPROC)GetWindowLongPtrW(hWnd, GWLP_WNDPROC );
  535. if ( windowProc )
  536. {
  537. windowProc( hWnd, uMsg, wParam, lParam );
  538. }
  539. #endif
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Copies the input state record over
  543. //-----------------------------------------------------------------------------
  544. void CInputSystem::CopyInputState( InputState_t *pDest, const InputState_t &src, bool bCopyEvents )
  545. {
  546. pDest->m_Events.RemoveAll();
  547. pDest->m_bDirty = false;
  548. if ( src.m_bDirty )
  549. {
  550. pDest->m_ButtonState = src.m_ButtonState;
  551. memcpy( &pDest->m_ButtonPressedTick, &src.m_ButtonPressedTick, sizeof( pDest->m_ButtonPressedTick ) );
  552. memcpy( &pDest->m_ButtonReleasedTick, &src.m_ButtonReleasedTick, sizeof( pDest->m_ButtonReleasedTick ) );
  553. memcpy( &pDest->m_pAnalogDelta, &src.m_pAnalogDelta, sizeof( pDest->m_pAnalogDelta ) );
  554. memcpy( &pDest->m_pAnalogValue, &src.m_pAnalogValue, sizeof( pDest->m_pAnalogValue ) );
  555. if ( bCopyEvents )
  556. {
  557. if ( src.m_Events.Count() > 0 )
  558. {
  559. pDest->m_Events.EnsureCount( src.m_Events.Count() );
  560. memcpy( pDest->m_Events.Base(), src.m_Events.Base(), src.m_Events.Count() * sizeof(InputEvent_t) );
  561. }
  562. }
  563. }
  564. }
  565. #if defined( WIN32 ) && !defined( USE_SDL )
  566. void CInputSystem::PollInputState_Windows()
  567. {
  568. if ( IsPC() && m_bPumpEnabled )
  569. {
  570. // Poll mouse + keyboard
  571. MSG msg;
  572. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  573. {
  574. if ( msg.message == WM_QUIT )
  575. {
  576. PostEvent( IE_Quit, m_nLastSampleTick );
  577. break;
  578. }
  579. #if defined( INCLUDE_SCALEFORM )
  580. if ( g_pScaleformUI )
  581. {
  582. // Scaleform IME requirement. Pass these messages to GFxIME BEFORE any TranlsateMessage/DispatchMessage.
  583. if ( (msg.message == WM_KEYDOWN) || (msg.message == WM_KEYUP) || ImmIsUIMessage( NULL, msg.message, msg.wParam, msg.lParam )
  584. || (msg.message == WM_LBUTTONDOWN) || (msg.message == WM_LBUTTONUP) )
  585. {
  586. g_pScaleformUI->PreProcessKeyboardEvent( (size_t)msg.hwnd, msg.message, msg.wParam, msg.lParam );
  587. }
  588. }
  589. #endif
  590. TranslateMessage( &msg );
  591. DispatchMessage( &msg );
  592. }
  593. // NOTE: Under some implementations of Win9x,
  594. // dispatching messages can cause the FPU control word to change
  595. SetupFPUControlWord();
  596. }
  597. }
  598. #endif
  599. #if defined(OSX) || defined( USE_SDL )
  600. #if defined( USE_SDL )
  601. static BYTE scantokey[SDL_NUM_SCANCODES];
  602. static void initKeymap(void)
  603. {
  604. memset(scantokey, '\0', sizeof (scantokey));
  605. for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_Z; i++)
  606. scantokey[i] = KEY_A + (i - SDL_SCANCODE_A);
  607. for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_9; i++)
  608. scantokey[i] = KEY_1 + (i - SDL_SCANCODE_1);
  609. for (int i = SDL_SCANCODE_F1; i <= SDL_SCANCODE_F12; i++)
  610. scantokey[i] = KEY_F1 + (i - SDL_SCANCODE_F1);
  611. for (int i = SDL_SCANCODE_KP_1; i <= SDL_SCANCODE_KP_9; i++)
  612. scantokey[i] = KEY_PAD_1 + (i - SDL_SCANCODE_KP_1);
  613. scantokey[SDL_SCANCODE_0] = KEY_0;
  614. scantokey[SDL_SCANCODE_KP_0] = KEY_PAD_0;
  615. scantokey[SDL_SCANCODE_RETURN] = KEY_ENTER;
  616. scantokey[SDL_SCANCODE_ESCAPE] = KEY_ESCAPE;
  617. scantokey[SDL_SCANCODE_BACKSPACE] = KEY_BACKSPACE;
  618. scantokey[SDL_SCANCODE_TAB] = KEY_TAB;
  619. scantokey[SDL_SCANCODE_SPACE] = KEY_SPACE;
  620. scantokey[SDL_SCANCODE_MINUS] = KEY_MINUS;
  621. scantokey[SDL_SCANCODE_EQUALS] = KEY_EQUAL;
  622. scantokey[SDL_SCANCODE_LEFTBRACKET] = KEY_LBRACKET;
  623. scantokey[SDL_SCANCODE_RIGHTBRACKET] = KEY_RBRACKET;
  624. scantokey[SDL_SCANCODE_BACKSLASH] = KEY_BACKSLASH;
  625. scantokey[SDL_SCANCODE_SEMICOLON] = KEY_SEMICOLON;
  626. scantokey[SDL_SCANCODE_APOSTROPHE] = KEY_APOSTROPHE;
  627. scantokey[SDL_SCANCODE_GRAVE] = KEY_BACKQUOTE;
  628. scantokey[SDL_SCANCODE_COMMA] = KEY_COMMA;
  629. scantokey[SDL_SCANCODE_PERIOD] = KEY_PERIOD;
  630. scantokey[SDL_SCANCODE_SLASH] = KEY_SLASH;
  631. scantokey[SDL_SCANCODE_CAPSLOCK] = KEY_CAPSLOCK;
  632. scantokey[SDL_SCANCODE_SCROLLLOCK] = KEY_SCROLLLOCK;
  633. scantokey[SDL_SCANCODE_INSERT] = KEY_INSERT;
  634. scantokey[SDL_SCANCODE_HOME] = KEY_HOME;
  635. scantokey[SDL_SCANCODE_PAGEUP] = KEY_PAGEUP;
  636. scantokey[SDL_SCANCODE_DELETE] = KEY_DELETE;
  637. scantokey[SDL_SCANCODE_END] = KEY_END;
  638. scantokey[SDL_SCANCODE_PAGEDOWN] = KEY_PAGEDOWN;
  639. scantokey[SDL_SCANCODE_RIGHT] = KEY_RIGHT;
  640. scantokey[SDL_SCANCODE_LEFT] = KEY_LEFT;
  641. scantokey[SDL_SCANCODE_DOWN] = KEY_DOWN;
  642. scantokey[SDL_SCANCODE_UP] = KEY_UP;
  643. scantokey[SDL_SCANCODE_NUMLOCKCLEAR] = KEY_NUMLOCK;
  644. scantokey[SDL_SCANCODE_KP_DIVIDE] = KEY_PAD_DIVIDE;
  645. scantokey[SDL_SCANCODE_KP_MULTIPLY] = KEY_PAD_MULTIPLY;
  646. scantokey[SDL_SCANCODE_KP_MINUS] = KEY_PAD_MINUS;
  647. scantokey[SDL_SCANCODE_KP_PLUS] = KEY_PAD_PLUS;
  648. // Map keybad enter to enter for vgui. This means vgui dialog won't ever see KEY_PAD_ENTER
  649. scantokey[SDL_SCANCODE_KP_ENTER] = KEY_ENTER;
  650. scantokey[SDL_SCANCODE_KP_PERIOD] = KEY_PAD_DECIMAL;
  651. scantokey[SDL_SCANCODE_APPLICATION] = KEY_APP;
  652. scantokey[SDL_SCANCODE_LCTRL] = KEY_LCONTROL;
  653. scantokey[SDL_SCANCODE_LSHIFT] = KEY_LSHIFT;
  654. scantokey[SDL_SCANCODE_LALT] = KEY_LALT;
  655. scantokey[SDL_SCANCODE_LGUI] = KEY_LWIN;
  656. scantokey[SDL_SCANCODE_RCTRL] = KEY_RCONTROL;
  657. scantokey[SDL_SCANCODE_RSHIFT] = KEY_RSHIFT;
  658. scantokey[SDL_SCANCODE_RALT] = KEY_RALT;
  659. scantokey[SDL_SCANCODE_RGUI] = KEY_RWIN;
  660. }
  661. #elif defined(OSX)
  662. static BYTE scantokey[128] =
  663. {
  664. KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
  665. KEY_C, KEY_V, KEY_BACKQUOTE /*german backquote char*/ , KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R, //15
  666. KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5, // 23
  667. KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RBRACKET, KEY_O, //31
  668. KEY_U, KEY_LBRACKET, KEY_I, KEY_P, KEY_ENTER , KEY_L, KEY_J, KEY_APOSTROPHE, //39
  669. KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA,KEY_SLASH, KEY_N, KEY_M, KEY_PERIOD, // 47
  670. KEY_TAB, KEY_SPACE, KEY_BACKQUOTE, KEY_BACKSPACE, 0, KEY_ESCAPE, KEY_RWIN, KEY_LWIN, //55
  671. KEY_LSHIFT, KEY_CAPSLOCK, KEY_LALT, KEY_LCONTROL, KEY_LSHIFT, 0, KEY_RCONTROL, 0, //63
  672. 0, KEY_PAD_DECIMAL, 0 , KEY_PAD_MULTIPLY, 0 , KEY_PAD_PLUS, 0 , KEY_NUMLOCK , // 71
  673. 0, 0 , 0 , KEY_PAD_DIVIDE, KEY_PAD_ENTER, 0 , KEY_PAD_MINUS, 0 , // 79
  674. 0, KEY_PAD_DIVIDE, KEY_PAD_0, KEY_PAD_1, KEY_PAD_2, KEY_PAD_3, KEY_PAD_4, KEY_PAD_5, // 87
  675. KEY_PAD_6, KEY_PAD_7, 0, KEY_PAD_8, KEY_PAD_9, 0, 0 , 0 , // 95
  676. KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11, // 103
  677. 0, 0 , 0 , 0 , 0, KEY_F10, KEY_APP , KEY_F12, // 111
  678. 0 , 0, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END, // 119
  679. KEY_F2, KEY_PAGEDOWN, KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0, // 127
  680. };
  681. #else
  682. #error
  683. #endif
  684. bool MapCocoaVirtualKeyToButtonCode( int nCocoaVirtualKeyCode, ButtonCode_t *pOut )
  685. {
  686. if ( nCocoaVirtualKeyCode < 0 )
  687. *pOut = (ButtonCode_t)(-1 * nCocoaVirtualKeyCode);
  688. else
  689. {
  690. #ifdef OSX
  691. int modified = nCocoaVirtualKeyCode & 255;
  692. if ( modified > 127)
  693. {
  694. return false;
  695. }
  696. #else
  697. nCocoaVirtualKeyCode &= 0x000000ff;
  698. #endif
  699. *pOut = (ButtonCode_t)scantokey[nCocoaVirtualKeyCode];
  700. }
  701. return true;
  702. }
  703. #ifdef LINUX
  704. void CInputSystem::PollInputState_Linux()
  705. #elif defined( OSX )
  706. void CInputSystem::PollInputState_OSX()
  707. #elif defined( _WIN32 )
  708. void CInputSystem::PollInputState_Windows()
  709. #endif
  710. {
  711. InputState_t &state = m_InputState[ m_bIsPolling ];
  712. if ( m_bPumpEnabled )
  713. m_pLauncherMgr->PumpWindowsMessageLoop();
  714. // These are Carbon virtual key codes. AFAIK they don't have a header that defines these, but they are supposed to map
  715. // to the same letters across international keyboards, so our mapping here should work.
  716. CCocoaEvent events[32];
  717. while ( 1 )
  718. {
  719. int nEvents = m_pLauncherMgr->GetEvents( events, ARRAYSIZE( events ) );
  720. if ( nEvents == 0 )
  721. break;
  722. for ( int iEvent=0; iEvent < nEvents; iEvent++ )
  723. {
  724. CCocoaEvent *pEvent = &events[iEvent];
  725. switch( pEvent->m_EventType )
  726. {
  727. case CocoaEvent_Deleted:
  728. break;
  729. case CocoaEvent_KeyDown:
  730. {
  731. ButtonCode_t virtualCode;
  732. if ( MapCocoaVirtualKeyToButtonCode( pEvent->m_VirtualKeyCode, &virtualCode ) )
  733. {
  734. ButtonCode_t scanCode = virtualCode;
  735. #ifdef LINUX
  736. if( scanCode != BUTTON_CODE_NONE )
  737. #endif
  738. {
  739. // For SDL, hitting spacebar causes a SDL_KEYDOWN event, then SDL_TEXTINPUT with
  740. // event.text.text[0] = ' ', and then we get here and wind up sending two events
  741. // to PostButtonPressedEvent. The first is virtualCode = ' ', the 2nd has virtualCode = 0.
  742. // This will confuse Button::OnKeyCodePressed(), which is checking for space keydown
  743. // followed by space keyup. So we ignore all BUTTON_CODE_NONE events here.
  744. PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, scanCode, virtualCode );
  745. }
  746. InputEvent_t event;
  747. memset( &event, 0, sizeof(event) );
  748. event.m_nTick = GetPollTick();
  749. event.m_nType = IE_KeyCodeTyped;
  750. event.m_nData = scanCode;
  751. g_pInputSystem->PostUserEvent( event );
  752. #if defined( LINUX ) || (defined( OSX ) && defined( USE_SDL ) )
  753. if ( scanCode == KEY_BACKSPACE )
  754. {
  755. // On Linux (and OS X, when using SDL), we need to fire this event to have backspace keypresses picked up by scaleform.
  756. PostEvent( IE_KeyTyped, GetPollTick(), (wchar_t)8 );
  757. }
  758. #endif
  759. }
  760. if ( !(pEvent->m_ModifierKeyMask & (1<<eCommandKey) ) && pEvent->m_VirtualKeyCode >= 0 && pEvent->m_UnicodeKey > 0 )
  761. {
  762. InputEvent_t event;
  763. memset( &event, 0, sizeof(event) );
  764. event.m_nTick = GetPollTick();
  765. event.m_nType = IE_KeyTyped;
  766. event.m_nData = (int)pEvent->m_UnicodeKey;
  767. g_pInputSystem->PostUserEvent( event );
  768. }
  769. #if defined ( CSTRIKE15 )
  770. // [will] - HACK: Allow cmd+a, cmd+c, cmd+v, cmd+x to go through, and treat them as the ctrl modified versions.
  771. // This allows these to work in the Scaleform chat window.
  772. if ( pEvent->m_ModifierKeyMask & (1<<eCommandKey)
  773. && ( pEvent->m_UnicodeKey == 'a'
  774. || pEvent->m_UnicodeKey == 'c'
  775. || pEvent->m_UnicodeKey == 'v'
  776. || pEvent->m_UnicodeKey == 'x' ) )
  777. {
  778. InputEvent_t event;
  779. memset( &event, 0, sizeof(event) );
  780. event.m_nTick = GetPollTick();
  781. event.m_nType = IE_KeyTyped;
  782. event.m_nData = (int)pEvent->m_UnicodeKey - 96; // Subtract 96 to give the ctrl version of this character.
  783. g_pInputSystem->PostUserEvent( event );
  784. }
  785. #endif
  786. }
  787. break;
  788. case CocoaEvent_KeyUp:
  789. {
  790. ButtonCode_t virtualCode;
  791. if ( MapCocoaVirtualKeyToButtonCode( pEvent->m_VirtualKeyCode, &virtualCode ) )
  792. {
  793. ButtonCode_t scanCode = virtualCode;
  794. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, scanCode, virtualCode );
  795. }
  796. }
  797. break;
  798. case CocoaEvent_MouseButtonDown:
  799. {
  800. int nButtonMask = pEvent->m_MouseButtonFlags;
  801. ButtonCode_t dblClickCode = BUTTON_CODE_INVALID;
  802. if ( pEvent->m_nMouseClickCount > 1 )
  803. {
  804. switch( pEvent->m_MouseButton )
  805. {
  806. default:
  807. case COCOABUTTON_LEFT:
  808. dblClickCode = MOUSE_LEFT;
  809. break;
  810. case COCOABUTTON_RIGHT:
  811. dblClickCode = MOUSE_RIGHT;
  812. break;
  813. case COCOABUTTON_MIDDLE:
  814. dblClickCode = MOUSE_MIDDLE;
  815. break;
  816. case COCOABUTTON_4:
  817. dblClickCode = MOUSE_4;
  818. break;
  819. case COCOABUTTON_5:
  820. dblClickCode = MOUSE_5;
  821. break;
  822. }
  823. }
  824. UpdateMouseButtonState( nButtonMask, dblClickCode );
  825. }
  826. break;
  827. case CocoaEvent_MouseButtonUp:
  828. {
  829. int nButtonMask = pEvent->m_MouseButtonFlags;
  830. UpdateMouseButtonState( nButtonMask );
  831. }
  832. break;
  833. case CocoaEvent_MouseMove:
  834. {
  835. UpdateMousePositionState( state, (short)pEvent->m_MousePos[0], (short)pEvent->m_MousePos[1] );
  836. InputEvent_t event;
  837. memset( &event, 0, sizeof(event) );
  838. event.m_nTick = GetPollTick();
  839. event.m_nType = IE_LocateMouseClick;
  840. event.m_nData = (short)pEvent->m_MousePos[0];
  841. event.m_nData2 = (short)pEvent->m_MousePos[1];
  842. g_pInputSystem->PostUserEvent( event );
  843. }
  844. break;
  845. case CocoaEvent_MouseScroll:
  846. {
  847. ButtonCode_t code = (short)pEvent->m_MousePos[1] > 0 ? MOUSE_WHEEL_UP : MOUSE_WHEEL_DOWN;
  848. state.m_ButtonPressedTick[ code ] = state.m_ButtonReleasedTick[ code ] = m_nLastSampleTick;
  849. PostEvent( IE_ButtonPressed, m_nLastSampleTick, code, code );
  850. PostEvent( IE_ButtonReleased, m_nLastSampleTick, code, code );
  851. #ifdef LINUX
  852. state.m_pAnalogDelta[ MOUSE_WHEEL ] = pEvent->m_MousePos[1];
  853. #else
  854. state.m_pAnalogDelta[ MOUSE_WHEEL ] = ( (short)pEvent->m_MousePos[1] ) / 10;
  855. #endif
  856. state.m_pAnalogValue[ MOUSE_WHEEL ] += state.m_pAnalogDelta[ MOUSE_WHEEL ];
  857. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_WHEEL, state.m_pAnalogValue[ MOUSE_WHEEL ], state.m_pAnalogDelta[ MOUSE_WHEEL ] );
  858. }
  859. break;
  860. case CocoaEvent_AppActivate:
  861. {
  862. InputEvent_t event;
  863. memset( &event, 0, sizeof(event) );
  864. event.m_nType = IE_FirstAppEvent + 1;
  865. event.m_nData = (bool)pEvent->m_ModifierKeyMask;
  866. g_pInputSystem->PostUserEvent( event );
  867. }
  868. break;
  869. case CocoaEvent_AppQuit:
  870. {
  871. PostEvent( IE_Quit, m_nLastSampleTick );
  872. }
  873. break;
  874. }
  875. }
  876. }
  877. }
  878. #endif // PLATFORM_OSX
  879. //-----------------------------------------------------------------------------
  880. // Polls the current input state
  881. //-----------------------------------------------------------------------------
  882. void CInputSystem::PollInputState( bool bIsInGame )
  883. {
  884. #if !defined( _CERT ) && !defined(LINUX)
  885. PollPressX360Button();
  886. #endif
  887. m_bIsPolling = true;
  888. ++m_nPollCount;
  889. // set whether in a game or not
  890. m_bIsInGame = bIsInGame;
  891. // Deals with polled input events
  892. InputState_t &queuedState = m_InputState[ INPUT_STATE_QUEUED ];
  893. CopyInputState( &m_InputState[ INPUT_STATE_CURRENT ], queuedState, true );
  894. // Sample the joystick
  895. SampleDevices();
  896. // NOTE: This happens after SampleDevices since that updates LastSampleTick
  897. // Also, I believe it's correct to post the joystick events with
  898. // the LastPollTick not updated (not 100% sure though)
  899. m_nLastPollTick = m_nLastSampleTick;
  900. #if defined( PLATFORM_OSX )
  901. PollInputState_OSX();
  902. #elif defined( LINUX )
  903. PollInputState_Linux();
  904. #elif defined( WIN32 )
  905. PollInputState_Windows();
  906. #elif defined( _PS3 )
  907. #else
  908. #error
  909. #endif
  910. // Leave the queued state up-to-date with the current
  911. CopyInputState( &queuedState, m_InputState[ INPUT_STATE_CURRENT ], false );
  912. m_bIsPolling = false;
  913. }
  914. //-----------------------------------------------------------------------------
  915. // Computes the sample tick
  916. //-----------------------------------------------------------------------------
  917. int CInputSystem::ComputeSampleTick()
  918. {
  919. // This logic will only fail if the app has been running for 49.7 days
  920. int nSampleTick;
  921. DWORD nCurrentTick = Plat_MSTime();
  922. if ( nCurrentTick >= m_StartupTimeTick )
  923. {
  924. nSampleTick = (int)( nCurrentTick - m_StartupTimeTick );
  925. }
  926. else
  927. {
  928. DWORD nDelta = (DWORD)0xFFFFFFFF - m_StartupTimeTick;
  929. nSampleTick = (int)( nCurrentTick + nDelta ) + 1;
  930. }
  931. return nSampleTick;
  932. }
  933. //-----------------------------------------------------------------------------
  934. // How many times has poll been called?
  935. //-----------------------------------------------------------------------------
  936. int CInputSystem::GetPollCount() const
  937. {
  938. return m_nPollCount;
  939. }
  940. //-----------------------------------------------------------------------------
  941. // Samples attached devices and appends events to the input queue
  942. //-----------------------------------------------------------------------------
  943. void CInputSystem::SampleDevices( void )
  944. {
  945. m_nLastSampleTick = ComputeSampleTick();
  946. static ConVarRef joystick_force_disabled( "joystick_force_disabled" );
  947. #if !defined( PLATFORM_POSIX ) || defined( _GAMECONSOLE )
  948. if ( joystick_force_disabled.IsValid() && joystick_force_disabled.GetBool() == false )
  949. {
  950. PollXDevices();
  951. }
  952. #endif
  953. if ( m_bXController == false && joystick_force_disabled.IsValid() && joystick_force_disabled.GetBool() == false )
  954. {
  955. PollJoystick();
  956. }
  957. m_bSteamController = PollSteamControllers();
  958. }
  959. //-----------------------------------------------------------------------------
  960. // Purpose: Forwards rumble info to attached devices
  961. //-----------------------------------------------------------------------------
  962. void CInputSystem::SetRumble( float fLeftMotor, float fRightMotor, int userId )
  963. {
  964. #ifndef LINUX
  965. // TODO: send force feedback to rumble-enabled joysticks
  966. SetXDeviceRumble( fLeftMotor, fRightMotor, userId );
  967. #endif
  968. }
  969. //-----------------------------------------------------------------------------
  970. // Purpose: Force an immediate stop, transmits immediately to all devices
  971. //-----------------------------------------------------------------------------
  972. void CInputSystem::StopRumble( int userId )
  973. {
  974. if ( IsPlatformWindowsPC() )
  975. {
  976. if ( userId == INVALID_USER_ID )
  977. {
  978. xdevice_t* pXDevice = &m_XDevices[0];
  979. for ( int i = 0; i < XUSER_MAX_COUNT; ++i, ++pXDevice )
  980. {
  981. if ( pXDevice->active )
  982. {
  983. pXDevice->vibration.wLeftMotorSpeed = 0;
  984. pXDevice->vibration.wRightMotorSpeed = 0;
  985. pXDevice->pendingRumbleUpdate = true;
  986. WriteToXDevice( pXDevice );
  987. }
  988. }
  989. }
  990. else
  991. {
  992. xdevice_t* pXDevice = &m_XDevices[userId];
  993. if ( pXDevice->active )
  994. {
  995. pXDevice->vibration.wLeftMotorSpeed = 0;
  996. pXDevice->vibration.wRightMotorSpeed = 0;
  997. pXDevice->pendingRumbleUpdate = true;
  998. WriteToXDevice( pXDevice );
  999. }
  1000. }
  1001. }
  1002. else
  1003. {
  1004. #ifndef LINUX
  1005. SetXDeviceRumble( 0, 0, userId );
  1006. #endif
  1007. }
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Joystick interface
  1011. //-----------------------------------------------------------------------------
  1012. int CInputSystem::GetJoystickCount() const
  1013. {
  1014. return m_nJoystickCount;
  1015. }
  1016. void CInputSystem::EnableJoystickInput( int nJoystick, bool bEnable )
  1017. {
  1018. m_JoysticksEnabled.SetFlag( 1 << nJoystick, bEnable );
  1019. }
  1020. void CInputSystem::EnableJoystickDiagonalPOV( int nJoystick, bool bEnable )
  1021. {
  1022. m_pJoystickInfo[ nJoystick ].m_bDiagonalPOVControlEnabled = bEnable;
  1023. }
  1024. //-----------------------------------------------------------------------------
  1025. // Poll current state
  1026. //-----------------------------------------------------------------------------
  1027. int CInputSystem::GetPollTick() const
  1028. {
  1029. return m_nLastPollTick;
  1030. }
  1031. bool CInputSystem::IsButtonDown( ButtonCode_t code ) const
  1032. {
  1033. return m_InputState[INPUT_STATE_CURRENT].m_ButtonState.IsBitSet( code );
  1034. }
  1035. int CInputSystem::GetAnalogValue( AnalogCode_t code ) const
  1036. {
  1037. return m_InputState[INPUT_STATE_CURRENT].m_pAnalogValue[code];
  1038. }
  1039. int CInputSystem::GetAnalogDelta( AnalogCode_t code ) const
  1040. {
  1041. return m_InputState[INPUT_STATE_CURRENT].m_pAnalogDelta[code];
  1042. }
  1043. int CInputSystem::GetButtonPressedTick( ButtonCode_t code ) const
  1044. {
  1045. return m_InputState[INPUT_STATE_CURRENT].m_ButtonPressedTick[code];
  1046. }
  1047. int CInputSystem::GetButtonReleasedTick( ButtonCode_t code ) const
  1048. {
  1049. return m_InputState[INPUT_STATE_CURRENT].m_ButtonReleasedTick[code];
  1050. }
  1051. bool CInputSystem::MotionControllerActive( ) const
  1052. {
  1053. bool isReadingMotionControllerInput = IsDeviceReadingInput( INPUT_DEVICE_HYDRA ) ||
  1054. IsDeviceReadingInput( INPUT_DEVICE_PLAYSTATION_MOVE ) ||
  1055. IsDeviceReadingInput( INPUT_DEVICE_SHARPSHOOTER );
  1056. return ( isReadingMotionControllerInput && m_bMotionControllerActive );
  1057. }
  1058. Quaternion CInputSystem::GetMotionControllerOrientation( ) const
  1059. {
  1060. return m_qMotionControllerOrientation;
  1061. }
  1062. float CInputSystem::GetMotionControllerPosX( ) const
  1063. {
  1064. return m_fMotionControllerPosX;
  1065. }
  1066. float CInputSystem::GetMotionControllerPosY( ) const
  1067. {
  1068. return m_fMotionControllerPosY;
  1069. }
  1070. int CInputSystem::GetMotionControllerDeviceStatus( ) const
  1071. {
  1072. return m_nMotionControllerStatus;
  1073. }
  1074. void CInputSystem::SetMotionControllerDeviceStatus( int nStatus )
  1075. {
  1076. m_nMotionControllerStatus = nStatus;
  1077. }
  1078. uint64 CInputSystem::GetMotionControllerDeviceStatusFlags( ) const
  1079. {
  1080. return m_nMotionControllerStatusFlags;
  1081. }
  1082. #if defined( _OSX ) || defined (LINUX)
  1083. // this is defined in xcontroller.cpp, but that file isn't included
  1084. // in posix builds
  1085. void CInputSystem::SetMotionControllerCalibrationInvalid( void )
  1086. {
  1087. }
  1088. void CInputSystem::StepMotionControllerCalibration( void )
  1089. {
  1090. }
  1091. void CInputSystem::ResetMotionControllerScreenCalibration( void )
  1092. {
  1093. }
  1094. #endif // _OSX
  1095. //-----------------------------------------------------------------------------
  1096. // Returns the input events since the last poll
  1097. //-----------------------------------------------------------------------------
  1098. int CInputSystem::GetEventCount() const
  1099. {
  1100. return m_InputState[INPUT_STATE_CURRENT].m_Events.Count();
  1101. }
  1102. const InputEvent_t* CInputSystem::GetEventData( ) const
  1103. {
  1104. return m_InputState[INPUT_STATE_CURRENT].m_Events.Base();
  1105. }
  1106. //-----------------------------------------------------------------------------
  1107. // Posts a user-defined event into the event queue; this is expected
  1108. // to be called in overridden wndprocs connected to the root panel.
  1109. //-----------------------------------------------------------------------------
  1110. void CInputSystem::PostUserEvent( const InputEvent_t &event )
  1111. {
  1112. InputState_t &state = m_InputState[ m_bIsPolling ];
  1113. state.m_Events.AddToTail( event );
  1114. state.m_bDirty = true;
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Chains the window message to the previous wndproc
  1118. //-----------------------------------------------------------------------------
  1119. inline LRESULT CInputSystem::ChainWindowMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1120. {
  1121. #if !defined( PLATFORM_POSIX )
  1122. if ( m_ChainedWndProc )
  1123. return CallWindowProc( m_ChainedWndProc, hwnd, uMsg, wParam, lParam );
  1124. #endif
  1125. // FIXME: This comment is lifted from vguimatsurface;
  1126. // may not apply in future when the system is completed.
  1127. // This means the application is driving the messages (calling our window procedure manually)
  1128. // rather than us hooking their window procedure. The engine needs to do this in order for VCR
  1129. // mode to play back properly.
  1130. return 0;
  1131. }
  1132. //-----------------------------------------------------------------------------
  1133. // Release all buttons
  1134. //-----------------------------------------------------------------------------
  1135. void CInputSystem::ReleaseAllButtons( int nFirstButton, int nLastButton )
  1136. {
  1137. // Force button up messages for all down buttons
  1138. for ( int i = nFirstButton; i <= nLastButton; ++i )
  1139. {
  1140. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, (ButtonCode_t)i, (ButtonCode_t)i );
  1141. }
  1142. }
  1143. //-----------------------------------------------------------------------------
  1144. // Zero analog state
  1145. //-----------------------------------------------------------------------------
  1146. void CInputSystem::ZeroAnalogState( int nFirstState, int nLastState )
  1147. {
  1148. InputState_t &state = m_InputState[ m_bIsPolling ];
  1149. memset( &state.m_pAnalogDelta[nFirstState], 0, ( nLastState - nFirstState + 1 ) * sizeof(int) );
  1150. memset( &state.m_pAnalogValue[nFirstState], 0, ( nLastState - nFirstState + 1 ) * sizeof(int) );
  1151. }
  1152. //-----------------------------------------------------------------------------
  1153. // Determines all mouse button presses
  1154. //-----------------------------------------------------------------------------
  1155. int CInputSystem::ButtonMaskFromMouseWParam( WPARAM wParam, ButtonCode_t code, bool bDown ) const
  1156. {
  1157. int nButtonMask = 0;
  1158. #if !defined( POSIX ) && !defined( USE_SDL)
  1159. if ( wParam & MK_LBUTTON )
  1160. {
  1161. nButtonMask |= 1;
  1162. }
  1163. if ( wParam & MK_RBUTTON )
  1164. {
  1165. nButtonMask |= 2;
  1166. }
  1167. if ( wParam & MK_MBUTTON )
  1168. {
  1169. nButtonMask |= 4;
  1170. }
  1171. if ( wParam & MS_MK_BUTTON4 )
  1172. {
  1173. nButtonMask |= 8;
  1174. }
  1175. if ( wParam & MS_MK_BUTTON5 )
  1176. {
  1177. nButtonMask |= 16;
  1178. }
  1179. #endif
  1180. #ifdef _DEBUG
  1181. if ( code != BUTTON_CODE_INVALID )
  1182. {
  1183. int nMsgMask = 1 << ( code - MOUSE_FIRST );
  1184. int nTestMask = bDown ? nMsgMask : 0;
  1185. Assert( ( nButtonMask & nMsgMask ) == nTestMask );
  1186. }
  1187. #endif
  1188. return nButtonMask;
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. // Updates the state of all mouse buttons
  1192. //-----------------------------------------------------------------------------
  1193. void CInputSystem::UpdateMouseButtonState( int nButtonMask, ButtonCode_t dblClickCode )
  1194. {
  1195. for ( int i = 0; i < 5; ++i )
  1196. {
  1197. ButtonCode_t code = (ButtonCode_t)( MOUSE_FIRST + i );
  1198. bool bDown = ( nButtonMask & ( 1 << i ) ) != 0;
  1199. if ( bDown )
  1200. {
  1201. InputEventType_t type = ( code != dblClickCode ) ? IE_ButtonPressed : IE_ButtonDoubleClicked;
  1202. PostButtonPressedEvent( type, m_nLastSampleTick, code, code );
  1203. }
  1204. else
  1205. {
  1206. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, code, code );
  1207. }
  1208. }
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Handles input messages
  1212. //-----------------------------------------------------------------------------
  1213. void CInputSystem::SetCursorPosition( int x, int y )
  1214. {
  1215. if ( !m_hAttachedHWnd )
  1216. return;
  1217. #if defined( USE_SDL )
  1218. m_pLauncherMgr->SetCursorPosition( x, y );
  1219. #elif defined( OSX )
  1220. m_pLauncherMgr->SetCursorPosition( x, y );
  1221. #elif defined( WIN32 )
  1222. POINT pt;
  1223. pt.x = x; pt.y = y;
  1224. ClientToScreen( (HWND)m_hAttachedHWnd, &pt );
  1225. SetCursorPos( pt.x, pt.y );
  1226. #elif defined( PLATFORM_PS3 )
  1227. POINT pt;
  1228. pt.x = x; pt.y = y;
  1229. SetCursorPos( pt.x, pt.y );
  1230. #else
  1231. #error
  1232. #endif
  1233. InputState_t &state = m_InputState[ m_bIsPolling ];
  1234. bool bXChanged = ( state.m_pAnalogValue[ MOUSE_X ] != x );
  1235. bool bYChanged = ( state.m_pAnalogValue[ MOUSE_Y ] != y );
  1236. state.m_pAnalogValue[ MOUSE_X ] = x;
  1237. state.m_pAnalogValue[ MOUSE_Y ] = y;
  1238. state.m_pAnalogDelta[ MOUSE_X ] = 0;
  1239. state.m_pAnalogDelta[ MOUSE_Y ] = 0;
  1240. if ( bXChanged )
  1241. {
  1242. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_X, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogDelta[ MOUSE_X ] );
  1243. }
  1244. if ( bYChanged )
  1245. {
  1246. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_Y, state.m_pAnalogValue[ MOUSE_Y ], state.m_pAnalogDelta[ MOUSE_Y ] );
  1247. }
  1248. if ( bXChanged || bYChanged )
  1249. {
  1250. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_XY, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogValue[ MOUSE_Y ] );
  1251. }
  1252. }
  1253. void CInputSystem::GetCursorPosition( int *pX, int *pY )
  1254. {
  1255. if ( !m_hAttachedHWnd )
  1256. {
  1257. *pX = *pY = 0;
  1258. return;
  1259. }
  1260. #if defined( USE_SDL )
  1261. *pX = m_InputState[INPUT_STATE_CURRENT].m_pAnalogValue[MOUSE_X];
  1262. *pY = m_InputState[INPUT_STATE_CURRENT].m_pAnalogValue[MOUSE_Y];
  1263. #elif defined( PLATFORM_OSX )
  1264. if ( m_bCursorVisible )
  1265. {
  1266. CGEventRef event = CGEventCreate( NULL );
  1267. CGPoint pnt = CGEventGetLocation( event );
  1268. // [will] - QuickDraw functions removed in 10.7, so using using CocoaMgr for window info instead.
  1269. unsigned int displayWidth, displayHeight;
  1270. m_pLauncherMgr->DisplayedSize( displayWidth, displayHeight );
  1271. *pX = pnt.x;
  1272. *pY = pnt.y;
  1273. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1274. int rx, ry, width, height;
  1275. pRenderContext->GetViewport( rx, ry, width, height );
  1276. int windowHeight = (int)displayWidth;
  1277. int windowWidth = (int)displayHeight;
  1278. if ( width != windowWidth || abs( height - windowHeight ) > 22 )
  1279. {
  1280. // scale the x/y back into the co-ords of the back buffer, not the scaled up window
  1281. //DevMsg( "Mouse x:%d y:%d %d %d %d %d\n", x, y, width, windowWidth, height, abs( height - windowHeight ) );
  1282. *pX = *pX * (float)width/windowWidth;
  1283. *pY = *pY * (float)height/windowHeight;
  1284. }
  1285. CFRelease( event );
  1286. }
  1287. else
  1288. {
  1289. // cursor is invisible, just say the center of the screen
  1290. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1291. int rx, ry, width, height;
  1292. pRenderContext->GetViewport( rx, ry, width, height );
  1293. *pX = width/2;
  1294. *pY = height/2;
  1295. }
  1296. #elif !defined( PLATFORM_POSIX )
  1297. POINT pt;
  1298. ::GetCursorPos( &pt );
  1299. ScreenToClient((HWND)m_hAttachedHWnd, &pt);
  1300. *pX = pt.x; *pY = pt.y;
  1301. #endif
  1302. }
  1303. void CInputSystem::SetMouseCursorVisible( bool bVisible )
  1304. {
  1305. m_bCursorVisible = bVisible;
  1306. }
  1307. void CInputSystem::UpdateMousePositionState( InputState_t &state, short x, short y )
  1308. {
  1309. int nOldX = state.m_pAnalogValue[ MOUSE_X ];
  1310. int nOldY = state.m_pAnalogValue[ MOUSE_Y ];
  1311. state.m_pAnalogValue[ MOUSE_X ] = x;
  1312. state.m_pAnalogValue[ MOUSE_Y ] = y;
  1313. state.m_pAnalogDelta[ MOUSE_X ] = state.m_pAnalogValue[ MOUSE_X ] - nOldX;
  1314. state.m_pAnalogDelta[ MOUSE_Y ] = state.m_pAnalogValue[ MOUSE_Y ] - nOldY;
  1315. if ( state.m_pAnalogDelta[ MOUSE_X ] != 0 )
  1316. {
  1317. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_X, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogDelta[ MOUSE_X ] );
  1318. }
  1319. if ( state.m_pAnalogDelta[ MOUSE_Y ] != 0 )
  1320. {
  1321. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_Y, state.m_pAnalogValue[ MOUSE_Y ], state.m_pAnalogDelta[ MOUSE_Y ] );
  1322. }
  1323. if ( state.m_pAnalogDelta[ MOUSE_X ] != 0 || state.m_pAnalogDelta[ MOUSE_Y ] != 0 )
  1324. {
  1325. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_XY, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogValue[ MOUSE_Y ] );
  1326. }
  1327. }
  1328. #ifdef PLATFORM_WINDOWS
  1329. //-----------------------------------------------------------------------------
  1330. // Generates LocateMouseClick messages
  1331. //-----------------------------------------------------------------------------
  1332. void CInputSystem::LocateMouseClick( LPARAM lParam )
  1333. {
  1334. if ( ShouldGenerateUIEvents() )
  1335. {
  1336. PostEvent( IE_LocateMouseClick, m_nLastSampleTick, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1337. }
  1338. }
  1339. //-----------------------------------------------------------------------------
  1340. // Handles input messages
  1341. //-----------------------------------------------------------------------------
  1342. LRESULT CInputSystem::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1343. {
  1344. #if !defined( POSIX ) && !defined( USE_SDL )
  1345. if ( !m_bEnabled )
  1346. return ChainWindowMessage( hwnd, uMsg, wParam, lParam );
  1347. if ( ShouldGenerateUIEvents() && ( hwnd != m_hLastIMEHWnd ) )
  1348. {
  1349. m_hLastIMEHWnd = hwnd;
  1350. PostEvent( IE_IMESetWindow, m_nLastSampleTick, (intp)hwnd );
  1351. }
  1352. // Allow ActivateApp messages to get through so we know when to reset input state
  1353. if ( ( hwnd != m_hAttachedHWnd ) && ( uMsg != WM_ACTIVATEAPP ) )
  1354. return ChainWindowMessage( hwnd, uMsg, wParam, lParam );
  1355. InputState_t &state = m_InputState[ m_bIsPolling ];
  1356. switch( uMsg )
  1357. {
  1358. case WM_ACTIVATEAPP:
  1359. if ( hwnd == m_hAttachedHWnd )
  1360. {
  1361. bool bActivated = ( wParam == 1 );
  1362. if ( !bActivated )
  1363. {
  1364. ResetInputState();
  1365. }
  1366. }
  1367. break;
  1368. case WM_CLOSE:
  1369. // Handle close messages
  1370. PostEvent( IE_Close, m_nLastSampleTick );
  1371. // don't Run default message pump, as that destroys the window
  1372. return 0;
  1373. case WM_SETCURSOR:
  1374. if ( ShouldGenerateUIEvents() )
  1375. {
  1376. PostEvent( IE_SetCursor, m_nLastSampleTick );
  1377. }
  1378. break;
  1379. case WM_SIZE:
  1380. {
  1381. int nWidth = LOWORD( lParam );
  1382. int nHeight = HIWORD( lParam );
  1383. bool bMinimized = ( wParam == SIZE_MINIMIZED ) || IsIconic( hwnd );
  1384. if ( bMinimized )
  1385. {
  1386. nWidth = nHeight = 0;
  1387. }
  1388. PostEvent( IE_WindowSizeChanged, m_nLastSampleTick, nWidth, nHeight, bMinimized );
  1389. }
  1390. break;
  1391. case WM_LBUTTONDOWN:
  1392. {
  1393. LocateMouseClick( lParam );
  1394. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_LEFT, true );
  1395. ETWMouseDown( 0, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1396. UpdateMouseButtonState( nButtonMask );
  1397. }
  1398. break;
  1399. case WM_LBUTTONUP:
  1400. {
  1401. LocateMouseClick( lParam );
  1402. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_LEFT, false );
  1403. ETWMouseUp( 0, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1404. UpdateMouseButtonState( nButtonMask );
  1405. }
  1406. break;
  1407. case WM_RBUTTONDOWN:
  1408. {
  1409. LocateMouseClick( lParam );
  1410. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_RIGHT, true );
  1411. ETWMouseDown( 2, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1412. UpdateMouseButtonState( nButtonMask );
  1413. }
  1414. break;
  1415. case WM_RBUTTONUP:
  1416. {
  1417. LocateMouseClick( lParam );
  1418. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_RIGHT, false );
  1419. ETWMouseUp( 2, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1420. UpdateMouseButtonState( nButtonMask );
  1421. }
  1422. break;
  1423. case WM_MBUTTONDOWN:
  1424. {
  1425. LocateMouseClick( lParam );
  1426. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_MIDDLE, true );
  1427. ETWMouseDown( 1, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1428. UpdateMouseButtonState( nButtonMask );
  1429. }
  1430. break;
  1431. case WM_MBUTTONUP:
  1432. {
  1433. LocateMouseClick( lParam );
  1434. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_MIDDLE, false );
  1435. ETWMouseUp( 1, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1436. UpdateMouseButtonState( nButtonMask );
  1437. }
  1438. break;
  1439. case MS_WM_XBUTTONDOWN:
  1440. {
  1441. LocateMouseClick( lParam );
  1442. ButtonCode_t code = ( HIWORD( wParam ) == 1 ) ? MOUSE_4 : MOUSE_5;
  1443. int nButtonMask = ButtonMaskFromMouseWParam( wParam, code, true );
  1444. UpdateMouseButtonState( nButtonMask );
  1445. // Windows docs say the XBUTTON messages we should return true from
  1446. return TRUE;
  1447. }
  1448. break;
  1449. case MS_WM_XBUTTONUP:
  1450. {
  1451. LocateMouseClick( lParam );
  1452. ButtonCode_t code = ( HIWORD( wParam ) == 1 ) ? MOUSE_4 : MOUSE_5;
  1453. int nButtonMask = ButtonMaskFromMouseWParam( wParam, code, false );
  1454. UpdateMouseButtonState( nButtonMask );
  1455. // Windows docs say the XBUTTON messages we should return true from
  1456. return TRUE;
  1457. }
  1458. break;
  1459. case WM_LBUTTONDBLCLK:
  1460. {
  1461. LocateMouseClick( lParam );
  1462. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_LEFT, true );
  1463. ETWMouseDown( 0, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1464. UpdateMouseButtonState( nButtonMask, MOUSE_LEFT );
  1465. }
  1466. break;
  1467. case WM_RBUTTONDBLCLK:
  1468. {
  1469. LocateMouseClick( lParam );
  1470. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_RIGHT, true );
  1471. ETWMouseDown( 2, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1472. UpdateMouseButtonState( nButtonMask, MOUSE_RIGHT );
  1473. }
  1474. break;
  1475. case WM_MBUTTONDBLCLK:
  1476. {
  1477. LocateMouseClick( lParam );
  1478. int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_MIDDLE, true );
  1479. ETWMouseDown( 1, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1480. UpdateMouseButtonState( nButtonMask, MOUSE_MIDDLE );
  1481. }
  1482. break;
  1483. case MS_WM_XBUTTONDBLCLK:
  1484. {
  1485. LocateMouseClick( lParam );
  1486. ButtonCode_t code = ( HIWORD( wParam ) == 1 ) ? MOUSE_4 : MOUSE_5;
  1487. int nButtonMask = ButtonMaskFromMouseWParam( wParam, code, true );
  1488. UpdateMouseButtonState( nButtonMask, code );
  1489. // Windows docs say the XBUTTON messages we should return true from
  1490. return TRUE;
  1491. }
  1492. break;
  1493. case WM_KEYDOWN:
  1494. case WM_SYSKEYDOWN:
  1495. {
  1496. // Suppress key repeats
  1497. if ( !( lParam & ( 1<<30 ) ) )
  1498. {
  1499. // NOTE: These two can be unequal! For example, keypad enter
  1500. // which returns KEY_ENTER from virtual keys, and KEY_PAD_ENTER from scan codes
  1501. // Since things like vgui care about virtual keys; we're going to
  1502. // put both scan codes in the input message
  1503. ButtonCode_t virtualCode = ButtonCode_VirtualKeyToButtonCode( wParam );
  1504. ButtonCode_t scanCode = ButtonCode_ScanCodeToButtonCode( lParam );
  1505. PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, scanCode, virtualCode );
  1506. // Post ETW events describing key presses to help correlate input events to performance
  1507. // problems in the game.
  1508. ETWKeyDown( scanCode, virtualCode, ButtonCodeToString( virtualCode ) );
  1509. // Deal with toggles
  1510. if ( scanCode == KEY_CAPSLOCK || scanCode == KEY_SCROLLLOCK || scanCode == KEY_NUMLOCK )
  1511. {
  1512. int nVirtualKey;
  1513. ButtonCode_t toggleCode;
  1514. switch( scanCode )
  1515. {
  1516. default: case KEY_CAPSLOCK: nVirtualKey = VK_CAPITAL; toggleCode = KEY_CAPSLOCKTOGGLE; break;
  1517. case KEY_SCROLLLOCK: nVirtualKey = VK_SCROLL; toggleCode = KEY_SCROLLLOCKTOGGLE; break;
  1518. case KEY_NUMLOCK: nVirtualKey = VK_NUMLOCK; toggleCode = KEY_NUMLOCKTOGGLE; break;
  1519. };
  1520. SHORT wState = GetKeyState( nVirtualKey );
  1521. bool bToggleState = ( wState & 0x1 ) != 0;
  1522. PostButtonPressedEvent( bToggleState ? IE_ButtonPressed : IE_ButtonReleased, m_nLastSampleTick, toggleCode, toggleCode );
  1523. }
  1524. }
  1525. if ( ShouldGenerateUIEvents() )
  1526. {
  1527. ButtonCode_t virtualCode = ButtonCode_VirtualKeyToButtonCode( wParam );
  1528. int nKeyRepeat = LOWORD( lParam );
  1529. for ( int i = 0; i < nKeyRepeat; ++i )
  1530. {
  1531. PostEvent( IE_KeyCodeTyped, m_nLastSampleTick, virtualCode );
  1532. }
  1533. }
  1534. }
  1535. break;
  1536. case WM_KEYUP:
  1537. case WM_SYSKEYUP:
  1538. {
  1539. // Don't handle key ups if the key's already up. This can happen when we alt-tab back to the engine.
  1540. ButtonCode_t virtualCode = ButtonCode_VirtualKeyToButtonCode( wParam );
  1541. ButtonCode_t scanCode = ButtonCode_ScanCodeToButtonCode( lParam );
  1542. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, scanCode, virtualCode );
  1543. }
  1544. break;
  1545. case WM_MOUSEWHEEL:
  1546. {
  1547. ButtonCode_t code = (short)HIWORD( wParam ) > 0 ? MOUSE_WHEEL_UP : MOUSE_WHEEL_DOWN;
  1548. state.m_ButtonPressedTick[ code ] = state.m_ButtonReleasedTick[ code ] = m_nLastSampleTick;
  1549. PostEvent( IE_ButtonPressed, m_nLastSampleTick, code, code );
  1550. PostEvent( IE_ButtonReleased, m_nLastSampleTick, code, code );
  1551. state.m_pAnalogDelta[ MOUSE_WHEEL ] = ( (short)HIWORD(wParam) ) / WHEEL_DELTA;
  1552. state.m_pAnalogValue[ MOUSE_WHEEL ] += state.m_pAnalogDelta[ MOUSE_WHEEL ];
  1553. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_WHEEL, state.m_pAnalogValue[ MOUSE_WHEEL ], state.m_pAnalogDelta[ MOUSE_WHEEL ] );
  1554. }
  1555. break;
  1556. case WM_MOUSEMOVE:
  1557. {
  1558. UpdateMousePositionState( state, (short)LOWORD(lParam), (short)HIWORD(lParam) );
  1559. int nButtonMask = ButtonMaskFromMouseWParam( wParam );
  1560. UpdateMouseButtonState( nButtonMask );
  1561. }
  1562. break;
  1563. #if defined ( WIN32 ) && !defined ( _X360 )
  1564. case WM_INPUT:
  1565. {
  1566. if ( m_bRawInputSupported )
  1567. {
  1568. UINT dwSize = sizeof( RAWINPUT );
  1569. static BYTE lpb[ sizeof( RAWINPUT ) ];
  1570. pfnGetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
  1571. RAWINPUT* raw = (RAWINPUT*)lpb;
  1572. if (raw->header.dwType == RIM_TYPEMOUSE)
  1573. {
  1574. m_mouseRawAccumX += raw->data.mouse.lLastX;
  1575. m_mouseRawAccumY += raw->data.mouse.lLastY;
  1576. }
  1577. }
  1578. }
  1579. break;
  1580. #endif
  1581. case WM_SYSCHAR:
  1582. case WM_CHAR:
  1583. if ( ShouldGenerateUIEvents() && !m_bIMEComposing )
  1584. {
  1585. PostEvent( IE_KeyTyped, m_nLastSampleTick, (wchar_t)wParam );
  1586. }
  1587. break;
  1588. case WM_INPUTLANGCHANGE:
  1589. // Note that this is passed to IME managers even if the IME is currently
  1590. // disallowed so that IMEs are still aware of the current language
  1591. // in case they are allowed in the future.
  1592. #if defined( INCLUDE_SCALEFORM )
  1593. if ( g_pScaleformUI )
  1594. {
  1595. g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam );
  1596. }
  1597. #endif
  1598. if ( ShouldGenerateUIEvents() )
  1599. {
  1600. PostEvent( IE_InputLanguageChanged, m_nLastSampleTick );
  1601. }
  1602. break;
  1603. case WM_IME_KEYDOWN:
  1604. #if defined( INCLUDE_SCALEFORM )
  1605. if ( g_pScaleformUI && g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam ) )
  1606. return 0;
  1607. #endif
  1608. break;
  1609. case WM_IME_STARTCOMPOSITION:
  1610. #if defined( INCLUDE_SCALEFORM )
  1611. if ( g_pScaleformUI && g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam ) )
  1612. {
  1613. m_bIMEComposing = true;
  1614. return 0;
  1615. }
  1616. #endif
  1617. if ( ShouldGenerateUIEvents() )
  1618. {
  1619. m_bIMEComposing = true;
  1620. PostEvent( IE_IMEStartComposition, m_nLastSampleTick );
  1621. return TRUE;
  1622. }
  1623. break;
  1624. case WM_IME_COMPOSITION:
  1625. #if defined( INCLUDE_SCALEFORM )
  1626. if ( g_pScaleformUI && g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam ) )
  1627. return 0;
  1628. #endif
  1629. if ( ShouldGenerateUIEvents() )
  1630. {
  1631. PostEvent( IE_IMEComposition, m_nLastSampleTick, (int)lParam );
  1632. return TRUE;
  1633. }
  1634. break;
  1635. case WM_IME_ENDCOMPOSITION:
  1636. #if defined( INCLUDE_SCALEFORM )
  1637. if ( g_pScaleformUI && g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam ) )
  1638. {
  1639. m_bIMEComposing = false;
  1640. return 0;
  1641. }
  1642. #endif
  1643. if ( ShouldGenerateUIEvents() )
  1644. {
  1645. m_bIMEComposing = false;
  1646. PostEvent( IE_IMEEndComposition, m_nLastSampleTick );
  1647. return TRUE;
  1648. }
  1649. break;
  1650. case WM_IME_NOTIFY:
  1651. #if defined( INCLUDE_SCALEFORM )
  1652. if ( g_pScaleformUI && g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam ) )
  1653. return 0;
  1654. #endif
  1655. if ( ShouldGenerateUIEvents() )
  1656. {
  1657. switch (wParam)
  1658. {
  1659. default:
  1660. break;
  1661. case 14: // Chinese Traditional IMN_PRIVATE...
  1662. break;
  1663. case IMN_OPENCANDIDATE:
  1664. PostEvent( IE_IMEShowCandidates, m_nLastSampleTick );
  1665. return 1;
  1666. case IMN_CHANGECANDIDATE:
  1667. PostEvent( IE_IMEChangeCandidates, m_nLastSampleTick );
  1668. return 0;
  1669. case IMN_CLOSECANDIDATE:
  1670. PostEvent( IE_IMECloseCandidates, m_nLastSampleTick );
  1671. break;
  1672. // To detect the change of IME mode, or the toggling of Japanese IME
  1673. case IMN_SETCONVERSIONMODE:
  1674. case IMN_SETSENTENCEMODE:
  1675. case IMN_SETOPENSTATUS:
  1676. PostEvent( IE_IMERecomputeModes, m_nLastSampleTick );
  1677. if ( wParam == IMN_SETOPENSTATUS )
  1678. return 0;
  1679. break;
  1680. case IMN_CLOSESTATUSWINDOW:
  1681. case IMN_GUIDELINE:
  1682. case IMN_OPENSTATUSWINDOW:
  1683. case IMN_SETCANDIDATEPOS:
  1684. case IMN_SETCOMPOSITIONFONT:
  1685. case IMN_SETCOMPOSITIONWINDOW:
  1686. case IMN_SETSTATUSWINDOWPOS:
  1687. break;
  1688. }
  1689. }
  1690. break;
  1691. case WM_IME_CHAR:
  1692. #if defined( INCLUDE_SCALEFORM )
  1693. if ( g_pScaleformUI && g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam ) )
  1694. return 0;
  1695. #endif
  1696. if ( ShouldGenerateUIEvents() )
  1697. {
  1698. // We need to process this message so that the IME doesn't double
  1699. // convert the unicode IME characters into garbage characters and post
  1700. // them to our window... (get ? marks after text entry ).
  1701. return 0;
  1702. }
  1703. break;
  1704. case WM_IME_SETCONTEXT:
  1705. #if defined( INCLUDE_SCALEFORM )
  1706. if ( g_pScaleformUI )
  1707. {
  1708. g_pScaleformUI->HandleIMEEvent( (size_t)hwnd, uMsg, wParam, lParam );
  1709. lParam = 0;
  1710. }
  1711. else
  1712. #endif
  1713. if ( ShouldGenerateUIEvents() )
  1714. {
  1715. // We draw all IME windows ourselves
  1716. lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
  1717. lParam &= ~ISC_SHOWUIGUIDELINE;
  1718. lParam &= ~ISC_SHOWUIALLCANDIDATEWINDOW;
  1719. }
  1720. break;
  1721. }
  1722. // Can't put this in the case statement, it's not constant
  1723. if ( IsPC() && ( uMsg == m_uiMouseWheel ) )
  1724. {
  1725. ButtonCode_t code = ( ( int )wParam ) > 0 ? MOUSE_WHEEL_UP : MOUSE_WHEEL_DOWN;
  1726. state.m_ButtonPressedTick[ code ] = state.m_ButtonReleasedTick[ code ] = m_nLastSampleTick;
  1727. PostEvent( IE_ButtonPressed, m_nLastSampleTick, code, code );
  1728. PostEvent( IE_ButtonReleased, m_nLastSampleTick, code, code );
  1729. state.m_pAnalogDelta[ MOUSE_WHEEL ] = ( ( int )wParam ) / WHEEL_DELTA;
  1730. state.m_pAnalogValue[ MOUSE_WHEEL ] += state.m_pAnalogDelta[ MOUSE_WHEEL ];
  1731. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_WHEEL, state.m_pAnalogValue[ MOUSE_WHEEL ], state.m_pAnalogDelta[ MOUSE_WHEEL ] );
  1732. }
  1733. return ChainWindowMessage( hwnd, uMsg, wParam, lParam );
  1734. #else
  1735. return 0;
  1736. #endif
  1737. }
  1738. #endif
  1739. //-----------------------------------------------------------------------------
  1740. // Initializes, shuts down cursors
  1741. //-----------------------------------------------------------------------------
  1742. void CInputSystem::InitCursors()
  1743. {
  1744. #ifdef PLATFORM_WINDOWS
  1745. // load up all default cursors
  1746. memset( m_pDefaultCursors, 0, sizeof(m_pDefaultCursors) );
  1747. m_pDefaultCursors[INPUT_CURSOR_NONE] = INPUT_CURSOR_HANDLE_INVALID;
  1748. m_pDefaultCursors[INPUT_CURSOR_ARROW] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_NORMAL);
  1749. m_pDefaultCursors[INPUT_CURSOR_IBEAM] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_IBEAM);
  1750. m_pDefaultCursors[INPUT_CURSOR_HOURGLASS] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_WAIT);
  1751. m_pDefaultCursors[INPUT_CURSOR_CROSSHAIR] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_CROSS);
  1752. m_pDefaultCursors[INPUT_CURSOR_WAITARROW] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)32650);
  1753. m_pDefaultCursors[INPUT_CURSOR_UP] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_UP);
  1754. m_pDefaultCursors[INPUT_CURSOR_SIZE_NW_SE] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_SIZENWSE);
  1755. m_pDefaultCursors[INPUT_CURSOR_SIZE_NE_SW] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_SIZENESW);
  1756. m_pDefaultCursors[INPUT_CURSOR_SIZE_W_E] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_SIZEWE);
  1757. m_pDefaultCursors[INPUT_CURSOR_SIZE_N_S] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_SIZENS);
  1758. m_pDefaultCursors[INPUT_CURSOR_SIZE_ALL] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_SIZEALL);
  1759. m_pDefaultCursors[INPUT_CURSOR_NO] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)OCR_NO);
  1760. m_pDefaultCursors[INPUT_CURSOR_HAND] = (InputCursorHandle_t)LoadCursor(NULL, (LPCTSTR)32649);
  1761. #endif
  1762. }
  1763. void CInputSystem::ShutdownCursors()
  1764. {
  1765. #ifdef PLATFORM_WINDOWS
  1766. int nCount = m_UserCursors.GetNumStrings();
  1767. for ( int i = 0; i < nCount; ++i )
  1768. {
  1769. ::DestroyCursor( (HCURSOR)m_UserCursors[ i ] );
  1770. }
  1771. m_UserCursors.Purge();
  1772. for ( int i = 0; i < ARRAYSIZE( m_pDefaultCursors ); ++i )
  1773. {
  1774. if ( m_pDefaultCursors[i] != INPUT_CURSOR_HANDLE_INVALID )
  1775. {
  1776. ::DestroyCursor( (HCURSOR)m_pDefaultCursors[ i ] );
  1777. m_pDefaultCursors[ i ] = INPUT_CURSOR_HANDLE_INVALID;
  1778. }
  1779. }
  1780. #endif
  1781. }
  1782. //-----------------------------------------------------------------------------
  1783. // Gets the cursor
  1784. //-----------------------------------------------------------------------------
  1785. InputCursorHandle_t CInputSystem::GetStandardCursor( InputStandardCursor_t id )
  1786. {
  1787. return m_pDefaultCursors[id];
  1788. }
  1789. InputCursorHandle_t CInputSystem::LoadCursorFromFile( const char *pFileName, const char *pPathID )
  1790. {
  1791. if ( !g_pFullFileSystem )
  1792. return INPUT_CURSOR_HANDLE_INVALID;
  1793. char fn[ 512 ];
  1794. Q_strncpy( fn, pFileName, sizeof( fn ) );
  1795. Q_strlower( fn );
  1796. Q_FixSlashes( fn );
  1797. UtlSymId_t nCursorIndex = m_UserCursors.Find( fn );
  1798. if ( nCursorIndex != m_UserCursors.InvalidIndex() )
  1799. return m_UserCursors[ nCursorIndex ];
  1800. g_pFullFileSystem->GetLocalCopy( fn );
  1801. #ifdef PLATFORM_WINDOWS
  1802. char fullpath[ 512 ];
  1803. g_pFullFileSystem->RelativePathToFullPath( fn, pPathID, fullpath, sizeof( fullpath ) );
  1804. HCURSOR newCursor = (HCURSOR)::LoadCursorFromFile( fullpath );
  1805. m_UserCursors[ fn ] = (InputCursorHandle_t)newCursor;
  1806. return (InputCursorHandle_t)newCursor;
  1807. #endif
  1808. return 0;
  1809. }
  1810. void CInputSystem::SetCursorIcon( InputCursorHandle_t hCursor )
  1811. {
  1812. #ifdef PLATFORM_WINDOWS
  1813. m_hCursor = hCursor;
  1814. HCURSOR hWindowsCursor = (HCURSOR)hCursor;
  1815. ::SetCursor( hWindowsCursor );
  1816. #endif
  1817. }
  1818. void CInputSystem::ResetCursorIcon()
  1819. {
  1820. SetCursorIcon( m_hCursor );
  1821. }
  1822. void CInputSystem::EnableMouseCapture( PlatWindow_t hWnd )
  1823. {
  1824. #ifdef PLATFORM_WINDOWS
  1825. if ( m_hCurrentCaptureWnd == hWnd )
  1826. return;
  1827. // Determine if we're the foreground window. If not, force release of the mouse. Otherwise, we can capture the mouse
  1828. // while we're in the background and then we never get WM_ACTIVATE messages when trying to click on the app. This
  1829. // causes the app to react like it has mouse focus (firing weapons, etc) but doesn't actually come to the foreground
  1830. // and doesn't accept keyboard input.
  1831. //
  1832. // We're using GetForegroundWindow here, but we really want to ask engine or game if they're the ActiveApp.
  1833. bool bActiveWindow = true;
  1834. #if !defined( _GAMECONSOLE )
  1835. HWND hInputWnd = reinterpret_cast< HWND >( hWnd );
  1836. bActiveWindow = ( hInputWnd == ::GetForegroundWindow() );
  1837. #else
  1838. HWND hInputWnd = reinterpret_cast< HWND >( m_hCurrentCaptureWnd );
  1839. #endif
  1840. if ( m_hCurrentCaptureWnd != PLAT_WINDOW_INVALID || !bActiveWindow )
  1841. {
  1842. ::ReleaseCapture();
  1843. }
  1844. m_hCurrentCaptureWnd = hWnd;
  1845. if ( m_hCurrentCaptureWnd != PLAT_WINDOW_INVALID && bActiveWindow )
  1846. {
  1847. ::SetCapture( hInputWnd );
  1848. }
  1849. #endif
  1850. }
  1851. void CInputSystem::GetRawMouseAccumulators( int& accumX, int& accumY )
  1852. {
  1853. #if defined( USE_SDL )
  1854. if ( m_pLauncherMgr )
  1855. {
  1856. m_pLauncherMgr->GetMouseDelta( accumX, accumY, false );
  1857. }
  1858. #else
  1859. accumX = m_mouseRawAccumX;
  1860. accumY = m_mouseRawAccumY;
  1861. m_mouseRawAccumX = m_mouseRawAccumY = 0;
  1862. #endif
  1863. }
  1864. void CInputSystem::DisableMouseCapture()
  1865. {
  1866. #ifdef PLATFORM_WINDOWS
  1867. EnableMouseCapture( PLAT_WINDOW_INVALID );
  1868. #endif
  1869. }
  1870. // ===================================================================
  1871. // If we add another support for another input device, we need to
  1872. // update the platform assignments below to reflect it. From here,
  1873. // pretty much everything else that uses these interfaces will work
  1874. // unchanged (obviously UI and device code needs to be added)
  1875. // Also: Add name to GetInputDeviceNameUI/Internal() in
  1876. // PlatformInputDevice.cpp
  1877. // ===================================================================
  1878. void CInputSystem::InitPlatfromInputDeviceInfo( void )
  1879. {
  1880. PlatformInputDevice::InitPlatfromInputDeviceInfo();
  1881. // Set the platform for which this code/client is compiled on and
  1882. // the input devices that are assumed to be already installed (as
  1883. // opposed to being queried by the inputsystem)
  1884. #if defined( PLATFORM_WINDOWS_PC )
  1885. m_currentlyConnectedInputDevices = INPUT_DEVICE_KEYBOARD_MOUSE;
  1886. #elif defined( PLATFORM_OSX )
  1887. m_currentlyConnectedInputDevices = INPUT_DEVICE_KEYBOARD_MOUSE;
  1888. #elif defined( PLATFORM_LINUX )
  1889. m_currentlyConnectedInputDevices = INPUT_DEVICE_KEYBOARD_MOUSE;
  1890. #elif defined( PLATFORM_X360 )
  1891. m_currentlyConnectedInputDevices = INPUT_DEVICE_GAMEPAD;
  1892. #elif defined( PLATFORM_PS3 )
  1893. m_currentlyConnectedInputDevices = INPUT_DEVICE_NONE;
  1894. #else
  1895. m_currentlyConnectedInputDevices = INPUT_DEVICE_NONE;
  1896. #endif
  1897. ResetCurrentInputDevice();
  1898. m_setCurrentInputDeviceOnNextButtonPress = false;
  1899. }
  1900. void CInputSystem::ResetCurrentInputDevice( void )
  1901. {
  1902. if ( m_currentInputDevice == INPUT_DEVICE_STEAM_CONTROLLER )
  1903. {
  1904. // Disable resetting away from the steam controller if it's being used.
  1905. return;
  1906. }
  1907. #if defined( PLATFORM_WINDOWS_PC )
  1908. m_currentInputDevice = INPUT_DEVICE_KEYBOARD_MOUSE;
  1909. #elif defined( PLATFORM_OSX )
  1910. m_currentInputDevice = INPUT_DEVICE_KEYBOARD_MOUSE;
  1911. #elif defined( PLATFORM_LINUX )
  1912. m_currentInputDevice = INPUT_DEVICE_KEYBOARD_MOUSE;
  1913. #elif defined( PLATFORM_X360 )
  1914. m_currentInputDevice = INPUT_DEVICE_GAMEPAD;
  1915. #elif defined( PLATFORM_PS3 )
  1916. m_currentInputDevice = INPUT_DEVICE_NONE;
  1917. #else
  1918. m_currentInputDevice = INPUT_DEVICE_NONE;
  1919. #endif
  1920. }
  1921. InputDevice_t CInputSystem::GetConnectedInputDevices( void )
  1922. {
  1923. return m_currentlyConnectedInputDevices;
  1924. }
  1925. bool CInputSystem::IsInputDeviceConnected( InputDevice_t device )
  1926. {
  1927. if ( countBits( device ) != 1 || ( device & PlatformInputDevice::s_AllInputDevices ) != device )
  1928. {
  1929. AssertMsg( false, "invalid input device" );
  1930. return false;
  1931. }
  1932. return ( ( m_currentlyConnectedInputDevices & device ) == device );
  1933. }
  1934. void CInputSystem::SetInputDeviceConnected( InputDevice_t device, bool connected )
  1935. {
  1936. if ( ( countBits( device ) != 1 ) || ( device & PlatformInputDevice::s_validPlatformInputDevices[PlatformInputDevice::s_LocalInputPlatform] ) != device )
  1937. {
  1938. AssertMsg( false, "invalid input device" );
  1939. return;
  1940. }
  1941. if ( connected )
  1942. {
  1943. // Message if device already connected?
  1944. m_currentlyConnectedInputDevices = m_currentlyConnectedInputDevices | device;
  1945. }
  1946. else
  1947. {
  1948. // Message if device not currently connected?
  1949. m_currentlyConnectedInputDevices = m_currentlyConnectedInputDevices & (~device);
  1950. }
  1951. }
  1952. InputDevice_t CInputSystem::IsOnlySingleDeviceConnected( void )
  1953. {
  1954. int32 mask = 1;
  1955. // nav controller doesn't need to be considered a seperate device.
  1956. int32 connectedMask = m_currentlyConnectedInputDevices & (~INPUT_DEVICE_MOVE_NAV_CONTROLLER);
  1957. if ( IsInputDeviceConnected( INPUT_DEVICE_SHARPSHOOTER ) )
  1958. {
  1959. connectedMask = m_currentlyConnectedInputDevices & ( ~INPUT_DEVICE_PLAYSTATION_MOVE );
  1960. }
  1961. // [dkorus] loop through a mask that represents each possible device.
  1962. // if one matches our connected mask exactly, we have only that device connected
  1963. while( mask <= INPUT_DEVICE_MAX )
  1964. {
  1965. if ( connectedMask == mask )
  1966. return (InputDevice_t) connectedMask;
  1967. mask = mask << 1;
  1968. }
  1969. return INPUT_DEVICE_NONE;
  1970. }
  1971. bool CInputSystem::IsDeviceReadingInput( InputDevice_t device ) const
  1972. {
  1973. #ifndef _GAMECONSOLE
  1974. return true;
  1975. #endif
  1976. #if !defined( _CERT )
  1977. // [dkorus] test code for the device selection
  1978. int forceSelected = dev_force_selected_device.GetInt();
  1979. if ( forceSelected != 0)
  1980. {
  1981. if ( device == forceSelected )
  1982. {
  1983. return true;
  1984. }
  1985. else
  1986. {
  1987. return false;
  1988. }
  1989. }
  1990. #endif
  1991. if ( device == m_currentInputDevice ||
  1992. m_currentInputDevice == INPUT_DEVICE_NONE )
  1993. {
  1994. return true;
  1995. }
  1996. return false;
  1997. }
  1998. InputDevice_t CInputSystem::GetCurrentInputDevice( void )
  1999. {
  2000. return m_currentInputDevice;
  2001. }
  2002. void CInputSystem::SetCurrentInputDevice( InputDevice_t device )
  2003. {
  2004. if ( ( device != INPUT_DEVICE_NONE ) &&
  2005. ( ( countBits( device ) != 1 ) || ( device & PlatformInputDevice::s_validPlatformInputDevices[PlatformInputDevice::s_LocalInputPlatform] ) != device ) )
  2006. {
  2007. AssertMsg( false, "invalid input device" );
  2008. return;
  2009. }
  2010. m_currentInputDevice = device;
  2011. }
  2012. void CInputSystem::SampleInputToFindCurrentDevice( bool doSample )
  2013. {
  2014. m_setCurrentInputDeviceOnNextButtonPress = doSample;
  2015. }
  2016. bool CInputSystem::IsSamplingForCurrentDevice( void )
  2017. {
  2018. return m_setCurrentInputDeviceOnNextButtonPress;
  2019. }
  2020. #ifndef LINUX
  2021. #if !defined( _CERT )
  2022. // [mhansen] Add support for pressing Xbox 360 controller buttons (should work on PS3 too)
  2023. struct C_press_x360_button_code
  2024. {
  2025. char c1;
  2026. char c2;
  2027. xKey_t key;
  2028. };
  2029. static const C_press_x360_button_code press_x360_button_codes[] =
  2030. {
  2031. { 'l', 't', XK_BUTTON_LTRIGGER },
  2032. { 'r', 't', XK_BUTTON_RTRIGGER },
  2033. { 's', 't', XK_BUTTON_START },
  2034. { 'b', 'a', XK_BUTTON_BACK },
  2035. { 'l', 'b', XK_BUTTON_LEFT_SHOULDER },
  2036. { 'r', 'b', XK_BUTTON_RIGHT_SHOULDER },
  2037. { 'l', 's', XK_BUTTON_LEFT_SHOULDER },
  2038. { 'r', 's', XK_BUTTON_RIGHT_SHOULDER },
  2039. { 'a', 0, XK_BUTTON_A },
  2040. { 'b', 0, XK_BUTTON_B },
  2041. { 'x', 0, XK_BUTTON_X },
  2042. { 'y', 0, XK_BUTTON_Y },
  2043. { 'l', 0, XK_BUTTON_LEFT },
  2044. { 'r', 0, XK_BUTTON_RIGHT },
  2045. { 'u', 0, XK_BUTTON_UP },
  2046. { 'd', 0, XK_BUTTON_DOWN },
  2047. };
  2048. static const int cNum_press_x360_button_codes = ARRAYSIZE( press_x360_button_codes );
  2049. void CInputSystem::PressX360Button( const CCommand &args )
  2050. {
  2051. if ( pc_fake_controller.GetBool( ) && !m_bXController )
  2052. {
  2053. // [dkorus] we're simulating fake controller input and we don't have a controller enabled. Fake a controller so we can accept controller presses.
  2054. // this fixes the PC so it can use the same scripting engine as the other setups
  2055. // NOTE: This is wrapped in a !_CERT block. This shouldn't end up in the shipped game.
  2056. m_bXController = true;
  2057. }
  2058. if ( args.ArgC() < 2 )
  2059. {
  2060. Warning( "press_x360_button: requires a key to send (lt, rt, st[art], ba[ck], lb, rb, a, b, x, y, l[eft], r[right], u[p], d[own])" );
  2061. return;
  2062. }
  2063. const char* pKey = args[1];
  2064. // We're stashing this in a bitmask so make sure we don't overflow it
  2065. //COMPILE_TIME_ASSERT( cNum_press_x360_button_codes < sizeof( m_press_x360_buttons[ 0 ] ) );
  2066. xKey_t key = XK_BUTTON_A;
  2067. for ( uint32 i = 0; i < cNum_press_x360_button_codes; i++ )
  2068. {
  2069. if ( pKey[0] == press_x360_button_codes[i].c1 && ( pKey[1] == press_x360_button_codes[i].c2 || press_x360_button_codes[i].c2 == 0 ) )
  2070. {
  2071. key = press_x360_button_codes[i].key;
  2072. m_press_x360_buttons[ 0 ] = m_press_x360_buttons[ 0 ] | (1 << i );
  2073. break;
  2074. }
  2075. }
  2076. }
  2077. void CInputSystem::PollPressX360Button( void )
  2078. {
  2079. uint32 pressedButtons = m_press_x360_buttons[ 0 ];
  2080. uint32 releasedButtons = m_press_x360_buttons[ 1 ];
  2081. // Reset the buttons we pressed this frame
  2082. m_press_x360_buttons[ 0 ] = 0;
  2083. // Store the buttons we pressed this frame so we can clear them next frame
  2084. m_press_x360_buttons[ 1 ] = pressedButtons;
  2085. // Clear any old button presses and press any new ones
  2086. for ( uint32 i = 0; i < cNum_press_x360_button_codes; i++ )
  2087. {
  2088. uint32 mask = 1 << i;
  2089. if ( releasedButtons & mask )
  2090. {
  2091. PostXKeyEvent( 0, press_x360_button_codes[i].key, 0 );
  2092. }
  2093. if ( pressedButtons & mask )
  2094. {
  2095. PostXKeyEvent( 0, press_x360_button_codes[i].key, 32768/*XBX_MAX_BUTTONSAMPLE*/ );
  2096. }
  2097. }
  2098. }
  2099. #endif // !_CERT
  2100. #endif