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.

764 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "keys.h"
  9. #include "cdll_engine_int.h"
  10. #include "cmd.h"
  11. #include "toolframework/itoolframework.h"
  12. #include "toolframework/itoolsystem.h"
  13. #include "tier1/utlbuffer.h"
  14. #include "vgui_baseui_interface.h"
  15. #include "tier2/tier2.h"
  16. #include "inputsystem/iinputsystem.h"
  17. #include "cheatcodes.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. enum KeyUpTarget_t
  21. {
  22. KEY_UP_ANYTARGET = 0,
  23. KEY_UP_ENGINE,
  24. KEY_UP_VGUI,
  25. KEY_UP_TOOLS,
  26. KEY_UP_CLIENT,
  27. };
  28. struct KeyInfo_t
  29. {
  30. char *m_pKeyBinding;
  31. unsigned char m_nKeyUpTarget : 3; // see KeyUpTarget_t
  32. unsigned char m_bKeyDown : 1;
  33. };
  34. //-----------------------------------------------------------------------------
  35. // Current keypress state
  36. //-----------------------------------------------------------------------------
  37. static KeyInfo_t s_pKeyInfo[BUTTON_CODE_LAST];
  38. //-----------------------------------------------------------------------------
  39. // Trap mode is used by the keybinding UI
  40. //-----------------------------------------------------------------------------
  41. static bool s_bTrapMode = false;
  42. static bool s_bDoneTrapping = false;
  43. static ButtonCode_t s_nTrapKeyUp = BUTTON_CODE_INVALID;
  44. static ButtonCode_t s_nTrapKey = BUTTON_CODE_INVALID;
  45. //-----------------------------------------------------------------------------
  46. // Can keys be passed to various targets?
  47. //-----------------------------------------------------------------------------
  48. static inline bool ShouldPassKeyUpToTarget( ButtonCode_t code, KeyUpTarget_t target )
  49. {
  50. return ( s_pKeyInfo[code].m_nKeyUpTarget == target ) || ( s_pKeyInfo[code].m_nKeyUpTarget == KEY_UP_ANYTARGET );
  51. }
  52. /*
  53. ===================
  54. Key_SetBinding
  55. ===================
  56. */
  57. void Key_SetBinding( ButtonCode_t keynum, const char *pBinding )
  58. {
  59. char *pNewBinding;
  60. int l;
  61. if ( keynum == BUTTON_CODE_INVALID )
  62. return;
  63. // free old bindings
  64. if ( s_pKeyInfo[keynum].m_pKeyBinding )
  65. {
  66. // Exactly the same, don't re-bind and fragment memory
  67. if ( !Q_strcmp( s_pKeyInfo[keynum].m_pKeyBinding, pBinding ) )
  68. return;
  69. delete[] s_pKeyInfo[keynum].m_pKeyBinding;
  70. s_pKeyInfo[keynum].m_pKeyBinding = NULL;
  71. }
  72. // allocate memory for new binding
  73. l = Q_strlen( pBinding );
  74. pNewBinding = (char *)new char[ l+1 ];
  75. Q_strncpy( pNewBinding, pBinding, l + 1 );
  76. pNewBinding[l] = 0;
  77. s_pKeyInfo[keynum].m_pKeyBinding = pNewBinding;
  78. }
  79. /*
  80. ===================
  81. Key_Unbind_f
  82. ===================
  83. */
  84. CON_COMMAND_F( unbind, "Unbind a key.", FCVAR_DONTRECORD )
  85. {
  86. ButtonCode_t b;
  87. if ( args.ArgC() != 2 )
  88. {
  89. ConMsg( "unbind <key> : remove commands from a key\n" );
  90. return;
  91. }
  92. b = g_pInputSystem->StringToButtonCode( args[1] );
  93. if ( b == BUTTON_CODE_INVALID )
  94. {
  95. ConMsg( "\"%s\" isn't a valid key\n", args[1] );
  96. return;
  97. }
  98. if ( b == KEY_ESCAPE )
  99. {
  100. ConMsg( "Can't unbind ESCAPE key\n" );
  101. return;
  102. }
  103. Key_SetBinding( b, "" );
  104. }
  105. CON_COMMAND_F( unbind_mac, "Unbind a key on the Mac only.", FCVAR_DONTRECORD )
  106. {
  107. if ( IsOSX() )
  108. {
  109. ButtonCode_t b;
  110. if ( args.ArgC() != 2 )
  111. {
  112. ConMsg( "unbind <key> : remove commands from a key\n" );
  113. return;
  114. }
  115. b = g_pInputSystem->StringToButtonCode( args[1] );
  116. if ( b == BUTTON_CODE_INVALID )
  117. {
  118. ConMsg( "\"%s\" isn't a valid key\n", args[1] );
  119. return;
  120. }
  121. if ( b == KEY_ESCAPE )
  122. {
  123. ConMsg( "Can't unbind ESCAPE key\n" );
  124. return;
  125. }
  126. Key_SetBinding( b, "" );
  127. }
  128. }
  129. CON_COMMAND_F( unbindall, "Unbind all keys.", FCVAR_DONTRECORD )
  130. {
  131. int i;
  132. for ( i=0; i<BUTTON_CODE_LAST; i++ )
  133. {
  134. if ( !s_pKeyInfo[i].m_pKeyBinding )
  135. continue;
  136. // Don't ever unbind escape or console key
  137. if ( i == KEY_ESCAPE )
  138. continue;
  139. if ( i == KEY_BACKQUOTE )
  140. continue;
  141. Key_SetBinding( (ButtonCode_t)i, "" );
  142. }
  143. }
  144. #ifndef SWDS
  145. CON_COMMAND_F( escape, "Escape key pressed.", FCVAR_CLIENTCMD_CAN_EXECUTE )
  146. {
  147. EngineVGui()->HideGameUI();
  148. }
  149. #endif
  150. /*
  151. ===================
  152. Key_Bind_f
  153. ===================
  154. */
  155. void BindKey( const char *pchBind, bool bShow, const char *pchCmd )
  156. {
  157. if ( !g_pInputSystem )
  158. return;
  159. ButtonCode_t b = g_pInputSystem->StringToButtonCode( pchBind );
  160. if ( b == BUTTON_CODE_INVALID )
  161. {
  162. ConMsg( "\"%s\" isn't a valid key\n", pchBind );
  163. return;
  164. }
  165. if ( bShow )
  166. {
  167. if (s_pKeyInfo[b].m_pKeyBinding)
  168. {
  169. ConMsg( "\"%s\" = \"%s\"\n", pchBind, s_pKeyInfo[b].m_pKeyBinding );
  170. }
  171. else
  172. {
  173. ConMsg( "\"%s\" is not bound\n", pchBind );
  174. }
  175. return;
  176. }
  177. if ( b == KEY_ESCAPE )
  178. {
  179. pchCmd = "cancelselect";
  180. }
  181. Key_SetBinding( b, pchCmd );
  182. }
  183. CON_COMMAND_F( bind, "Bind a key.", FCVAR_DONTRECORD )
  184. {
  185. int i, c;
  186. char cmd[1024];
  187. c = args.ArgC();
  188. if ( c != 2 && c != 3 )
  189. {
  190. ConMsg( "bind <key> [command] : attach a command to a key\n" );
  191. return;
  192. }
  193. // copy the rest of the command line
  194. cmd[0] = 0; // start out with a null string
  195. for ( i=2 ; i< c ; i++ )
  196. {
  197. if (i > 2)
  198. {
  199. Q_strncat( cmd, " ", sizeof( cmd ), COPY_ALL_CHARACTERS );
  200. }
  201. Q_strncat( cmd, args[i], sizeof( cmd ), COPY_ALL_CHARACTERS );
  202. }
  203. BindKey( args[1], c == 2, cmd );
  204. }
  205. CON_COMMAND_F( bind_mac, "Bind this key but only on Mac, not win32", FCVAR_DONTRECORD )
  206. {
  207. if ( IsOSX() )
  208. {
  209. int i, c;
  210. char cmd[1024];
  211. c = args.ArgC();
  212. if ( c != 2 && c != 3 )
  213. {
  214. ConMsg( "bind <key> [command] : attach a command to a key\n" );
  215. return;
  216. }
  217. // copy the rest of the command line
  218. cmd[0] = 0; // start out with a null string
  219. for ( i=2 ; i< c ; i++ )
  220. {
  221. if (i > 2)
  222. {
  223. Q_strncat( cmd, " ", sizeof( cmd ), COPY_ALL_CHARACTERS );
  224. }
  225. Q_strncat( cmd, args[i], sizeof( cmd ), COPY_ALL_CHARACTERS );
  226. }
  227. BindKey( args[1], c == 2, cmd );
  228. }
  229. }
  230. /*
  231. ============
  232. Key_CountBindings
  233. Count number of lines of bindings we'll be writing
  234. ============
  235. */
  236. int Key_CountBindings( void )
  237. {
  238. int i;
  239. int c = 0;
  240. for ( i = 0; i < BUTTON_CODE_LAST; i++ )
  241. {
  242. if ( !s_pKeyInfo[i].m_pKeyBinding || !s_pKeyInfo[i].m_pKeyBinding[0] )
  243. continue;
  244. c++;
  245. }
  246. return c;
  247. }
  248. /*
  249. ============
  250. Key_WriteBindings
  251. Writes lines containing "bind key value"
  252. ============
  253. */
  254. void Key_WriteBindings( CUtlBuffer &buf )
  255. {
  256. int i;
  257. for ( i = 0 ; i < BUTTON_CODE_LAST ; i++ )
  258. {
  259. if ( !s_pKeyInfo[i].m_pKeyBinding || !s_pKeyInfo[i].m_pKeyBinding[0] )
  260. continue;
  261. buf.Printf( "bind \"%s\" \"%s\"\n", g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i ), s_pKeyInfo[i].m_pKeyBinding );
  262. }
  263. }
  264. /*
  265. ============
  266. Key_NameForBinding
  267. Returns the keyname to which a binding string is bound. E.g., if
  268. TAB is bound to +use then searching for +use will return "TAB"
  269. ============
  270. */
  271. const char *Key_NameForBinding( const char *pBinding )
  272. {
  273. int i;
  274. const char *pBind = pBinding;
  275. if ( pBinding[0] == '+' )
  276. {
  277. ++pBind;
  278. }
  279. for (i=0 ; i<BUTTON_CODE_LAST ; i++)
  280. {
  281. if (s_pKeyInfo[i].m_pKeyBinding)
  282. {
  283. if (*s_pKeyInfo[i].m_pKeyBinding)
  284. {
  285. if ( s_pKeyInfo[i].m_pKeyBinding[0] == '+' )
  286. {
  287. if ( !Q_strcasecmp( s_pKeyInfo[i].m_pKeyBinding+1, (char *)pBind ) )
  288. return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
  289. }
  290. else
  291. {
  292. if ( !Q_strcasecmp( s_pKeyInfo[i].m_pKeyBinding, (char *)pBind ) )
  293. return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
  294. }
  295. }
  296. }
  297. }
  298. // Xbox 360 controller: Handle the dual bindings for duck and zoom
  299. if ( !Q_stricmp( "duck", pBind ) )
  300. return Key_NameForBinding( "toggle_duck" );
  301. if ( !Q_stricmp( "zoom", pBind ) )
  302. return Key_NameForBinding( "toggle_zoom" );
  303. return NULL;
  304. }
  305. /*
  306. ============
  307. Key_NameForBinding
  308. Returns the keyname to which a binding string is bound. E.g., if
  309. TAB is bound to +use then searching for +use will return "TAB"
  310. Does not perform "helpful" removal of '+' character from bindings.
  311. ============
  312. */
  313. const char *Key_NameForBindingExact( const char *pBinding )
  314. {
  315. int i;
  316. for (i=0 ; i<BUTTON_CODE_LAST ; i++)
  317. {
  318. if (s_pKeyInfo[i].m_pKeyBinding)
  319. {
  320. if (*s_pKeyInfo[i].m_pKeyBinding)
  321. {
  322. if ( !Q_strcasecmp( s_pKeyInfo[i].m_pKeyBinding, pBinding ) )
  323. return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
  324. }
  325. }
  326. }
  327. return NULL;
  328. }
  329. const char *Key_BindingForKey( ButtonCode_t code )
  330. {
  331. if ( code < 0 || code > BUTTON_CODE_LAST )
  332. return NULL;
  333. if ( !s_pKeyInfo[ code ].m_pKeyBinding )
  334. return NULL;
  335. return s_pKeyInfo[ code ].m_pKeyBinding;
  336. }
  337. CON_COMMAND( key_listboundkeys, "List bound keys with bindings." )
  338. {
  339. int i;
  340. for (i=0 ; i<BUTTON_CODE_LAST ; i++)
  341. {
  342. const char *pBinding = Key_BindingForKey( (ButtonCode_t)i );
  343. if ( !pBinding || !pBinding[0] )
  344. continue;
  345. ConMsg( "\"%s\" = \"%s\"\n", g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i ), pBinding );
  346. }
  347. }
  348. CON_COMMAND( key_findbinding, "Find key bound to specified command string." )
  349. {
  350. if ( args.ArgC() != 2 )
  351. {
  352. ConMsg( "usage: key_findbinding substring\n" );
  353. return;
  354. }
  355. const char *substring = args[1];
  356. if ( !substring || !substring[ 0 ] )
  357. {
  358. ConMsg( "usage: key_findbinding substring\n" );
  359. return;
  360. }
  361. int i;
  362. for (i=0 ; i<BUTTON_CODE_LAST ; i++)
  363. {
  364. const char *pBinding = Key_BindingForKey( (ButtonCode_t)i );
  365. if ( !pBinding || !pBinding[0] )
  366. continue;
  367. if ( Q_strstr( pBinding, substring ) )
  368. {
  369. ConMsg( "\"%s\" = \"%s\"\n",
  370. g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i ), pBinding );
  371. }
  372. }
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Initialization, shutdown
  376. //-----------------------------------------------------------------------------
  377. void Key_Init (void)
  378. {
  379. ReadCheatCommandsFromFile( "scripts/cheatcodes.txt" );
  380. ReadCheatCommandsFromFile( "scripts/mod_cheatcodes.txt" );
  381. }
  382. void Key_Shutdown( void )
  383. {
  384. for ( int i = 0; i < ARRAYSIZE( s_pKeyInfo ); ++i )
  385. {
  386. delete[] s_pKeyInfo[ i ].m_pKeyBinding;
  387. s_pKeyInfo[ i ].m_pKeyBinding = NULL;
  388. }
  389. ClearCheatCommands();
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose: Starts trap mode (used for keybinding UI)
  393. //-----------------------------------------------------------------------------
  394. void Key_StartTrapMode( void )
  395. {
  396. if ( s_bTrapMode )
  397. return;
  398. Assert( !s_bDoneTrapping && s_nTrapKeyUp == BUTTON_CODE_INVALID );
  399. s_bDoneTrapping = false;
  400. s_bTrapMode = true;
  401. s_nTrapKeyUp = BUTTON_CODE_INVALID;
  402. }
  403. //-----------------------------------------------------------------------------
  404. // We're done trapping once the first key is hit
  405. //-----------------------------------------------------------------------------
  406. bool Key_CheckDoneTrapping( ButtonCode_t& code )
  407. {
  408. if ( s_bTrapMode )
  409. return false;
  410. if ( !s_bDoneTrapping )
  411. return false;
  412. code = s_nTrapKey;
  413. s_nTrapKey = BUTTON_CODE_INVALID;
  414. // Reset since we retrieved the results
  415. s_bDoneTrapping = false;
  416. return true;
  417. }
  418. #ifndef SWDS
  419. //-----------------------------------------------------------------------------
  420. // Filter out trapped keys
  421. //-----------------------------------------------------------------------------
  422. static bool FilterTrappedKey( ButtonCode_t code, bool bDown )
  423. {
  424. // After we've trapped a key, we want to capture the button up message for that key
  425. if ( s_nTrapKeyUp == code && !bDown )
  426. {
  427. s_nTrapKeyUp = BUTTON_CODE_INVALID;
  428. return true;
  429. }
  430. // Only key down events are trapped
  431. if ( s_bTrapMode && bDown )
  432. {
  433. s_nTrapKey = code;
  434. s_bTrapMode = false;
  435. s_bDoneTrapping = true;
  436. s_nTrapKeyUp = code;
  437. return true;
  438. }
  439. return false;
  440. }
  441. //-----------------------------------------------------------------------------
  442. // Lets tools have a whack at key events
  443. //-----------------------------------------------------------------------------
  444. static bool HandleToolKey( const InputEvent_t &event )
  445. {
  446. IToolSystem *toolsys = toolframework->GetTopmostTool();
  447. return toolsys && toolsys->TrapKey( (ButtonCode_t)event.m_nData, ( event.m_nType != IE_ButtonReleased ) );
  448. }
  449. #endif // !SWDS
  450. //-----------------------------------------------------------------------------
  451. // Lets vgui have a whack at key events
  452. //-----------------------------------------------------------------------------
  453. #ifndef SWDS
  454. static bool HandleVGuiKey( const InputEvent_t &event )
  455. {
  456. bool bDown = event.m_nType != IE_ButtonReleased;
  457. ButtonCode_t code = (ButtonCode_t)event.m_nData;
  458. if ( bDown && IsX360() )
  459. {
  460. LogKeyPress( code );
  461. CheckCheatCodes();
  462. }
  463. return EngineVGui()->Key_Event( event );
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Lets the client have a whack at key events
  467. //-----------------------------------------------------------------------------
  468. static bool HandleClientKey( const InputEvent_t &event )
  469. {
  470. bool bDown = event.m_nType != IE_ButtonReleased;
  471. ButtonCode_t code = (ButtonCode_t)event.m_nData;
  472. if ( g_ClientDLL && g_ClientDLL->IN_KeyEvent( bDown ? 1 : 0, code, s_pKeyInfo[ code ].m_pKeyBinding ) == 0 )
  473. return true;
  474. return false;
  475. }
  476. #endif
  477. //-----------------------------------------------------------------------------
  478. // Lets the engine have a whack at key events
  479. //-----------------------------------------------------------------------------
  480. #ifndef SWDS
  481. static bool HandleEngineKey( const InputEvent_t &event )
  482. {
  483. bool bDown = event.m_nType != IE_ButtonReleased;
  484. ButtonCode_t code = (ButtonCode_t)event.m_nData;
  485. // Warn about unbound keys
  486. if ( IsPC() && bDown )
  487. {
  488. if ( IsJoystickCode( code ) && !IsJoystickAxisCode( code ) && !IsSteamControllerCode( code ) && !s_pKeyInfo[code].m_pKeyBinding )
  489. {
  490. ConDMsg( "%s is unbound.\n", g_pInputSystem->ButtonCodeToString( code ) );
  491. }
  492. }
  493. // Allow the client to handle mouse wheel events while the game has focus, without having to bind keys.
  494. #if !defined( SWDS )
  495. if ( ( code == MOUSE_WHEEL_UP || code == MOUSE_WHEEL_DOWN ) && g_pClientReplay )
  496. {
  497. g_ClientDLL->IN_OnMouseWheeled( code == MOUSE_WHEEL_UP ? 1 : -1 );
  498. }
  499. #endif
  500. // key up events only generate commands if the game key binding is
  501. // a button command (leading + sign). These will occur even in console mode,
  502. // to keep the character from continuing an action started before a console
  503. // switch. Button commands include the kenum as a parameter, so multiple
  504. // downs can be matched with ups
  505. char *kb = s_pKeyInfo[ code ].m_pKeyBinding;
  506. if ( !kb || !kb[0] )
  507. return false;
  508. char cmd[1024];
  509. if ( !bDown )
  510. {
  511. if ( kb[0] == '+' )
  512. {
  513. Q_snprintf( cmd, sizeof( cmd ), "-%s %i\n", kb+1, code );
  514. Cbuf_AddText( cmd );
  515. return true;
  516. }
  517. return false;
  518. }
  519. // Send to the interpreter
  520. if (kb[0] == '+')
  521. {
  522. // button commands add keynum as a parm
  523. Q_snprintf( cmd, sizeof( cmd ), "%s %i\n", kb, code );
  524. Cbuf_AddText( cmd );
  525. return true;
  526. }
  527. // Swallow console toggle if any modifier keys are down if it's bound to toggleconsole (the default)
  528. if ( !Q_stricmp( kb, "toggleconsole" ) )
  529. {
  530. if ( s_pKeyInfo[KEY_LALT].m_bKeyDown || s_pKeyInfo[KEY_LSHIFT].m_bKeyDown || s_pKeyInfo[KEY_LCONTROL].m_bKeyDown ||
  531. s_pKeyInfo[KEY_RALT].m_bKeyDown || s_pKeyInfo[KEY_RSHIFT].m_bKeyDown || s_pKeyInfo[KEY_RCONTROL].m_bKeyDown )
  532. return false;
  533. }
  534. Cbuf_AddText( kb );
  535. Cbuf_AddText( "\n" );
  536. return true;
  537. }
  538. #endif // !SWDS
  539. //-----------------------------------------------------------------------------
  540. // Helper function to make sure key down/key up events go to the right places
  541. //-----------------------------------------------------------------------------
  542. #ifndef SWDS
  543. typedef bool (*FilterKeyFunc_t)( const InputEvent_t &event );
  544. static bool FilterKey( const InputEvent_t &event, KeyUpTarget_t target, FilterKeyFunc_t func )
  545. {
  546. bool bDown = event.m_nType != IE_ButtonReleased;
  547. ButtonCode_t code = (ButtonCode_t)event.m_nData;
  548. // Don't pass the key up to tools if some other system wants it
  549. if ( !bDown && !ShouldPassKeyUpToTarget( code, target ) )
  550. return false;
  551. bool bFiltered = func( event );
  552. // If we filtered it, then we need to get the key up event
  553. if ( bDown )
  554. {
  555. if ( bFiltered )
  556. {
  557. Assert( s_pKeyInfo[code].m_nKeyUpTarget == KEY_UP_ANYTARGET );
  558. s_pKeyInfo[code].m_nKeyUpTarget = target;
  559. }
  560. }
  561. else // Up case
  562. {
  563. if ( s_pKeyInfo[code].m_nKeyUpTarget == target )
  564. {
  565. s_pKeyInfo[code].m_nKeyUpTarget = KEY_UP_ANYTARGET;
  566. bFiltered = true;
  567. }
  568. else
  569. {
  570. // NOTE: It is illegal to trap up key events. The system will do it for us
  571. Assert( !bFiltered );
  572. }
  573. }
  574. return bFiltered;
  575. }
  576. #endif // !SWDS
  577. //-----------------------------------------------------------------------------
  578. // Called by the system between frames for both key up and key down events
  579. //-----------------------------------------------------------------------------
  580. void Key_Event( const InputEvent_t &event )
  581. {
  582. #ifdef SWDS
  583. return;
  584. #else
  585. ASSERT_NO_REENTRY();
  586. bool bDown = event.m_nType != IE_ButtonReleased;
  587. ButtonCode_t code = (ButtonCode_t)event.m_nData;
  588. #ifdef LINUX
  589. // We're getting some crashes referencing s_pKeyInfo[ code ]. Let's try to
  590. // hard error here and see if we can get code and type at http://minidump.
  591. if ( code < 0 || code >= ARRAYSIZE( s_pKeyInfo ) )
  592. {
  593. Error( "Key_Event: invalid code! type:%d code:%d\n", event.m_nType, code );
  594. }
  595. #endif
  596. // Don't handle key ups if the key's already up.
  597. // NOTE: This should already be taken care of by the input system
  598. Assert( s_pKeyInfo[code].m_bKeyDown != bDown );
  599. if ( s_pKeyInfo[code].m_bKeyDown == bDown )
  600. return;
  601. s_pKeyInfo[code].m_bKeyDown = bDown;
  602. // Deal with trapped keys
  603. if ( FilterTrappedKey( code, bDown ) )
  604. return;
  605. // Keep vgui's notion of which keys are down up-to-date regardless of filtering
  606. // Necessary because vgui has multiple input contexts, so vgui can't directly
  607. // ask the input system for this information.
  608. EngineVGui()->UpdateButtonState( event );
  609. // Let tools have a whack at keys
  610. if ( FilterKey( event, KEY_UP_TOOLS, HandleToolKey ) )
  611. return;
  612. // Let vgui have a whack at keys
  613. if ( FilterKey( event, KEY_UP_VGUI, HandleVGuiKey ) )
  614. return;
  615. // Let the client have a whack at keys
  616. if ( FilterKey( event, KEY_UP_CLIENT, HandleClientKey ) )
  617. return;
  618. // Finally, let the engine deal. Here's where keybindings occur.
  619. FilterKey( event, KEY_UP_ENGINE, HandleEngineKey );
  620. #endif
  621. }