DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

KeyInput.cpp (20863B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "../idlib/precompiled.h"
     30 #pragma hdrstop
     31 
     32 typedef struct {
     33 	keyNum_t		keynum;
     34 	const char *	name;
     35 	const char *	strId;	// localized string id
     36 } keyname_t;
     37 
     38 #define NAMEKEY( code, strId ) { K_##code, #code, strId }
     39 #define NAMEKEY2( code ) { K_##code, #code, #code }
     40 
     41 #define ALIASKEY( alias, code ) { K_##code, alias, "" }
     42 
     43 // names not in this list can either be lowercase ascii, or '0xnn' hex sequences
     44 keyname_t keynames[] =
     45 {
     46 	NAMEKEY( ESCAPE, "#str_07020" ),
     47 	NAMEKEY2( 1 ),
     48 	NAMEKEY2( 2 ),
     49 	NAMEKEY2( 3 ),
     50 	NAMEKEY2( 4 ),
     51 	NAMEKEY2( 5 ),
     52 	NAMEKEY2( 6 ),
     53 	NAMEKEY2( 7 ),
     54 	NAMEKEY2( 8 ),
     55 	NAMEKEY2( 9 ),
     56 	NAMEKEY2( 0 ),
     57 	NAMEKEY( MINUS, "-" ),
     58 	NAMEKEY( EQUALS, "=" ),
     59 	NAMEKEY( BACKSPACE, "#str_07022" ),
     60 	NAMEKEY( TAB, "#str_07018" ),
     61 	NAMEKEY2( Q ),
     62 	NAMEKEY2( W ),
     63 	NAMEKEY2( E ),
     64 	NAMEKEY2( R ),
     65 	NAMEKEY2( T ),
     66 	NAMEKEY2( Y ),
     67 	NAMEKEY2( U ),
     68 	NAMEKEY2( I ),
     69 	NAMEKEY2( O ),
     70 	NAMEKEY2( P ),
     71 	NAMEKEY( LBRACKET, "[" ),
     72 	NAMEKEY( RBRACKET, "]" ),
     73 	NAMEKEY( ENTER, "#str_07019" ),
     74 	NAMEKEY( LCTRL, "#str_07028" ),
     75 	NAMEKEY2( A ),
     76 	NAMEKEY2( S ),
     77 	NAMEKEY2( D ),
     78 	NAMEKEY2( F ),
     79 	NAMEKEY2( G ),
     80 	NAMEKEY2( H ),
     81 	NAMEKEY2( J ),
     82 	NAMEKEY2( K ),
     83 	NAMEKEY2( L ),
     84 	NAMEKEY( SEMICOLON, "#str_07129" ),
     85 	NAMEKEY( APOSTROPHE, "#str_07130" ),
     86 	NAMEKEY( GRAVE, "`" ),
     87 	NAMEKEY( LSHIFT, "#str_07029" ),
     88 	NAMEKEY( BACKSLASH, "\\" ),
     89 	NAMEKEY2( Z ),
     90 	NAMEKEY2( X ),
     91 	NAMEKEY2( C ),
     92 	NAMEKEY2( V ),
     93 	NAMEKEY2( B ),
     94 	NAMEKEY2( N ),
     95 	NAMEKEY2( M ),
     96 	NAMEKEY( COMMA, "," ),
     97 	NAMEKEY( PERIOD, "." ),
     98 	NAMEKEY( SLASH, "/" ),
     99 	NAMEKEY( RSHIFT, "#str_bind_RSHIFT" ),
    100 	NAMEKEY( KP_STAR, "#str_07126" ),
    101 	NAMEKEY( LALT, "#str_07027" ),
    102 	NAMEKEY( SPACE, "#str_07021" ),
    103 	NAMEKEY( CAPSLOCK, "#str_07034" ),
    104 	NAMEKEY( F1, "#str_07036" ),
    105 	NAMEKEY( F2, "#str_07037" ),
    106 	NAMEKEY( F3, "#str_07038" ),
    107 	NAMEKEY( F4, "#str_07039" ),
    108 	NAMEKEY( F5, "#str_07040" ),
    109 	NAMEKEY( F6, "#str_07041" ),
    110 	NAMEKEY( F7, "#str_07042" ),
    111 	NAMEKEY( F8, "#str_07043" ),
    112 	NAMEKEY( F9, "#str_07044" ),
    113 	NAMEKEY( F10, "#str_07045" ),
    114 	NAMEKEY( NUMLOCK, "#str_07125" ),
    115 	NAMEKEY( SCROLL, "#str_07035" ),
    116 	NAMEKEY( KP_7, "#str_07110" ),
    117 	NAMEKEY( KP_8, "#str_07111" ),
    118 	NAMEKEY( KP_9, "#str_07112" ),
    119 	NAMEKEY( KP_MINUS, "#str_07123" ),
    120 	NAMEKEY( KP_4, "#str_07113" ),
    121 	NAMEKEY( KP_5, "#str_07114" ),
    122 	NAMEKEY( KP_6, "#str_07115" ),
    123 	NAMEKEY( KP_PLUS, "#str_07124" ),
    124 	NAMEKEY( KP_1, "#str_07116" ),
    125 	NAMEKEY( KP_2, "#str_07117" ),
    126 	NAMEKEY( KP_3, "#str_07118" ),
    127 	NAMEKEY( KP_0, "#str_07120" ),
    128 	NAMEKEY( KP_DOT, "#str_07121" ),
    129 	NAMEKEY( F11, "#str_07046" ),
    130 	NAMEKEY( F12, "#str_07047" ),
    131 	NAMEKEY2( F13 ),
    132 	NAMEKEY2( F14 ),
    133 	NAMEKEY2( F15 ),
    134 	NAMEKEY2( KANA ),
    135 	NAMEKEY2( CONVERT ),
    136 	NAMEKEY2( NOCONVERT ),
    137 	NAMEKEY2( YEN ),
    138 	NAMEKEY( KP_EQUALS, "#str_07127" ),
    139 	NAMEKEY2( CIRCUMFLEX ),
    140 	NAMEKEY( AT, "@" ),
    141 	NAMEKEY( COLON, ":" ),
    142 	NAMEKEY( UNDERLINE, "_" ),
    143 	NAMEKEY2( KANJI ),
    144 	NAMEKEY2( STOP ),
    145 	NAMEKEY2( AX ),
    146 	NAMEKEY2( UNLABELED ),
    147 	NAMEKEY( KP_ENTER, "#str_07119" ),
    148 	NAMEKEY( RCTRL, "#str_bind_RCTRL" ),
    149 	NAMEKEY( KP_COMMA, "," ),
    150 	NAMEKEY( KP_SLASH, "#str_07122" ),
    151 	NAMEKEY( PRINTSCREEN, "#str_07179" ),
    152 	NAMEKEY( RALT, "#str_bind_RALT" ),
    153 	NAMEKEY( PAUSE, "#str_07128" ),
    154 	NAMEKEY( HOME, "#str_07052" ),
    155 	NAMEKEY( UPARROW, "#str_07023" ),
    156 	NAMEKEY( PGUP, "#str_07051" ),
    157 	NAMEKEY( LEFTARROW, "#str_07025" ),
    158 	NAMEKEY( RIGHTARROW, "#str_07026" ),
    159 	NAMEKEY( END, "#str_07053" ),
    160 	NAMEKEY( DOWNARROW, "#str_07024" ),
    161 	NAMEKEY( PGDN, "#str_07050" ),
    162 	NAMEKEY( INS, "#str_07048" ),
    163 	NAMEKEY( DEL, "#str_07049" ),
    164 	NAMEKEY( LWIN, "#str_07030" ),
    165 	NAMEKEY( RWIN, "#str_07031" ),
    166 	NAMEKEY( APPS, "#str_07032" ),
    167 	NAMEKEY2( POWER ),
    168 	NAMEKEY2( SLEEP ),
    169 
    170 	// --
    171 
    172 	NAMEKEY( MOUSE1, "#str_07054" ),
    173 	NAMEKEY( MOUSE2, "#str_07055" ),
    174 	NAMEKEY( MOUSE3, "#str_07056" ),
    175 	NAMEKEY( MOUSE4, "#str_07057" ),
    176 	NAMEKEY( MOUSE5, "#str_07058" ),
    177 	NAMEKEY( MOUSE6, "#str_07059" ),
    178 	NAMEKEY( MOUSE7, "#str_07060" ),
    179 	NAMEKEY( MOUSE8, "#str_07061" ),
    180 
    181 	NAMEKEY( MWHEELDOWN, "#str_07132" ),
    182 	NAMEKEY( MWHEELUP, "#str_07131" ),
    183 
    184 	NAMEKEY( JOY1, "#str_07062" ),
    185 	NAMEKEY( JOY2, "#str_07063" ),
    186 	NAMEKEY( JOY3, "#str_07064" ),
    187 	NAMEKEY( JOY4, "#str_07065" ),
    188 	NAMEKEY( JOY5, "#str_07066" ),
    189 	NAMEKEY( JOY6, "#str_07067" ),
    190 	NAMEKEY( JOY7, "#str_07068" ),
    191 	NAMEKEY( JOY8, "#str_07069" ),
    192 	NAMEKEY( JOY9, "#str_07070" ),
    193 	NAMEKEY( JOY10, "#str_07071" ),
    194 	NAMEKEY( JOY11, "#str_07072" ),
    195 	NAMEKEY( JOY12, "#str_07073" ),
    196 	NAMEKEY( JOY13, "#str_07074" ),
    197 	NAMEKEY( JOY14, "#str_07075" ),
    198 	NAMEKEY( JOY15, "#str_07076" ),
    199 	NAMEKEY( JOY16, "#str_07077" ),
    200 
    201 	NAMEKEY2( JOY_DPAD_UP ),
    202 	NAMEKEY2( JOY_DPAD_DOWN ),
    203 	NAMEKEY2( JOY_DPAD_LEFT ),
    204 	NAMEKEY2( JOY_DPAD_RIGHT ),
    205 
    206 	NAMEKEY2( JOY_STICK1_UP ),
    207 	NAMEKEY2( JOY_STICK1_DOWN ),
    208 	NAMEKEY2( JOY_STICK1_LEFT ),
    209 	NAMEKEY2( JOY_STICK1_RIGHT ),
    210 
    211 	NAMEKEY2( JOY_STICK2_UP ),
    212 	NAMEKEY2( JOY_STICK2_DOWN ),
    213 	NAMEKEY2( JOY_STICK2_LEFT ),
    214 	NAMEKEY2( JOY_STICK2_RIGHT ),
    215 
    216 	NAMEKEY2( JOY_TRIGGER1 ),
    217 	NAMEKEY2( JOY_TRIGGER2 ),
    218 
    219 	//------------------------
    220 	// Aliases to make it easier to bind or to support old configs
    221 	//------------------------
    222 	ALIASKEY( "ALT", LALT ),
    223 	ALIASKEY( "RIGHTALT", RALT ),
    224 	ALIASKEY( "CTRL", LCTRL ),
    225 	ALIASKEY( "SHIFT", LSHIFT ),
    226 	ALIASKEY( "MENU", APPS ),
    227 	ALIASKEY( "COMMAND", LALT ),
    228 
    229 	ALIASKEY( "KP_HOME", KP_7 ),
    230 	ALIASKEY( "KP_UPARROW", KP_8 ),
    231 	ALIASKEY( "KP_PGUP", KP_9 ),
    232 	ALIASKEY( "KP_LEFTARROW", KP_4 ),
    233 	ALIASKEY( "KP_RIGHTARROW", KP_6 ),
    234 	ALIASKEY( "KP_END", KP_1 ),
    235 	ALIASKEY( "KP_DOWNARROW", KP_2 ),
    236 	ALIASKEY( "KP_PGDN", KP_3 ),
    237 	ALIASKEY( "KP_INS", KP_0 ),
    238 	ALIASKEY( "KP_DEL", KP_DOT ),
    239 	ALIASKEY( "KP_NUMLOCK", NUMLOCK ),
    240 
    241 	ALIASKEY( "-", MINUS ),
    242 	ALIASKEY( "=", EQUALS ),
    243 	ALIASKEY( "[", LBRACKET ),
    244 	ALIASKEY( "]", RBRACKET ),
    245 	ALIASKEY( "\\", BACKSLASH ),
    246 	ALIASKEY( "/", SLASH ),
    247 	ALIASKEY( ",", COMMA ),
    248 	ALIASKEY( ".", PERIOD ),
    249 
    250 	{K_NONE, NULL, NULL}
    251 };
    252 
    253 class idKey {
    254 public:
    255 					idKey() { down = false; repeats = 0; usercmdAction = 0; }
    256 	bool			down;
    257 	int				repeats;		// if > 1, it is autorepeating
    258 	idStr			binding;
    259 	int				usercmdAction;	// for testing by the asyncronous usercmd generation
    260 };
    261 
    262 bool		key_overstrikeMode = false;
    263 idKey *		keys = NULL;
    264 
    265 
    266 /*
    267 ===================
    268 idKeyInput::ArgCompletion_KeyName
    269 ===================
    270 */
    271 void idKeyInput::ArgCompletion_KeyName( const idCmdArgs &args, void(*callback)( const char *s ) ) {
    272 	for ( keyname_t * kn = keynames; kn->name; kn++ ) {
    273 		callback( va( "%s %s", args.Argv( 0 ), kn->name ) );
    274 	}
    275 }
    276 
    277 /*
    278 ===================
    279 idKeyInput::GetOverstrikeMode
    280 ===================
    281 */
    282 bool idKeyInput::GetOverstrikeMode() {
    283 	return key_overstrikeMode;
    284 }
    285 
    286 /*
    287 ===================
    288 idKeyInput::SetOverstrikeMode
    289 ===================
    290 */
    291 void idKeyInput::SetOverstrikeMode( bool state ) {
    292 	key_overstrikeMode = state;
    293 }
    294 
    295 /*
    296 ===================
    297 idKeyInput::IsDown
    298 ===================
    299 */
    300 bool idKeyInput::IsDown( int keynum ) {
    301 	if ( keynum == -1 ) {
    302 		return false;
    303 	}
    304 
    305 	return keys[keynum].down;
    306 }
    307 
    308 /*
    309 ========================
    310 idKeyInput::StringToKeyNum
    311 ========================
    312 */
    313 keyNum_t idKeyInput::StringToKeyNum( const char * str ) {
    314 
    315 	if ( !str || !str[0] ) {
    316 		return K_NONE;
    317 	}
    318 
    319 	// scan for a text match
    320 	for ( keyname_t * kn = keynames; kn->name; kn++ ) {
    321 		if ( !idStr::Icmp( str, kn->name ) ) {
    322 			return kn->keynum;
    323 		}
    324 	}
    325 
    326 	return K_NONE;
    327 }
    328 
    329 /*
    330 ========================
    331 idKeyInput::KeyNumToString
    332 ========================
    333 */
    334 const char * idKeyInput::KeyNumToString( keyNum_t keynum ) {
    335 	// check for a key string
    336 	for ( keyname_t * kn = keynames; kn->name; kn++ ) {
    337 		if ( keynum == kn->keynum ) {
    338 			return kn->name;
    339 		}
    340 	}
    341 	return "?";
    342 }
    343 
    344 
    345 /*
    346 ========================
    347 idKeyInput::LocalizedKeyName
    348 ========================
    349 */
    350 const char * idKeyInput::LocalizedKeyName( keyNum_t keynum ) {
    351 	if ( keynum < K_JOY1 ) {
    352 		// On the PC, we want to turn the scan code in to a key label that matches the currently selected keyboard layout
    353 		unsigned char keystate[256] = { 0 };
    354 		WCHAR temp[5];
    355 
    356 		int scancode = (int)keynum;
    357 		int vkey = MapVirtualKey( keynum, MAPVK_VSC_TO_VK_EX );
    358 		int result = -1;
    359 		while ( result < 0 ) {
    360 			result = ToUnicode( vkey, scancode, keystate, temp, sizeof( temp ) / sizeof( temp[0] ), 0 );
    361 		}
    362 		if ( result > 0 && temp[0] > ' ' && iswprint( temp[0] ) ) {
    363 			static idStr bindStr;
    364 			bindStr.Empty();
    365 			bindStr.AppendUTF8Char( temp[0] );
    366 			return bindStr;
    367 		}
    368 	}
    369 
    370 	// check for a key string
    371 	for ( keyname_t * kn = keynames; kn->name; kn++ ) {
    372 		if ( keynum == kn->keynum ) {
    373 			return idLocalization::GetString( kn->strId );
    374 		}
    375 	}
    376 	return "????";
    377 }
    378 
    379 /*
    380 ===================
    381 idKeyInput::SetBinding
    382 ===================
    383 */
    384 void idKeyInput::SetBinding( int keynum, const char *binding ) {
    385 	if ( keynum == -1 ) {
    386 		return;
    387 	}
    388 
    389 	// Clear out all button states so we aren't stuck forever thinking this key is held down
    390 	usercmdGen->Clear();
    391 
    392 	// allocate memory for new binding
    393 	keys[keynum].binding = binding;
    394 
    395 	// find the action for the async command generation
    396 	keys[keynum].usercmdAction = usercmdGen->CommandStringUsercmdData( binding );
    397 
    398 	// consider this like modifying an archived cvar, so the
    399 	// file write will be triggered at the next oportunity
    400 	cvarSystem->SetModifiedFlags( CVAR_ARCHIVE );
    401 }
    402 
    403 
    404 /*
    405 ===================
    406 idKeyInput::GetBinding
    407 ===================
    408 */
    409 const char *idKeyInput::GetBinding( int keynum ) {
    410 	if ( keynum == -1 ) {
    411 		return "";
    412 	}
    413 
    414 	return keys[ keynum ].binding;
    415 }
    416 
    417 /*
    418 ===================
    419 idKeyInput::GetUsercmdAction
    420 ===================
    421 */
    422 int idKeyInput::GetUsercmdAction( int keynum ) {
    423 	return keys[ keynum ].usercmdAction;
    424 }
    425 
    426 /*
    427 ===================
    428 Key_Unbind_f
    429 ===================
    430 */
    431 void Key_Unbind_f( const idCmdArgs &args ) {
    432 	int		b;
    433 
    434 	if ( args.Argc() != 2 ) {
    435 		common->Printf( "unbind <key> : remove commands from a key\n" );
    436 		return;
    437 	}
    438 	
    439 	b = idKeyInput::StringToKeyNum( args.Argv(1) );
    440 	if ( b == -1 ) {
    441 		// If it wasn't a key, it could be a command
    442 		if ( !idKeyInput::UnbindBinding( args.Argv(1) ) ) {
    443 			common->Printf( "\"%s\" isn't a valid key\n", args.Argv(1) );
    444 		}
    445 	} else {
    446 		idKeyInput::SetBinding( b, "" );
    447 	}
    448 }
    449 
    450 /*
    451 ===================
    452 Key_Unbindall_f
    453 ===================
    454 */
    455 void Key_Unbindall_f( const idCmdArgs &args ) {
    456 	for ( int i = 0; i < K_LAST_KEY; i++ ) {
    457 		idKeyInput::SetBinding( i, "" );
    458 	}
    459 }
    460 
    461 /*
    462 ===================
    463 Key_Bind_f
    464 ===================
    465 */
    466 void Key_Bind_f( const idCmdArgs &args ) {
    467 	int			i, c, b;
    468 	char		cmd[MAX_STRING_CHARS];
    469 	
    470 	c = args.Argc();
    471 
    472 	if ( c < 2 ) {
    473 		common->Printf( "bind <key> [command] : attach a command to a key\n" );
    474 		return;
    475 	}
    476 	b = idKeyInput::StringToKeyNum( args.Argv(1) );
    477 	if ( b == -1 ) {
    478 		common->Printf( "\"%s\" isn't a valid key\n", args.Argv(1) );
    479 		return;
    480 	}
    481 
    482 	if ( c == 2 ) {
    483 		if ( keys[b].binding.Length() ) {
    484 			common->Printf( "\"%s\" = \"%s\"\n", args.Argv(1), keys[b].binding.c_str() );
    485 		}
    486 		else {
    487 			common->Printf( "\"%s\" is not bound\n", args.Argv(1) );
    488 		}
    489 		return;
    490 	}
    491 	
    492 	// copy the rest of the command line
    493 	cmd[0] = 0;		// start out with a null string
    494 	for ( i = 2; i < c; i++ ) {
    495 		strcat( cmd, args.Argv( i ) );
    496 		if ( i != (c-1) ) {
    497 			strcat( cmd, " " );
    498 		}
    499 	}
    500 
    501 	idKeyInput::SetBinding( b, cmd );
    502 }
    503 
    504 /*
    505 ============
    506 Key_BindUnBindTwo_f
    507 
    508 binds keynum to bindcommand and unbinds if there are already two binds on the key
    509 ============
    510 */
    511 void Key_BindUnBindTwo_f( const idCmdArgs &args ) {
    512 	int c = args.Argc();
    513 	if ( c < 3 ) {
    514 		common->Printf( "bindunbindtwo <keynum> [command]\n" );
    515 		return;
    516 	}
    517 	int key = atoi( args.Argv( 1 ) );
    518 	idStr bind = args.Argv( 2 );
    519 	if ( idKeyInput::NumBinds( bind ) >= 2 && !idKeyInput::KeyIsBoundTo( key, bind ) ) {
    520 		idKeyInput::UnbindBinding( bind );
    521 	}
    522 	idKeyInput::SetBinding( key, bind );
    523 }
    524 
    525 
    526 
    527 /*
    528 ============
    529 idKeyInput::WriteBindings
    530 
    531 Writes lines containing "bind key value"
    532 ============
    533 */
    534 void idKeyInput::WriteBindings( idFile *f ) {
    535 	f->Printf( "unbindall\n" );
    536 
    537 	for ( int i = 0; i < K_LAST_KEY; i++ ) {
    538 		if ( keys[i].binding.Length() ) {
    539 			const char *name = KeyNumToString( (keyNum_t)i );
    540 			f->Printf( "bind \"%s\" \"%s\"\n", name, keys[i].binding.c_str() );
    541 		}
    542 	}
    543 }
    544 
    545 /*
    546 ============
    547 Key_ListBinds_f
    548 ============
    549 */
    550 void Key_ListBinds_f( const idCmdArgs &args ) {
    551 	for ( int i = 0; i < K_LAST_KEY; i++ ) {
    552 		if ( keys[i].binding.Length() ) {
    553 			common->Printf( "%s \"%s\"\n", idKeyInput::KeyNumToString( (keyNum_t)i ), keys[i].binding.c_str() );
    554 		}
    555 	}
    556 }
    557 
    558 /*
    559 ============
    560 idKeyInput::KeysFromBinding
    561 returns the localized name of the key for the binding
    562 ============
    563 */
    564 const char *idKeyInput::KeysFromBinding( const char *bind ) {
    565 	static char keyName[MAX_STRING_CHARS];
    566 	keyName[0] = 0;
    567 
    568 	if ( bind && *bind ) {
    569 		for ( int i = 0; i < K_LAST_KEY; i++ ) {
    570 			if ( keys[i].binding.Icmp( bind ) == 0 ) {
    571 				if ( keyName[0] != '\0' ) {
    572 					idStr::Append( keyName, sizeof( keyName ), idLocalization::GetString( "#str_07183" ) );
    573 				} 
    574 				idStr::Append( keyName, sizeof( keyName ), LocalizedKeyName( (keyNum_t)i ) );
    575 			}
    576 		}
    577 	}
    578 	if ( keyName[0] == '\0' ) {
    579 		idStr::Copynz( keyName, idLocalization::GetString( "#str_07133" ), sizeof( keyName ) );
    580 	}
    581 	idStr::ToLower( keyName );
    582 	return keyName;
    583 }
    584 
    585 /*
    586 ========================
    587 idKeyInput::KeyBindingsFromBinding
    588 
    589 return: bindings for keyboard mouse and gamepad
    590 ========================
    591 */
    592 keyBindings_t idKeyInput::KeyBindingsFromBinding( const char * bind, bool firstOnly, bool localized ) {
    593 	idStr keyboard;
    594 	idStr mouse;
    595 	idStr gamepad;
    596 
    597 	if ( bind && *bind ) {
    598 		for ( int i = 0; i < K_LAST_KEY; i++ ) {
    599 			if ( keys[i].binding.Icmp( bind ) == 0 ) {
    600 				if ( i >= K_JOY1 && i <= K_JOY_DPAD_RIGHT ) {
    601 					const char * gamepadKey = ""; 
    602 					if ( localized ) {
    603 						gamepadKey = LocalizedKeyName( (keyNum_t)i );
    604 					} else {
    605 						gamepadKey = KeyNumToString( (keyNum_t)i );
    606 					}
    607 					if ( idStr::Icmp( gamepadKey, "" ) != 0 ) {
    608 						if ( !gamepad.IsEmpty() ) {
    609 							if ( firstOnly ) {
    610 								continue;
    611 							}
    612 							gamepad.Append( ", " );
    613 						}
    614 						gamepad.Append( gamepadKey );
    615 					}
    616 				} else if ( i >= K_MOUSE1 && i <= K_MWHEELUP ) {
    617 					const char * mouseKey = ""; 
    618 					if ( localized ) {
    619 						mouseKey = LocalizedKeyName( (keyNum_t)i );
    620 					} else {
    621 						mouseKey = KeyNumToString( (keyNum_t)i );
    622 					}
    623 					if ( idStr::Icmp( mouseKey, "" ) != 0 ) {
    624 						if ( !mouse.IsEmpty() ) {
    625 							if ( firstOnly ) {
    626 								continue;
    627 							}
    628 							mouse.Append( ", " );
    629 						}
    630 						mouse.Append( mouseKey );
    631 					}
    632 				} else {
    633 					const char * tmp = ""; 
    634 					if ( localized ) {
    635 						tmp = LocalizedKeyName( (keyNum_t)i );
    636 					} else {
    637 						tmp = KeyNumToString( (keyNum_t)i );
    638 					}
    639 					if ( idStr::Icmp( tmp, "" ) != 0 && idStr::Icmp( tmp, keyboard ) != 0 ) {
    640 						if ( !keyboard.IsEmpty() ) {
    641 							if ( firstOnly ) {
    642 								continue;
    643 							}
    644 							keyboard.Append( ", " );
    645 						}
    646 						keyboard.Append( tmp );
    647 					}
    648 				}
    649 			}
    650 		}
    651 	}
    652 
    653 	keyBindings_t bindings;
    654 	bindings.gamepad = gamepad;
    655 	bindings.mouse = mouse;
    656 	bindings.keyboard = keyboard;
    657 
    658 	return bindings;
    659 }
    660 
    661 /*
    662 ============
    663 idKeyInput::BindingFromKey
    664 returns the binding for the localized name of the key
    665 ============
    666 */
    667 const char * idKeyInput::BindingFromKey( const char *key ) {
    668 	const int keyNum = idKeyInput::StringToKeyNum( key );
    669 	if ( keyNum < 0 || keyNum >= K_LAST_KEY ) {
    670 		return NULL;
    671 	}
    672 	return keys[keyNum].binding.c_str();
    673 }
    674 
    675 /*
    676 ============
    677 idKeyInput::UnbindBinding
    678 ============
    679 */
    680 bool idKeyInput::UnbindBinding( const char *binding ) {
    681 	bool unbound = false;
    682 	if ( binding && *binding ) {
    683 		for ( int i = 0; i < K_LAST_KEY; i++ ) {
    684 			if ( keys[i].binding.Icmp( binding ) == 0 ) {
    685 				SetBinding( i, "" );
    686 				unbound = true;
    687 			}
    688 		}
    689 	}
    690 	return unbound;
    691 }
    692 
    693 /*
    694 ============
    695 idKeyInput::NumBinds
    696 ============
    697 */
    698 int idKeyInput::NumBinds( const char *binding ) {
    699 	int count = 0;
    700 
    701 	if ( binding && *binding ) {
    702 		for ( int i = 0; i < K_LAST_KEY; i++ ) {
    703 			if ( keys[i].binding.Icmp( binding ) == 0 ) {
    704 				count++;
    705 			}
    706 		}
    707 	}
    708 	return count;
    709 }
    710 
    711 /*
    712 ============
    713 idKeyInput::KeyIsBountTo
    714 ============
    715 */
    716 bool idKeyInput::KeyIsBoundTo( int keynum, const char *binding ) {
    717 	if ( keynum >= 0 && keynum < K_LAST_KEY ) {
    718 		return ( keys[keynum].binding.Icmp( binding ) == 0 );
    719 	}
    720 	return false;
    721 }
    722 
    723 /*
    724 ===================
    725 idKeyInput::PreliminaryKeyEvent
    726 
    727 Tracks global key up/down state
    728 Called by the system for both key up and key down events
    729 ===================
    730 */
    731 void idKeyInput::PreliminaryKeyEvent( int keynum, bool down ) {
    732 	keys[keynum].down = down;
    733 }
    734 
    735 /*
    736 =================
    737 idKeyInput::ExecKeyBinding
    738 =================
    739 */
    740 bool idKeyInput::ExecKeyBinding( int keynum ) {
    741 	// commands that are used by the async thread
    742 	// don't add text
    743 	if ( keys[keynum].usercmdAction ) {
    744 		return false;
    745 	}
    746 
    747 	// send the bound action
    748 	if ( keys[keynum].binding.Length() ) {
    749 		cmdSystem->BufferCommandText( CMD_EXEC_APPEND, keys[keynum].binding.c_str() );
    750 		cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" );
    751 	}
    752 	return true;
    753 }
    754 
    755 /*
    756 ===================
    757 idKeyInput::ClearStates
    758 ===================
    759 */
    760 void idKeyInput::ClearStates() {
    761 	for ( int i = 0; i < K_LAST_KEY; i++ ) {
    762 		if ( keys[i].down ) {
    763 			PreliminaryKeyEvent( i, false );
    764 		}
    765 		keys[i].down = false;
    766 	}
    767 
    768 	// clear the usercommand states
    769 	usercmdGen->Clear();
    770 }
    771 
    772 /*
    773 ===================
    774 idKeyInput::Init
    775 ===================
    776 */
    777 void idKeyInput::Init() {
    778 
    779 	keys = new (TAG_SYSTEM) idKey[K_LAST_KEY];
    780 
    781 	// register our functions
    782 	cmdSystem->AddCommand( "bind", Key_Bind_f, CMD_FL_SYSTEM, "binds a command to a key", idKeyInput::ArgCompletion_KeyName );
    783 	cmdSystem->AddCommand( "bindunbindtwo", Key_BindUnBindTwo_f, CMD_FL_SYSTEM, "binds a key but unbinds it first if there are more than two binds" );
    784 	cmdSystem->AddCommand( "unbind", Key_Unbind_f, CMD_FL_SYSTEM, "unbinds any command from a key", idKeyInput::ArgCompletion_KeyName );
    785 	cmdSystem->AddCommand( "unbindall", Key_Unbindall_f, CMD_FL_SYSTEM, "unbinds any commands from all keys" );
    786 	cmdSystem->AddCommand( "listBinds", Key_ListBinds_f, CMD_FL_SYSTEM, "lists key bindings" );
    787 }
    788 
    789 /*
    790 ===================
    791 idKeyInput::Shutdown
    792 ===================
    793 */
    794 void idKeyInput::Shutdown() {
    795 	delete [] keys;
    796 	keys = NULL;
    797 }
    798 
    799 
    800 /*
    801 ========================
    802 Key_CovertHIDCode
    803 Converts from a USB HID code to a K_ code
    804 ========================
    805 */
    806 int Key_CovertHIDCode( int hid ) {
    807 	if ( hid >= 0 && hid <= 106 ) {
    808 		int table[] = {
    809 			K_NONE, K_NONE, K_NONE, K_NONE,
    810 			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,
    811 			K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9, K_0,
    812 			K_ENTER, K_ESCAPE, K_BACKSPACE, K_TAB, K_SPACE,
    813 			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,
    814 			K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, K_F7, K_F8, K_F9, K_F10, K_F11, K_F12,
    815 			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,
    816 			K_NUMLOCK, K_KP_SLASH, K_KP_STAR, K_KP_MINUS, K_KP_PLUS, K_KP_ENTER,
    817 			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,
    818 			K_NONE, K_APPS, K_POWER, K_KP_EQUALS,
    819 			K_F13, K_F14, K_F15
    820 		};
    821 		return table[hid];
    822 	}
    823 	if ( hid >= 224 && hid <= 231 ) {
    824 		int table[] = {
    825 			K_LCTRL, K_LSHIFT, K_LALT, K_LWIN,
    826 			K_RCTRL, K_RSHIFT, K_RALT, K_RWIN
    827 		};
    828 		return table[hid - 224];
    829 	}
    830 	return K_NONE;
    831 }