doom3-bfg/neo/framework/KeyInput.cpp

990 lines
22 KiB
C++
Raw Normal View History

2012-11-26 18:58:24 +00:00
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012 Robert Beckebans
2012-11-26 18:58:24 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "precompiled.h"
2012-11-26 18:58:24 +00:00
#pragma hdrstop
typedef struct
{
2012-11-26 18:58:24 +00:00
keyNum_t keynum;
const char* name;
const char* strId; // localized string id
2012-11-26 18:58:24 +00:00
} keyname_t;
#define NAMEKEY( code, strId ) { K_##code, #code, strId }
#define NAMEKEY2( code ) { K_##code, #code, #code }
#define ALIASKEY( alias, code ) { K_##code, alias, "" }
// names not in this list can either be lowercase ascii, or '0xnn' hex sequences
keyname_t keynames[] =
{
NAMEKEY( ESCAPE, "#str_07020" ),
NAMEKEY2( 1 ),
NAMEKEY2( 2 ),
NAMEKEY2( 3 ),
NAMEKEY2( 4 ),
NAMEKEY2( 5 ),
NAMEKEY2( 6 ),
NAMEKEY2( 7 ),
NAMEKEY2( 8 ),
NAMEKEY2( 9 ),
NAMEKEY2( 0 ),
NAMEKEY( MINUS, "-" ),
NAMEKEY( EQUALS, "=" ),
NAMEKEY( BACKSPACE, "#str_07022" ),
NAMEKEY( TAB, "#str_07018" ),
NAMEKEY2( Q ),
NAMEKEY2( W ),
NAMEKEY2( E ),
NAMEKEY2( R ),
NAMEKEY2( T ),
NAMEKEY2( Y ),
NAMEKEY2( U ),
NAMEKEY2( I ),
NAMEKEY2( O ),
NAMEKEY2( P ),
NAMEKEY( LBRACKET, "[" ),
NAMEKEY( RBRACKET, "]" ),
NAMEKEY( ENTER, "#str_07019" ),
NAMEKEY( LCTRL, "#str_07028" ),
NAMEKEY2( A ),
NAMEKEY2( S ),
NAMEKEY2( D ),
NAMEKEY2( F ),
NAMEKEY2( G ),
NAMEKEY2( H ),
NAMEKEY2( J ),
NAMEKEY2( K ),
NAMEKEY2( L ),
NAMEKEY( SEMICOLON, "#str_07129" ),
NAMEKEY( APOSTROPHE, "#str_07130" ),
NAMEKEY( GRAVE, "`" ),
NAMEKEY( LSHIFT, "#str_07029" ),
NAMEKEY( BACKSLASH, "\\" ),
NAMEKEY2( Z ),
NAMEKEY2( X ),
NAMEKEY2( C ),
NAMEKEY2( V ),
NAMEKEY2( B ),
NAMEKEY2( N ),
NAMEKEY2( M ),
NAMEKEY( COMMA, "," ),
NAMEKEY( PERIOD, "." ),
NAMEKEY( SLASH, "/" ),
NAMEKEY( RSHIFT, "#str_bind_RSHIFT" ),
NAMEKEY( KP_STAR, "#str_07126" ),
NAMEKEY( LALT, "#str_07027" ),
NAMEKEY( SPACE, "#str_07021" ),
NAMEKEY( CAPSLOCK, "#str_07034" ),
NAMEKEY( F1, "#str_07036" ),
NAMEKEY( F2, "#str_07037" ),
NAMEKEY( F3, "#str_07038" ),
NAMEKEY( F4, "#str_07039" ),
NAMEKEY( F5, "#str_07040" ),
NAMEKEY( F6, "#str_07041" ),
NAMEKEY( F7, "#str_07042" ),
NAMEKEY( F8, "#str_07043" ),
NAMEKEY( F9, "#str_07044" ),
NAMEKEY( F10, "#str_07045" ),
NAMEKEY( NUMLOCK, "#str_07125" ),
NAMEKEY( SCROLL, "#str_07035" ),
NAMEKEY( KP_7, "#str_07110" ),
NAMEKEY( KP_8, "#str_07111" ),
NAMEKEY( KP_9, "#str_07112" ),
NAMEKEY( KP_MINUS, "#str_07123" ),
NAMEKEY( KP_4, "#str_07113" ),
NAMEKEY( KP_5, "#str_07114" ),
NAMEKEY( KP_6, "#str_07115" ),
NAMEKEY( KP_PLUS, "#str_07124" ),
NAMEKEY( KP_1, "#str_07116" ),
NAMEKEY( KP_2, "#str_07117" ),
NAMEKEY( KP_3, "#str_07118" ),
NAMEKEY( KP_0, "#str_07120" ),
NAMEKEY( KP_DOT, "#str_07121" ),
NAMEKEY( F11, "#str_07046" ),
NAMEKEY( F12, "#str_07047" ),
NAMEKEY2( F13 ),
NAMEKEY2( F14 ),
NAMEKEY2( F15 ),
NAMEKEY2( KANA ),
NAMEKEY2( CONVERT ),
NAMEKEY2( NOCONVERT ),
NAMEKEY2( YEN ),
NAMEKEY( KP_EQUALS, "#str_07127" ),
NAMEKEY2( CIRCUMFLEX ),
NAMEKEY( AT, "@" ),
NAMEKEY( COLON, ":" ),
NAMEKEY( UNDERLINE, "_" ),
NAMEKEY2( KANJI ),
NAMEKEY2( STOP ),
NAMEKEY2( AX ),
NAMEKEY2( UNLABELED ),
NAMEKEY( KP_ENTER, "#str_07119" ),
NAMEKEY( RCTRL, "#str_bind_RCTRL" ),
NAMEKEY( KP_COMMA, "," ),
NAMEKEY( KP_SLASH, "#str_07122" ),
NAMEKEY( PRINTSCREEN, "#str_07179" ),
NAMEKEY( RALT, "#str_bind_RALT" ),
NAMEKEY( PAUSE, "#str_07128" ),
NAMEKEY( HOME, "#str_07052" ),
NAMEKEY( UPARROW, "#str_07023" ),
NAMEKEY( PGUP, "#str_07051" ),
NAMEKEY( LEFTARROW, "#str_07025" ),
NAMEKEY( RIGHTARROW, "#str_07026" ),
NAMEKEY( END, "#str_07053" ),
NAMEKEY( DOWNARROW, "#str_07024" ),
NAMEKEY( PGDN, "#str_07050" ),
NAMEKEY( INS, "#str_07048" ),
NAMEKEY( DEL, "#str_07049" ),
NAMEKEY( LWIN, "#str_07030" ),
NAMEKEY( RWIN, "#str_07031" ),
NAMEKEY( APPS, "#str_07032" ),
NAMEKEY2( POWER ),
NAMEKEY2( SLEEP ),
// DG: adding names for keys from cegui/directinput I added in enum keyNum_t in sys_public.h
// (they're really valid directinput scancodes, they just haven't been handled before in d3bfg)
NAMEKEY2( OEM_102 ),
NAMEKEY2( ABNT_C1 ),
NAMEKEY2( NEXTTRACK ),
NAMEKEY2( MUTE ),
NAMEKEY2( CALCULATOR ),
NAMEKEY2( PLAYPAUSE ),
NAMEKEY2( MEDIASTOP ),
NAMEKEY2( VOLUMEDOWN ),
NAMEKEY2( VOLUMEUP ),
NAMEKEY2( WEBHOME ),
NAMEKEY2( WAKE ),
NAMEKEY2( WEBSEARCH ),
NAMEKEY2( WEBFAVORITES ),
NAMEKEY2( WEBREFRESH ),
NAMEKEY2( WEBSTOP ),
NAMEKEY2( WEBFORWARD ),
NAMEKEY2( WEBBACK ),
NAMEKEY2( MYCOMPUTER ),
NAMEKEY2( MAIL ),
NAMEKEY2( MEDIASELECT ),
// DG end
2012-11-26 18:58:24 +00:00
// --
2012-11-26 18:58:24 +00:00
NAMEKEY( MOUSE1, "#str_07054" ),
NAMEKEY( MOUSE2, "#str_07055" ),
NAMEKEY( MOUSE3, "#str_07056" ),
NAMEKEY( MOUSE4, "#str_07057" ),
NAMEKEY( MOUSE5, "#str_07058" ),
NAMEKEY( MOUSE6, "#str_07059" ),
NAMEKEY( MOUSE7, "#str_07060" ),
NAMEKEY( MOUSE8, "#str_07061" ),
2012-11-26 18:58:24 +00:00
NAMEKEY( MWHEELDOWN, "#str_07132" ),
NAMEKEY( MWHEELUP, "#str_07131" ),
2012-11-26 18:58:24 +00:00
NAMEKEY( JOY1, "#str_07062" ),
NAMEKEY( JOY2, "#str_07063" ),
NAMEKEY( JOY3, "#str_07064" ),
NAMEKEY( JOY4, "#str_07065" ),
NAMEKEY( JOY5, "#str_07066" ),
NAMEKEY( JOY6, "#str_07067" ),
NAMEKEY( JOY7, "#str_07068" ),
NAMEKEY( JOY8, "#str_07069" ),
NAMEKEY( JOY9, "#str_07070" ),
NAMEKEY( JOY10, "#str_07071" ),
NAMEKEY( JOY11, "#str_07072" ),
NAMEKEY( JOY12, "#str_07073" ),
NAMEKEY( JOY13, "#str_07074" ),
NAMEKEY( JOY14, "#str_07075" ),
NAMEKEY( JOY15, "#str_07076" ),
NAMEKEY( JOY16, "#str_07077" ),
2012-11-26 18:58:24 +00:00
NAMEKEY2( JOY_DPAD_UP ),
NAMEKEY2( JOY_DPAD_DOWN ),
NAMEKEY2( JOY_DPAD_LEFT ),
NAMEKEY2( JOY_DPAD_RIGHT ),
2012-11-26 18:58:24 +00:00
NAMEKEY2( JOY_STICK1_UP ),
NAMEKEY2( JOY_STICK1_DOWN ),
NAMEKEY2( JOY_STICK1_LEFT ),
NAMEKEY2( JOY_STICK1_RIGHT ),
2012-11-26 18:58:24 +00:00
NAMEKEY2( JOY_STICK2_UP ),
NAMEKEY2( JOY_STICK2_DOWN ),
NAMEKEY2( JOY_STICK2_LEFT ),
NAMEKEY2( JOY_STICK2_RIGHT ),
2012-11-26 18:58:24 +00:00
NAMEKEY2( JOY_TRIGGER1 ),
NAMEKEY2( JOY_TRIGGER2 ),
2012-11-26 18:58:24 +00:00
//------------------------
// Aliases to make it easier to bind or to support old configs
//------------------------
ALIASKEY( "ALT", LALT ),
ALIASKEY( "RIGHTALT", RALT ),
ALIASKEY( "CTRL", LCTRL ),
ALIASKEY( "SHIFT", LSHIFT ),
ALIASKEY( "MENU", APPS ),
ALIASKEY( "COMMAND", LALT ),
2012-11-26 18:58:24 +00:00
ALIASKEY( "KP_HOME", KP_7 ),
ALIASKEY( "KP_UPARROW", KP_8 ),
ALIASKEY( "KP_PGUP", KP_9 ),
ALIASKEY( "KP_LEFTARROW", KP_4 ),
ALIASKEY( "KP_RIGHTARROW", KP_6 ),
ALIASKEY( "KP_END", KP_1 ),
ALIASKEY( "KP_DOWNARROW", KP_2 ),
ALIASKEY( "KP_PGDN", KP_3 ),
ALIASKEY( "KP_INS", KP_0 ),
ALIASKEY( "KP_DEL", KP_DOT ),
ALIASKEY( "KP_NUMLOCK", NUMLOCK ),
2012-11-26 18:58:24 +00:00
ALIASKEY( "-", MINUS ),
ALIASKEY( "=", EQUALS ),
ALIASKEY( "[", LBRACKET ),
ALIASKEY( "]", RBRACKET ),
ALIASKEY( "\\", BACKSLASH ),
ALIASKEY( "/", SLASH ),
ALIASKEY( ",", COMMA ),
ALIASKEY( ".", PERIOD ),
2012-11-26 18:58:24 +00:00
{K_NONE, NULL, NULL}
};
class idKey
{
2012-11-26 18:58:24 +00:00
public:
idKey()
{
down = false;
repeats = 0;
usercmdAction = 0;
}
2012-11-26 18:58:24 +00:00
bool down;
int repeats; // if > 1, it is autorepeating
idStr binding;
int usercmdAction; // for testing by the asyncronous usercmd generation
};
bool key_overstrikeMode = false;
idKey* keys = NULL;
2012-11-26 18:58:24 +00:00
/*
===================
idKeyInput::ArgCompletion_KeyName
===================
*/
void idKeyInput::ArgCompletion_KeyName( const idCmdArgs& args, void( *callback )( const char* s ) )
{
for( keyname_t* kn = keynames; kn->name; kn++ )
{
2012-11-26 18:58:24 +00:00
callback( va( "%s %s", args.Argv( 0 ), kn->name ) );
}
}
/*
===================
idKeyInput::GetOverstrikeMode
===================
*/
bool idKeyInput::GetOverstrikeMode()
{
2012-11-26 18:58:24 +00:00
return key_overstrikeMode;
}
/*
===================
idKeyInput::SetOverstrikeMode
===================
*/
void idKeyInput::SetOverstrikeMode( bool state )
{
2012-11-26 18:58:24 +00:00
key_overstrikeMode = state;
}
/*
===================
idKeyInput::IsDown
===================
*/
bool idKeyInput::IsDown( int keynum )
{
if( keynum == -1 )
{
2012-11-26 18:58:24 +00:00
return false;
}
2012-11-26 18:58:24 +00:00
return keys[keynum].down;
}
/*
========================
idKeyInput::StringToKeyNum
========================
*/
keyNum_t idKeyInput::StringToKeyNum( const char* str )
{
2012-11-26 18:58:24 +00:00
if( !str || !str[0] )
{
2012-11-26 18:58:24 +00:00
return K_NONE;
}
2012-11-26 18:58:24 +00:00
// scan for a text match
for( keyname_t* kn = keynames; kn->name; kn++ )
{
if( !idStr::Icmp( str, kn->name ) )
{
2012-11-26 18:58:24 +00:00
return kn->keynum;
}
}
2012-11-26 18:58:24 +00:00
return K_NONE;
}
/*
========================
idKeyInput::KeyNumToString
========================
*/
const char* idKeyInput::KeyNumToString( keyNum_t keynum )
{
2012-11-26 18:58:24 +00:00
// check for a key string
for( keyname_t* kn = keynames; kn->name; kn++ )
{
if( keynum == kn->keynum )
{
2012-11-26 18:58:24 +00:00
return kn->name;
}
}
return "?";
}
/*
========================
idKeyInput::LocalizedKeyName
========================
*/
const char* idKeyInput::LocalizedKeyName( keyNum_t keynum )
{
// RB
#if defined(_WIN32)
// DG TODO: move this into a win32 Sys_GetKeyName()
if( keynum < K_JOY1 )
{
2012-11-26 18:58:24 +00:00
// On the PC, we want to turn the scan code in to a key label that matches the currently selected keyboard layout
unsigned char keystate[256] = { 0 };
WCHAR temp[5];
int scancode = ( int )keynum;
2012-11-26 18:58:24 +00:00
int vkey = MapVirtualKey( keynum, MAPVK_VSC_TO_VK_EX );
int result = -1;
while( result < 0 )
{
2012-11-26 18:58:24 +00:00
result = ToUnicode( vkey, scancode, keystate, temp, sizeof( temp ) / sizeof( temp[0] ), 0 );
}
if( result > 0 && temp[0] > ' ' && iswprint( temp[0] ) )
{
2012-11-26 18:58:24 +00:00
static idStr bindStr;
bindStr.Empty();
bindStr.AppendUTF8Char( temp[0] );
return bindStr;
}
}
#else // DG: for !Windows I introduced Sys_GetKeyName() to get key label for current keyboard layout
const char* ret = nullptr;
if( keynum < K_JOY1 ) // only for keyboard keys, not joystick or mouse
{
ret = Sys_GetKeyName( keynum );
}
if( ret != NULL )
{
return ret;
}
#endif
2012-11-26 18:58:24 +00:00
// check for a key string
for( keyname_t* kn = keynames; kn->name; kn++ )
{
if( keynum == kn->keynum )
{
2012-11-26 18:58:24 +00:00
return idLocalization::GetString( kn->strId );
}
}
return "????";
// RB/DG end
2012-11-26 18:58:24 +00:00
}
/*
===================
idKeyInput::SetBinding
===================
*/
void idKeyInput::SetBinding( int keynum, const char* binding )
{
if( keynum == -1 )
{
2012-11-26 18:58:24 +00:00
return;
}
2012-11-26 18:58:24 +00:00
// Clear out all button states so we aren't stuck forever thinking this key is held down
usercmdGen->Clear();
2012-11-26 18:58:24 +00:00
// allocate memory for new binding
keys[keynum].binding = binding;
2012-11-26 18:58:24 +00:00
// find the action for the async command generation
keys[keynum].usercmdAction = usercmdGen->CommandStringUsercmdData( binding );
2012-11-26 18:58:24 +00:00
// consider this like modifying an archived cvar, so the
// file write will be triggered at the next oportunity
cvarSystem->SetModifiedFlags( CVAR_ARCHIVE );
}
/*
===================
idKeyInput::GetBinding
===================
*/
const char* idKeyInput::GetBinding( int keynum )
{
if( keynum == -1 )
{
2012-11-26 18:58:24 +00:00
return "";
}
2012-11-26 18:58:24 +00:00
return keys[ keynum ].binding;
}
/*
===================
idKeyInput::GetUsercmdAction
===================
*/
int idKeyInput::GetUsercmdAction( int keynum )
{
2012-11-26 18:58:24 +00:00
return keys[ keynum ].usercmdAction;
}
/*
===================
Key_Unbind_f
===================
*/
void Key_Unbind_f( const idCmdArgs& args )
{
2012-11-26 18:58:24 +00:00
int b;
if( args.Argc() != 2 )
{
2012-11-26 18:58:24 +00:00
common->Printf( "unbind <key> : remove commands from a key\n" );
return;
}
b = idKeyInput::StringToKeyNum( args.Argv( 1 ) );
if( b == -1 )
{
2012-11-26 18:58:24 +00:00
// If it wasn't a key, it could be a command
if( !idKeyInput::UnbindBinding( args.Argv( 1 ) ) )
{
common->Printf( "\"%s\" isn't a valid key\n", args.Argv( 1 ) );
2012-11-26 18:58:24 +00:00
}
}
else
{
2012-11-26 18:58:24 +00:00
idKeyInput::SetBinding( b, "" );
}
}
/*
===================
Key_Unbindall_f
===================
*/
void Key_Unbindall_f( const idCmdArgs& args )
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
2012-11-26 18:58:24 +00:00
idKeyInput::SetBinding( i, "" );
}
}
/*
===================
Key_Bind_f
===================
*/
void Key_Bind_f( const idCmdArgs& args )
{
2012-11-26 18:58:24 +00:00
int i, c, b;
char cmd[MAX_STRING_CHARS];
c = args.Argc();
if( c < 2 )
{
2012-11-26 18:58:24 +00:00
common->Printf( "bind <key> [command] : attach a command to a key\n" );
return;
}
b = idKeyInput::StringToKeyNum( args.Argv( 1 ) );
if( b == -1 )
{
common->Printf( "\"%s\" isn't a valid key\n", args.Argv( 1 ) );
2012-11-26 18:58:24 +00:00
return;
}
if( c == 2 )
{
if( keys[b].binding.Length() )
{
common->Printf( "\"%s\" = \"%s\"\n", args.Argv( 1 ), keys[b].binding.c_str() );
2012-11-26 18:58:24 +00:00
}
else
{
common->Printf( "\"%s\" is not bound\n", args.Argv( 1 ) );
2012-11-26 18:58:24 +00:00
}
return;
}
// copy the rest of the command line
cmd[0] = 0; // start out with a null string
for( i = 2; i < c; i++ )
{
2012-11-26 18:58:24 +00:00
strcat( cmd, args.Argv( i ) );
if( i != ( c - 1 ) )
{
2012-11-26 18:58:24 +00:00
strcat( cmd, " " );
}
}
2012-11-26 18:58:24 +00:00
idKeyInput::SetBinding( b, cmd );
}
/*
============
Key_BindUnBindTwo_f
binds keynum to bindcommand and unbinds if there are already two binds on the key
============
*/
void Key_BindUnBindTwo_f( const idCmdArgs& args )
{
2012-11-26 18:58:24 +00:00
int c = args.Argc();
if( c < 3 )
{
2012-11-26 18:58:24 +00:00
common->Printf( "bindunbindtwo <keynum> [command]\n" );
return;
}
int key = atoi( args.Argv( 1 ) );
idStr bind = args.Argv( 2 );
if( idKeyInput::NumBinds( bind ) >= 2 && !idKeyInput::KeyIsBoundTo( key, bind ) )
{
2012-11-26 18:58:24 +00:00
idKeyInput::UnbindBinding( bind );
}
idKeyInput::SetBinding( key, bind );
}
/*
============
idKeyInput::WriteBindings
Writes lines containing "bind key value"
============
*/
void idKeyInput::WriteBindings( idFile* f )
{
2012-11-26 18:58:24 +00:00
f->Printf( "unbindall\n" );
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].binding.Length() )
{
const char* name = KeyNumToString( ( keyNum_t )i );
2012-11-26 18:58:24 +00:00
f->Printf( "bind \"%s\" \"%s\"\n", name, keys[i].binding.c_str() );
}
}
}
/*
============
Key_ListBinds_f
============
*/
void Key_ListBinds_f( const idCmdArgs& args )
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].binding.Length() )
{
common->Printf( "%s \"%s\"\n", idKeyInput::KeyNumToString( ( keyNum_t )i ), keys[i].binding.c_str() );
2012-11-26 18:58:24 +00:00
}
}
}
/*
============
idKeyInput::KeysFromBinding
returns the localized name of the key for the binding
============
*/
const char* idKeyInput::KeysFromBinding( const char* bind )
{
2012-11-26 18:58:24 +00:00
static char keyName[MAX_STRING_CHARS];
keyName[0] = 0;
if( bind && *bind )
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].binding.Icmp( bind ) == 0 )
{
if( keyName[0] != '\0' )
{
2012-11-26 18:58:24 +00:00
idStr::Append( keyName, sizeof( keyName ), idLocalization::GetString( "#str_07183" ) );
}
idStr::Append( keyName, sizeof( keyName ), LocalizedKeyName( ( keyNum_t )i ) );
2012-11-26 18:58:24 +00:00
}
}
}
if( keyName[0] == '\0' )
{
2012-11-26 18:58:24 +00:00
idStr::Copynz( keyName, idLocalization::GetString( "#str_07133" ), sizeof( keyName ) );
}
idStr::ToLower( keyName );
return keyName;
}
/*
========================
idKeyInput::KeyBindingsFromBinding
return: bindings for keyboard mouse and gamepad
========================
*/
keyBindings_t idKeyInput::KeyBindingsFromBinding( const char* bind, bool firstOnly, bool localized )
{
2012-11-26 18:58:24 +00:00
idStr keyboard;
idStr mouse;
idStr gamepad;
if( bind && *bind )
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].binding.Icmp( bind ) == 0 )
{
if( i >= K_JOY1 && i <= K_JOY_DPAD_RIGHT )
{
const char* gamepadKey = "";
if( localized )
{
gamepadKey = LocalizedKeyName( ( keyNum_t )i );
}
else
{
gamepadKey = KeyNumToString( ( keyNum_t )i );
2012-11-26 18:58:24 +00:00
}
if( idStr::Icmp( gamepadKey, "" ) != 0 )
{
if( !gamepad.IsEmpty() )
{
if( firstOnly )
{
2012-11-26 18:58:24 +00:00
continue;
}
gamepad.Append( ", " );
}
gamepad.Append( gamepadKey );
}
}
else if( i >= K_MOUSE1 && i <= K_MWHEELUP )
{
const char* mouseKey = "";
if( localized )
{
mouseKey = LocalizedKeyName( ( keyNum_t )i );
}
else
{
mouseKey = KeyNumToString( ( keyNum_t )i );
2012-11-26 18:58:24 +00:00
}
if( idStr::Icmp( mouseKey, "" ) != 0 )
{
if( !mouse.IsEmpty() )
{
if( firstOnly )
{
2012-11-26 18:58:24 +00:00
continue;
}
mouse.Append( ", " );
}
mouse.Append( mouseKey );
}
}
else
{
const char* tmp = "";
if( localized )
{
tmp = LocalizedKeyName( ( keyNum_t )i );
}
else
{
tmp = KeyNumToString( ( keyNum_t )i );
2012-11-26 18:58:24 +00:00
}
if( idStr::Icmp( tmp, "" ) != 0 && idStr::Icmp( tmp, keyboard ) != 0 )
{
if( !keyboard.IsEmpty() )
{
if( firstOnly )
{
2012-11-26 18:58:24 +00:00
continue;
}
keyboard.Append( ", " );
}
keyboard.Append( tmp );
}
}
}
}
}
2012-11-26 18:58:24 +00:00
keyBindings_t bindings;
bindings.gamepad = gamepad;
bindings.mouse = mouse;
bindings.keyboard = keyboard;
2012-11-26 18:58:24 +00:00
return bindings;
}
/*
============
idKeyInput::BindingFromKey
returns the binding for the localized name of the key
============
*/
const char* idKeyInput::BindingFromKey( const char* key )
{
2012-11-26 18:58:24 +00:00
const int keyNum = idKeyInput::StringToKeyNum( key );
if( keyNum < 0 || keyNum >= K_LAST_KEY )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
return keys[keyNum].binding.c_str();
}
/*
============
idKeyInput::UnbindBinding
============
*/
bool idKeyInput::UnbindBinding( const char* binding )
{
2012-11-26 18:58:24 +00:00
bool unbound = false;
if( binding && *binding )
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].binding.Icmp( binding ) == 0 )
{
2012-11-26 18:58:24 +00:00
SetBinding( i, "" );
unbound = true;
}
}
}
return unbound;
}
/*
============
idKeyInput::NumBinds
============
*/
int idKeyInput::NumBinds( const char* binding )
{
2012-11-26 18:58:24 +00:00
int count = 0;
if( binding && *binding )
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].binding.Icmp( binding ) == 0 )
{
2012-11-26 18:58:24 +00:00
count++;
}
}
}
return count;
}
/*
============
idKeyInput::KeyIsBountTo
============
*/
bool idKeyInput::KeyIsBoundTo( int keynum, const char* binding )
{
if( keynum >= 0 && keynum < K_LAST_KEY )
{
2012-11-26 18:58:24 +00:00
return ( keys[keynum].binding.Icmp( binding ) == 0 );
}
return false;
}
/*
===================
idKeyInput::PreliminaryKeyEvent
Tracks global key up/down state
Called by the system for both key up and key down events
===================
*/
void idKeyInput::PreliminaryKeyEvent( int keynum, bool down )
{
2012-11-26 18:58:24 +00:00
keys[keynum].down = down;
}
/*
=================
idKeyInput::ExecKeyBinding
=================
*/
bool idKeyInput::ExecKeyBinding( int keynum )
{
2012-11-26 18:58:24 +00:00
// commands that are used by the async thread
// don't add text
if( keys[keynum].usercmdAction )
{
2012-11-26 18:58:24 +00:00
return false;
}
2012-11-26 18:58:24 +00:00
// send the bound action
if( keys[keynum].binding.Length() )
{
2012-11-26 18:58:24 +00:00
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, keys[keynum].binding.c_str() );
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" );
}
return true;
}
/*
===================
idKeyInput::ClearStates
===================
*/
void idKeyInput::ClearStates()
{
for( int i = 0; i < K_LAST_KEY; i++ )
{
if( keys[i].down )
{
2012-11-26 18:58:24 +00:00
PreliminaryKeyEvent( i, false );
}
keys[i].down = false;
}
2012-11-26 18:58:24 +00:00
// clear the usercommand states
usercmdGen->Clear();
}
/*
===================
idKeyInput::Init
===================
*/
void idKeyInput::Init()
{
2012-11-26 18:58:24 +00:00
keys = new( TAG_SYSTEM ) idKey[K_LAST_KEY];
2012-11-26 18:58:24 +00:00
// register our functions
cmdSystem->AddCommand( "bind", Key_Bind_f, CMD_FL_SYSTEM, "binds a command to a key", idKeyInput::ArgCompletion_KeyName );
cmdSystem->AddCommand( "bindunbindtwo", Key_BindUnBindTwo_f, CMD_FL_SYSTEM, "binds a key but unbinds it first if there are more than two binds" );
cmdSystem->AddCommand( "unbind", Key_Unbind_f, CMD_FL_SYSTEM, "unbinds any command from a key", idKeyInput::ArgCompletion_KeyName );
cmdSystem->AddCommand( "unbindall", Key_Unbindall_f, CMD_FL_SYSTEM, "unbinds any commands from all keys" );
cmdSystem->AddCommand( "listBinds", Key_ListBinds_f, CMD_FL_SYSTEM, "lists key bindings" );
}
/*
===================
idKeyInput::Shutdown
===================
*/
void idKeyInput::Shutdown()
{
2012-11-26 18:58:24 +00:00
delete [] keys;
keys = NULL;
}
/*
========================
Key_CovertHIDCode
Converts from a USB HID code to a K_ code
========================
*/
int Key_CovertHIDCode( int hid )
{
if( hid >= 0 && hid <= 106 )
{
int table[] =
{
2012-11-26 18:58:24 +00:00
K_NONE, K_NONE, K_NONE, K_NONE,
K_A, K_B, K_C, K_D, K_E, K_F, K_G, K_H, K_I, K_J, K_K, K_L, K_M, K_N, K_O, K_P, K_Q, K_R, K_S, K_T, K_U, K_V, K_W, K_X, K_Y, K_Z,
K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9, K_0,
K_ENTER, K_ESCAPE, K_BACKSPACE, K_TAB, K_SPACE,
K_MINUS, K_EQUALS, K_LBRACKET, K_RBRACKET, K_BACKSLASH, K_NONE, K_SEMICOLON, K_APOSTROPHE, K_GRAVE, K_COMMA, K_PERIOD, K_SLASH, K_CAPSLOCK,
K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, K_F7, K_F8, K_F9, K_F10, K_F11, K_F12,
K_PRINTSCREEN, K_SCROLL, K_PAUSE, K_INS, K_HOME, K_PGUP, K_DEL, K_END, K_PGDN, K_RIGHTARROW, K_LEFTARROW, K_DOWNARROW, K_UPARROW,
K_NUMLOCK, K_KP_SLASH, K_KP_STAR, K_KP_MINUS, K_KP_PLUS, K_KP_ENTER,
K_KP_1, K_KP_2, K_KP_3, K_KP_4, K_KP_5, K_KP_6, K_KP_7, K_KP_8, K_KP_9, K_KP_0, K_KP_DOT,
K_NONE, K_APPS, K_POWER, K_KP_EQUALS,
K_F13, K_F14, K_F15
};
return table[hid];
}
if( hid >= 224 && hid <= 231 )
{
int table[] =
{
2012-11-26 18:58:24 +00:00
K_LCTRL, K_LSHIFT, K_LALT, K_LWIN,
K_RCTRL, K_RSHIFT, K_RALT, K_RWIN
};
return table[hid - 224];
}
return K_NONE;
}