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 }