mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
1
This commit is contained in:
764
engine/keys.cpp
Normal file
764
engine/keys.cpp
Normal file
@@ -0,0 +1,764 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "keys.h"
|
||||
#include "cdll_engine_int.h"
|
||||
#include "cmd.h"
|
||||
#include "toolframework/itoolframework.h"
|
||||
#include "toolframework/itoolsystem.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "vgui_baseui_interface.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "inputsystem/iinputsystem.h"
|
||||
#include "cheatcodes.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
enum KeyUpTarget_t
|
||||
{
|
||||
KEY_UP_ANYTARGET = 0,
|
||||
KEY_UP_ENGINE,
|
||||
KEY_UP_VGUI,
|
||||
KEY_UP_TOOLS,
|
||||
KEY_UP_CLIENT,
|
||||
};
|
||||
|
||||
struct KeyInfo_t
|
||||
{
|
||||
char *m_pKeyBinding;
|
||||
unsigned char m_nKeyUpTarget : 3; // see KeyUpTarget_t
|
||||
unsigned char m_bKeyDown : 1;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Current keypress state
|
||||
//-----------------------------------------------------------------------------
|
||||
static KeyInfo_t s_pKeyInfo[BUTTON_CODE_LAST];
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Trap mode is used by the keybinding UI
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool s_bTrapMode = false;
|
||||
static bool s_bDoneTrapping = false;
|
||||
static ButtonCode_t s_nTrapKeyUp = BUTTON_CODE_INVALID;
|
||||
static ButtonCode_t s_nTrapKey = BUTTON_CODE_INVALID;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Can keys be passed to various targets?
|
||||
//-----------------------------------------------------------------------------
|
||||
static inline bool ShouldPassKeyUpToTarget( ButtonCode_t code, KeyUpTarget_t target )
|
||||
{
|
||||
return ( s_pKeyInfo[code].m_nKeyUpTarget == target ) || ( s_pKeyInfo[code].m_nKeyUpTarget == KEY_UP_ANYTARGET );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_SetBinding
|
||||
===================
|
||||
*/
|
||||
void Key_SetBinding( ButtonCode_t keynum, const char *pBinding )
|
||||
{
|
||||
char *pNewBinding;
|
||||
int l;
|
||||
|
||||
if ( keynum == BUTTON_CODE_INVALID )
|
||||
return;
|
||||
|
||||
// free old bindings
|
||||
if ( s_pKeyInfo[keynum].m_pKeyBinding )
|
||||
{
|
||||
// Exactly the same, don't re-bind and fragment memory
|
||||
if ( !Q_strcmp( s_pKeyInfo[keynum].m_pKeyBinding, pBinding ) )
|
||||
return;
|
||||
|
||||
delete[] s_pKeyInfo[keynum].m_pKeyBinding;
|
||||
s_pKeyInfo[keynum].m_pKeyBinding = NULL;
|
||||
}
|
||||
|
||||
// allocate memory for new binding
|
||||
l = Q_strlen( pBinding );
|
||||
pNewBinding = (char *)new char[ l+1 ];
|
||||
Q_strncpy( pNewBinding, pBinding, l + 1 );
|
||||
pNewBinding[l] = 0;
|
||||
s_pKeyInfo[keynum].m_pKeyBinding = pNewBinding;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Unbind_f
|
||||
===================
|
||||
*/
|
||||
CON_COMMAND_F( unbind, "Unbind a key.", FCVAR_DONTRECORD )
|
||||
{
|
||||
ButtonCode_t b;
|
||||
|
||||
if ( args.ArgC() != 2 )
|
||||
{
|
||||
ConMsg( "unbind <key> : remove commands from a key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
b = g_pInputSystem->StringToButtonCode( args[1] );
|
||||
if ( b == BUTTON_CODE_INVALID )
|
||||
{
|
||||
ConMsg( "\"%s\" isn't a valid key\n", args[1] );
|
||||
return;
|
||||
}
|
||||
if ( b == KEY_ESCAPE )
|
||||
{
|
||||
ConMsg( "Can't unbind ESCAPE key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Key_SetBinding( b, "" );
|
||||
}
|
||||
|
||||
|
||||
CON_COMMAND_F( unbind_mac, "Unbind a key on the Mac only.", FCVAR_DONTRECORD )
|
||||
{
|
||||
if ( IsOSX() )
|
||||
{
|
||||
ButtonCode_t b;
|
||||
|
||||
if ( args.ArgC() != 2 )
|
||||
{
|
||||
ConMsg( "unbind <key> : remove commands from a key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
b = g_pInputSystem->StringToButtonCode( args[1] );
|
||||
if ( b == BUTTON_CODE_INVALID )
|
||||
{
|
||||
ConMsg( "\"%s\" isn't a valid key\n", args[1] );
|
||||
return;
|
||||
}
|
||||
if ( b == KEY_ESCAPE )
|
||||
{
|
||||
ConMsg( "Can't unbind ESCAPE key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Key_SetBinding( b, "" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CON_COMMAND_F( unbindall, "Unbind all keys.", FCVAR_DONTRECORD )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=0; i<BUTTON_CODE_LAST; i++ )
|
||||
{
|
||||
if ( !s_pKeyInfo[i].m_pKeyBinding )
|
||||
continue;
|
||||
|
||||
// Don't ever unbind escape or console key
|
||||
if ( i == KEY_ESCAPE )
|
||||
continue;
|
||||
|
||||
if ( i == KEY_BACKQUOTE )
|
||||
continue;
|
||||
|
||||
Key_SetBinding( (ButtonCode_t)i, "" );
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SWDS
|
||||
CON_COMMAND_F( escape, "Escape key pressed.", FCVAR_CLIENTCMD_CAN_EXECUTE )
|
||||
{
|
||||
EngineVGui()->HideGameUI();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Bind_f
|
||||
===================
|
||||
*/
|
||||
|
||||
void BindKey( const char *pchBind, bool bShow, const char *pchCmd )
|
||||
{
|
||||
if ( !g_pInputSystem )
|
||||
return;
|
||||
|
||||
ButtonCode_t b = g_pInputSystem->StringToButtonCode( pchBind );
|
||||
if ( b == BUTTON_CODE_INVALID )
|
||||
{
|
||||
ConMsg( "\"%s\" isn't a valid key\n", pchBind );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( bShow )
|
||||
{
|
||||
if (s_pKeyInfo[b].m_pKeyBinding)
|
||||
{
|
||||
ConMsg( "\"%s\" = \"%s\"\n", pchBind, s_pKeyInfo[b].m_pKeyBinding );
|
||||
}
|
||||
else
|
||||
{
|
||||
ConMsg( "\"%s\" is not bound\n", pchBind );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( b == KEY_ESCAPE )
|
||||
{
|
||||
pchCmd = "cancelselect";
|
||||
}
|
||||
|
||||
Key_SetBinding( b, pchCmd );
|
||||
}
|
||||
|
||||
|
||||
CON_COMMAND_F( bind, "Bind a key.", FCVAR_DONTRECORD )
|
||||
{
|
||||
int i, c;
|
||||
char cmd[1024];
|
||||
|
||||
c = args.ArgC();
|
||||
|
||||
if ( c != 2 && c != 3 )
|
||||
{
|
||||
ConMsg( "bind <key> [command] : attach a command to a key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// copy the rest of the command line
|
||||
cmd[0] = 0; // start out with a null string
|
||||
for ( i=2 ; i< c ; i++ )
|
||||
{
|
||||
if (i > 2)
|
||||
{
|
||||
Q_strncat( cmd, " ", sizeof( cmd ), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
Q_strncat( cmd, args[i], sizeof( cmd ), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
|
||||
BindKey( args[1], c == 2, cmd );
|
||||
}
|
||||
|
||||
CON_COMMAND_F( bind_mac, "Bind this key but only on Mac, not win32", FCVAR_DONTRECORD )
|
||||
{
|
||||
if ( IsOSX() )
|
||||
{
|
||||
int i, c;
|
||||
char cmd[1024];
|
||||
|
||||
c = args.ArgC();
|
||||
|
||||
if ( c != 2 && c != 3 )
|
||||
{
|
||||
ConMsg( "bind <key> [command] : attach a command to a key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// copy the rest of the command line
|
||||
cmd[0] = 0; // start out with a null string
|
||||
for ( i=2 ; i< c ; i++ )
|
||||
{
|
||||
if (i > 2)
|
||||
{
|
||||
Q_strncat( cmd, " ", sizeof( cmd ), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
Q_strncat( cmd, args[i], sizeof( cmd ), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
|
||||
BindKey( args[1], c == 2, cmd );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Key_CountBindings
|
||||
|
||||
Count number of lines of bindings we'll be writing
|
||||
============
|
||||
*/
|
||||
int Key_CountBindings( void )
|
||||
{
|
||||
int i;
|
||||
int c = 0;
|
||||
|
||||
for ( i = 0; i < BUTTON_CODE_LAST; i++ )
|
||||
{
|
||||
if ( !s_pKeyInfo[i].m_pKeyBinding || !s_pKeyInfo[i].m_pKeyBinding[0] )
|
||||
continue;
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Key_WriteBindings
|
||||
|
||||
Writes lines containing "bind key value"
|
||||
============
|
||||
*/
|
||||
void Key_WriteBindings( CUtlBuffer &buf )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < BUTTON_CODE_LAST ; i++ )
|
||||
{
|
||||
if ( !s_pKeyInfo[i].m_pKeyBinding || !s_pKeyInfo[i].m_pKeyBinding[0] )
|
||||
continue;
|
||||
|
||||
buf.Printf( "bind \"%s\" \"%s\"\n", g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i ), s_pKeyInfo[i].m_pKeyBinding );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Key_NameForBinding
|
||||
|
||||
Returns the keyname to which a binding string is bound. E.g., if
|
||||
TAB is bound to +use then searching for +use will return "TAB"
|
||||
============
|
||||
*/
|
||||
const char *Key_NameForBinding( const char *pBinding )
|
||||
{
|
||||
int i;
|
||||
|
||||
const char *pBind = pBinding;
|
||||
if ( pBinding[0] == '+' )
|
||||
{
|
||||
++pBind;
|
||||
}
|
||||
|
||||
for (i=0 ; i<BUTTON_CODE_LAST ; i++)
|
||||
{
|
||||
if (s_pKeyInfo[i].m_pKeyBinding)
|
||||
{
|
||||
if (*s_pKeyInfo[i].m_pKeyBinding)
|
||||
{
|
||||
if ( s_pKeyInfo[i].m_pKeyBinding[0] == '+' )
|
||||
{
|
||||
if ( !Q_strcasecmp( s_pKeyInfo[i].m_pKeyBinding+1, (char *)pBind ) )
|
||||
return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !Q_strcasecmp( s_pKeyInfo[i].m_pKeyBinding, (char *)pBind ) )
|
||||
return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Xbox 360 controller: Handle the dual bindings for duck and zoom
|
||||
if ( !Q_stricmp( "duck", pBind ) )
|
||||
return Key_NameForBinding( "toggle_duck" );
|
||||
|
||||
if ( !Q_stricmp( "zoom", pBind ) )
|
||||
return Key_NameForBinding( "toggle_zoom" );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Key_NameForBinding
|
||||
|
||||
Returns the keyname to which a binding string is bound. E.g., if
|
||||
TAB is bound to +use then searching for +use will return "TAB"
|
||||
|
||||
Does not perform "helpful" removal of '+' character from bindings.
|
||||
============
|
||||
*/
|
||||
const char *Key_NameForBindingExact( const char *pBinding )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<BUTTON_CODE_LAST ; i++)
|
||||
{
|
||||
if (s_pKeyInfo[i].m_pKeyBinding)
|
||||
{
|
||||
if (*s_pKeyInfo[i].m_pKeyBinding)
|
||||
{
|
||||
if ( !Q_strcasecmp( s_pKeyInfo[i].m_pKeyBinding, pBinding ) )
|
||||
return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *Key_BindingForKey( ButtonCode_t code )
|
||||
{
|
||||
if ( code < 0 || code > BUTTON_CODE_LAST )
|
||||
return NULL;
|
||||
|
||||
if ( !s_pKeyInfo[ code ].m_pKeyBinding )
|
||||
return NULL;
|
||||
|
||||
return s_pKeyInfo[ code ].m_pKeyBinding;
|
||||
}
|
||||
|
||||
CON_COMMAND( key_listboundkeys, "List bound keys with bindings." )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<BUTTON_CODE_LAST ; i++)
|
||||
{
|
||||
const char *pBinding = Key_BindingForKey( (ButtonCode_t)i );
|
||||
if ( !pBinding || !pBinding[0] )
|
||||
continue;
|
||||
|
||||
ConMsg( "\"%s\" = \"%s\"\n", g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i ), pBinding );
|
||||
}
|
||||
}
|
||||
|
||||
CON_COMMAND( key_findbinding, "Find key bound to specified command string." )
|
||||
{
|
||||
if ( args.ArgC() != 2 )
|
||||
{
|
||||
ConMsg( "usage: key_findbinding substring\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
const char *substring = args[1];
|
||||
if ( !substring || !substring[ 0 ] )
|
||||
{
|
||||
ConMsg( "usage: key_findbinding substring\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<BUTTON_CODE_LAST ; i++)
|
||||
{
|
||||
const char *pBinding = Key_BindingForKey( (ButtonCode_t)i );
|
||||
if ( !pBinding || !pBinding[0] )
|
||||
continue;
|
||||
|
||||
if ( Q_strstr( pBinding, substring ) )
|
||||
{
|
||||
ConMsg( "\"%s\" = \"%s\"\n",
|
||||
g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i ), pBinding );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initialization, shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
void Key_Init (void)
|
||||
{
|
||||
ReadCheatCommandsFromFile( "scripts/cheatcodes.txt" );
|
||||
ReadCheatCommandsFromFile( "scripts/mod_cheatcodes.txt" );
|
||||
}
|
||||
|
||||
void Key_Shutdown( void )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( s_pKeyInfo ); ++i )
|
||||
{
|
||||
delete[] s_pKeyInfo[ i ].m_pKeyBinding;
|
||||
s_pKeyInfo[ i ].m_pKeyBinding = NULL;
|
||||
}
|
||||
|
||||
ClearCheatCommands();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Starts trap mode (used for keybinding UI)
|
||||
//-----------------------------------------------------------------------------
|
||||
void Key_StartTrapMode( void )
|
||||
{
|
||||
if ( s_bTrapMode )
|
||||
return;
|
||||
|
||||
Assert( !s_bDoneTrapping && s_nTrapKeyUp == BUTTON_CODE_INVALID );
|
||||
|
||||
s_bDoneTrapping = false;
|
||||
s_bTrapMode = true;
|
||||
s_nTrapKeyUp = BUTTON_CODE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// We're done trapping once the first key is hit
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Key_CheckDoneTrapping( ButtonCode_t& code )
|
||||
{
|
||||
if ( s_bTrapMode )
|
||||
return false;
|
||||
|
||||
if ( !s_bDoneTrapping )
|
||||
return false;
|
||||
|
||||
code = s_nTrapKey;
|
||||
s_nTrapKey = BUTTON_CODE_INVALID;
|
||||
|
||||
// Reset since we retrieved the results
|
||||
s_bDoneTrapping = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef SWDS
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Filter out trapped keys
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool FilterTrappedKey( ButtonCode_t code, bool bDown )
|
||||
{
|
||||
// After we've trapped a key, we want to capture the button up message for that key
|
||||
if ( s_nTrapKeyUp == code && !bDown )
|
||||
{
|
||||
s_nTrapKeyUp = BUTTON_CODE_INVALID;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only key down events are trapped
|
||||
if ( s_bTrapMode && bDown )
|
||||
{
|
||||
s_nTrapKey = code;
|
||||
s_bTrapMode = false;
|
||||
s_bDoneTrapping = true;
|
||||
s_nTrapKeyUp = code;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Lets tools have a whack at key events
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool HandleToolKey( const InputEvent_t &event )
|
||||
{
|
||||
IToolSystem *toolsys = toolframework->GetTopmostTool();
|
||||
return toolsys && toolsys->TrapKey( (ButtonCode_t)event.m_nData, ( event.m_nType != IE_ButtonReleased ) );
|
||||
}
|
||||
|
||||
#endif // !SWDS
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Lets vgui have a whack at key events
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef SWDS
|
||||
static bool HandleVGuiKey( const InputEvent_t &event )
|
||||
{
|
||||
bool bDown = event.m_nType != IE_ButtonReleased;
|
||||
ButtonCode_t code = (ButtonCode_t)event.m_nData;
|
||||
|
||||
if ( bDown && IsX360() )
|
||||
{
|
||||
LogKeyPress( code );
|
||||
CheckCheatCodes();
|
||||
}
|
||||
|
||||
return EngineVGui()->Key_Event( event );
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Lets the client have a whack at key events
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static bool HandleClientKey( const InputEvent_t &event )
|
||||
{
|
||||
bool bDown = event.m_nType != IE_ButtonReleased;
|
||||
ButtonCode_t code = (ButtonCode_t)event.m_nData;
|
||||
|
||||
if ( g_ClientDLL && g_ClientDLL->IN_KeyEvent( bDown ? 1 : 0, code, s_pKeyInfo[ code ].m_pKeyBinding ) == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Lets the engine have a whack at key events
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef SWDS
|
||||
static bool HandleEngineKey( const InputEvent_t &event )
|
||||
{
|
||||
bool bDown = event.m_nType != IE_ButtonReleased;
|
||||
ButtonCode_t code = (ButtonCode_t)event.m_nData;
|
||||
|
||||
// Warn about unbound keys
|
||||
if ( IsPC() && bDown )
|
||||
{
|
||||
if ( IsJoystickCode( code ) && !IsJoystickAxisCode( code ) && !IsSteamControllerCode( code ) && !s_pKeyInfo[code].m_pKeyBinding )
|
||||
{
|
||||
ConDMsg( "%s is unbound.\n", g_pInputSystem->ButtonCodeToString( code ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the client to handle mouse wheel events while the game has focus, without having to bind keys.
|
||||
#if !defined( SWDS )
|
||||
if ( ( code == MOUSE_WHEEL_UP || code == MOUSE_WHEEL_DOWN ) && g_pClientReplay )
|
||||
{
|
||||
g_ClientDLL->IN_OnMouseWheeled( code == MOUSE_WHEEL_UP ? 1 : -1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
// key up events only generate commands if the game key binding is
|
||||
// a button command (leading + sign). These will occur even in console mode,
|
||||
// to keep the character from continuing an action started before a console
|
||||
// switch. Button commands include the kenum as a parameter, so multiple
|
||||
// downs can be matched with ups
|
||||
char *kb = s_pKeyInfo[ code ].m_pKeyBinding;
|
||||
if ( !kb || !kb[0] )
|
||||
return false;
|
||||
|
||||
char cmd[1024];
|
||||
if ( !bDown )
|
||||
{
|
||||
if ( kb[0] == '+' )
|
||||
{
|
||||
Q_snprintf( cmd, sizeof( cmd ), "-%s %i\n", kb+1, code );
|
||||
Cbuf_AddText( cmd );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Send to the interpreter
|
||||
if (kb[0] == '+')
|
||||
{
|
||||
// button commands add keynum as a parm
|
||||
Q_snprintf( cmd, sizeof( cmd ), "%s %i\n", kb, code );
|
||||
Cbuf_AddText( cmd );
|
||||
return true;
|
||||
}
|
||||
|
||||
// Swallow console toggle if any modifier keys are down if it's bound to toggleconsole (the default)
|
||||
if ( !Q_stricmp( kb, "toggleconsole" ) )
|
||||
{
|
||||
if ( s_pKeyInfo[KEY_LALT].m_bKeyDown || s_pKeyInfo[KEY_LSHIFT].m_bKeyDown || s_pKeyInfo[KEY_LCONTROL].m_bKeyDown ||
|
||||
s_pKeyInfo[KEY_RALT].m_bKeyDown || s_pKeyInfo[KEY_RSHIFT].m_bKeyDown || s_pKeyInfo[KEY_RCONTROL].m_bKeyDown )
|
||||
return false;
|
||||
}
|
||||
|
||||
Cbuf_AddText( kb );
|
||||
Cbuf_AddText( "\n" );
|
||||
return true;
|
||||
}
|
||||
#endif // !SWDS
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper function to make sure key down/key up events go to the right places
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef SWDS
|
||||
typedef bool (*FilterKeyFunc_t)( const InputEvent_t &event );
|
||||
|
||||
static bool FilterKey( const InputEvent_t &event, KeyUpTarget_t target, FilterKeyFunc_t func )
|
||||
{
|
||||
bool bDown = event.m_nType != IE_ButtonReleased;
|
||||
ButtonCode_t code = (ButtonCode_t)event.m_nData;
|
||||
|
||||
// Don't pass the key up to tools if some other system wants it
|
||||
if ( !bDown && !ShouldPassKeyUpToTarget( code, target ) )
|
||||
return false;
|
||||
|
||||
bool bFiltered = func( event );
|
||||
|
||||
// If we filtered it, then we need to get the key up event
|
||||
if ( bDown )
|
||||
{
|
||||
if ( bFiltered )
|
||||
{
|
||||
Assert( s_pKeyInfo[code].m_nKeyUpTarget == KEY_UP_ANYTARGET );
|
||||
s_pKeyInfo[code].m_nKeyUpTarget = target;
|
||||
}
|
||||
}
|
||||
else // Up case
|
||||
{
|
||||
if ( s_pKeyInfo[code].m_nKeyUpTarget == target )
|
||||
{
|
||||
s_pKeyInfo[code].m_nKeyUpTarget = KEY_UP_ANYTARGET;
|
||||
bFiltered = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: It is illegal to trap up key events. The system will do it for us
|
||||
Assert( !bFiltered );
|
||||
}
|
||||
}
|
||||
|
||||
return bFiltered;
|
||||
}
|
||||
#endif // !SWDS
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called by the system between frames for both key up and key down events
|
||||
//-----------------------------------------------------------------------------
|
||||
void Key_Event( const InputEvent_t &event )
|
||||
{
|
||||
#ifdef SWDS
|
||||
return;
|
||||
#else
|
||||
ASSERT_NO_REENTRY();
|
||||
|
||||
bool bDown = event.m_nType != IE_ButtonReleased;
|
||||
ButtonCode_t code = (ButtonCode_t)event.m_nData;
|
||||
|
||||
#ifdef LINUX
|
||||
// We're getting some crashes referencing s_pKeyInfo[ code ]. Let's try to
|
||||
// hard error here and see if we can get code and type at http://minidump.
|
||||
if ( code < 0 || code >= ARRAYSIZE( s_pKeyInfo ) )
|
||||
{
|
||||
Error( "Key_Event: invalid code! type:%d code:%d\n", event.m_nType, code );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't handle key ups if the key's already up.
|
||||
// NOTE: This should already be taken care of by the input system
|
||||
Assert( s_pKeyInfo[code].m_bKeyDown != bDown );
|
||||
if ( s_pKeyInfo[code].m_bKeyDown == bDown )
|
||||
return;
|
||||
|
||||
s_pKeyInfo[code].m_bKeyDown = bDown;
|
||||
|
||||
// Deal with trapped keys
|
||||
if ( FilterTrappedKey( code, bDown ) )
|
||||
return;
|
||||
|
||||
// Keep vgui's notion of which keys are down up-to-date regardless of filtering
|
||||
// Necessary because vgui has multiple input contexts, so vgui can't directly
|
||||
// ask the input system for this information.
|
||||
EngineVGui()->UpdateButtonState( event );
|
||||
|
||||
// Let tools have a whack at keys
|
||||
if ( FilterKey( event, KEY_UP_TOOLS, HandleToolKey ) )
|
||||
return;
|
||||
|
||||
// Let vgui have a whack at keys
|
||||
if ( FilterKey( event, KEY_UP_VGUI, HandleVGuiKey ) )
|
||||
return;
|
||||
|
||||
// Let the client have a whack at keys
|
||||
if ( FilterKey( event, KEY_UP_CLIENT, HandleClientKey ) )
|
||||
return;
|
||||
|
||||
// Finally, let the engine deal. Here's where keybindings occur.
|
||||
FilterKey( event, KEY_UP_ENGINE, HandleEngineKey );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user