1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20#include "quakedef.h" 21 22/* 23 24key up events are sent even if in console mode 25 26*/ 27 28 29#define MAXCMDLINE 256 30char key_lines[32][MAXCMDLINE]; 31int key_linepos; 32int shift_down=false; 33int key_lastpress; 34 35int edit_line=0; 36int history_line=0; 37 38keydest_t key_dest; 39 40int key_count; // incremented every key event 41 42char *keybindings[256]; 43qboolean consolekeys[256]; // if true, can't be rebound while in console 44qboolean menubound[256]; // if true, can't be rebound while in menu 45int keyshift[256]; // key to map to if shift held down in console 46int key_repeats[256]; // if > 1, it is autorepeating 47qboolean keydown[256]; 48 49typedef struct 50{ 51 const char *name; 52 int keynum; 53} keyname_t; 54 55keyname_t keynames[] = 56{ 57 {"TAB", K_TAB}, 58 {"ENTER", K_ENTER}, 59 {"ESCAPE", K_ESCAPE}, 60 {"SPACE", K_SPACE}, 61 {"BACKSPACE", K_BACKSPACE}, 62 {"UPARROW", K_UPARROW}, 63 {"DOWNARROW", K_DOWNARROW}, 64 {"LEFTARROW", K_LEFTARROW}, 65 {"RIGHTARROW", K_RIGHTARROW}, 66 67 {"ALT", K_ALT}, 68 {"CTRL", K_CTRL}, 69 {"SHIFT", K_SHIFT}, 70 71 {"F1", K_F1}, 72 {"F2", K_F2}, 73 {"F3", K_F3}, 74 {"F4", K_F4}, 75 {"F5", K_F5}, 76 {"F6", K_F6}, 77 {"F7", K_F7}, 78 {"F8", K_F8}, 79 {"F9", K_F9}, 80 {"F10", K_F10}, 81 {"F11", K_F11}, 82 {"F12", K_F12}, 83 84 {"INS", K_INS}, 85 {"DEL", K_DEL}, 86 {"PGDN", K_PGDN}, 87 {"PGUP", K_PGUP}, 88 {"HOME", K_HOME}, 89 {"END", K_END}, 90 91 {"MOUSE1", K_MOUSE1}, 92 {"MOUSE2", K_MOUSE2}, 93 {"MOUSE3", K_MOUSE3}, 94 95 {"JOY1", K_JOY1}, 96 {"JOY2", K_JOY2}, 97 {"JOY3", K_JOY3}, 98 {"JOY4", K_JOY4}, 99 100 {"AUX1", K_AUX1}, 101 {"AUX2", K_AUX2}, 102 {"AUX3", K_AUX3}, 103 {"AUX4", K_AUX4}, 104 {"AUX5", K_AUX5}, 105 {"AUX6", K_AUX6}, 106 {"AUX7", K_AUX7}, 107 {"AUX8", K_AUX8}, 108 {"AUX9", K_AUX9}, 109 {"AUX10", K_AUX10}, 110 {"AUX11", K_AUX11}, 111 {"AUX12", K_AUX12}, 112 {"AUX13", K_AUX13}, 113 {"AUX14", K_AUX14}, 114 {"AUX15", K_AUX15}, 115 {"AUX16", K_AUX16}, 116 {"AUX17", K_AUX17}, 117 {"AUX18", K_AUX18}, 118 {"AUX19", K_AUX19}, 119 {"AUX20", K_AUX20}, 120 {"AUX21", K_AUX21}, 121 {"AUX22", K_AUX22}, 122 {"AUX23", K_AUX23}, 123 {"AUX24", K_AUX24}, 124 {"AUX25", K_AUX25}, 125 {"AUX26", K_AUX26}, 126 {"AUX27", K_AUX27}, 127 {"AUX28", K_AUX28}, 128 {"AUX29", K_AUX29}, 129 {"AUX30", K_AUX30}, 130 {"AUX31", K_AUX31}, 131 {"AUX32", K_AUX32}, 132 133 {"PAUSE", K_PAUSE}, 134 135 {"MWHEELUP", K_MWHEELUP}, 136 {"MWHEELDOWN", K_MWHEELDOWN}, 137 138 {"SEMICOLON", ';'}, // because a raw semicolon seperates commands 139 140 {NULL,0} 141}; 142 143/* 144============================================================================== 145 146 LINE TYPING INTO THE CONSOLE 147 148============================================================================== 149*/ 150 151 152/* 153==================== 154Key_Console 155 156Interactive line editing and console scrollback 157==================== 158*/ 159void Key_Console (int key) 160{ 161 const char *cmd; 162 163 if (key == K_ENTER) 164 { 165 Cbuf_AddText (key_lines[edit_line]+1); // skip the > 166 Cbuf_AddText ("\n"); 167 Con_Printf ("%s\n",key_lines[edit_line]); 168 edit_line = (edit_line + 1) & 31; 169 history_line = edit_line; 170 key_lines[edit_line][0] = ']'; 171 key_linepos = 1; 172 if (cls.state == ca_disconnected) 173 SCR_UpdateScreen (); // force an update, because the command 174 // may take some time 175 return; 176 } 177 178 if (key == K_TAB) 179 { // command completion 180 cmd = Cmd_CompleteCommand (key_lines[edit_line]+1); 181 if (!cmd) 182 cmd = Cvar_CompleteVariable (key_lines[edit_line]+1); 183 if (cmd) 184 { 185 Q_strcpy (key_lines[edit_line]+1, cmd); 186 key_linepos = Q_strlen(cmd)+1; 187 key_lines[edit_line][key_linepos] = ' '; 188 key_linepos++; 189 key_lines[edit_line][key_linepos] = 0; 190 return; 191 } 192 } 193 194 if (key == K_BACKSPACE || key == K_LEFTARROW) 195 { 196 if (key_linepos > 1) 197 key_linepos--; 198 return; 199 } 200 201 if (key == K_UPARROW) 202 { 203 do 204 { 205 history_line = (history_line - 1) & 31; 206 } while (history_line != edit_line 207 && !key_lines[history_line][1]); 208 if (history_line == edit_line) 209 history_line = (edit_line+1)&31; 210 Q_strcpy(key_lines[edit_line], key_lines[history_line]); 211 key_linepos = Q_strlen(key_lines[edit_line]); 212 return; 213 } 214 215 if (key == K_DOWNARROW) 216 { 217 if (history_line == edit_line) return; 218 do 219 { 220 history_line = (history_line + 1) & 31; 221 } 222 while (history_line != edit_line 223 && !key_lines[history_line][1]); 224 if (history_line == edit_line) 225 { 226 key_lines[edit_line][0] = ']'; 227 key_linepos = 1; 228 } 229 else 230 { 231 Q_strcpy(key_lines[edit_line], key_lines[history_line]); 232 key_linepos = Q_strlen(key_lines[edit_line]); 233 } 234 return; 235 } 236 237 if (key == K_PGUP || key==K_MWHEELUP) 238 { 239 con_backscroll += 2; 240 if (con_backscroll > (int)(con_totallines - (vid.height>>3) - 1)) 241 con_backscroll = (int)(con_totallines - (vid.height>>3) - 1); 242 return; 243 } 244 245 if (key == K_PGDN || key==K_MWHEELDOWN) 246 { 247 con_backscroll -= 2; 248 if (con_backscroll < 0) 249 con_backscroll = 0; 250 return; 251 } 252 253 if (key == K_HOME) 254 { 255 con_backscroll = con_totallines - (vid.height>>3) - 1; 256 return; 257 } 258 259 if (key == K_END) 260 { 261 con_backscroll = 0; 262 return; 263 } 264 265 if (key < 32 || key > 127) 266 return; // non printable 267 268 if (key_linepos < MAXCMDLINE-1) 269 { 270 key_lines[edit_line][key_linepos] = key; 271 key_linepos++; 272 key_lines[edit_line][key_linepos] = 0; 273 } 274 275} 276 277//============================================================================ 278 279char chat_buffer[32]; 280qboolean team_message = false; 281 282void Key_Message (int key) 283{ 284 static int chat_bufferlen = 0; 285 286 if (key == K_ENTER) 287 { 288 if (team_message) 289 Cbuf_AddText ("say_team \""); 290 else 291 Cbuf_AddText ("say \""); 292 Cbuf_AddText(chat_buffer); 293 Cbuf_AddText("\"\n"); 294 295 key_dest = key_game; 296 chat_bufferlen = 0; 297 chat_buffer[0] = 0; 298 return; 299 } 300 301 if (key == K_ESCAPE) 302 { 303 key_dest = key_game; 304 chat_bufferlen = 0; 305 chat_buffer[0] = 0; 306 return; 307 } 308 309 if (key < 32 || key > 127) 310 return; // non printable 311 312 if (key == K_BACKSPACE) 313 { 314 if (chat_bufferlen) 315 { 316 chat_bufferlen--; 317 chat_buffer[chat_bufferlen] = 0; 318 } 319 return; 320 } 321 322 if (chat_bufferlen == 31) 323 return; // all full 324 325 chat_buffer[chat_bufferlen++] = key; 326 chat_buffer[chat_bufferlen] = 0; 327} 328 329//============================================================================ 330 331 332/* 333=================== 334Key_StringToKeynum 335 336Returns a key number to be used to index keybindings[] by looking at 337the given string. Single ascii characters return themselves, while 338the K_* names are matched up. 339=================== 340*/ 341int Key_StringToKeynum (char *str) 342{ 343 keyname_t *kn; 344 345 if (!str || !str[0]) 346 return -1; 347 if (!str[1]) 348 return str[0]; 349 350 for (kn=keynames ; kn->name ; kn++) 351 { 352 if (!Q_strcasecmp(str,kn->name)) 353 return kn->keynum; 354 } 355 return -1; 356} 357 358/* 359=================== 360Key_KeynumToString 361 362Returns a string (either a single ascii char, or a K_* name) for the 363given keynum. 364FIXME: handle quote special (general escape sequence?) 365=================== 366*/ 367const char *Key_KeynumToString (int keynum) 368{ 369 keyname_t *kn; 370 static char tinystr[2]; 371 372 if (keynum == -1) 373 return "<KEY NOT FOUND>"; 374 if (keynum > 32 && keynum < 127) 375 { // printable ascii 376 tinystr[0] = keynum; 377 tinystr[1] = 0; 378 return tinystr; 379 } 380 381 for (kn=keynames ; kn->name ; kn++) 382 if (keynum == kn->keynum) 383 return kn->name; 384 385 return "<UNKNOWN KEYNUM>"; 386} 387 388 389/* 390=================== 391Key_SetBinding 392=================== 393*/ 394void Key_SetBinding (int keynum, const char *binding) 395{ 396 char *newKey; 397 int l; 398 399 if (keynum == -1) 400 return; 401 402// free old bindings 403 if (keybindings[keynum]) 404 { 405 Z_Free (keybindings[keynum]); 406 keybindings[keynum] = NULL; 407 } 408 409// allocate memory for new binding 410 l = Q_strlen (binding); 411 newKey = (char*) Z_Malloc (l+1); 412 Q_strcpy (newKey, binding); 413 newKey[l] = 0; 414 keybindings[keynum] = newKey; 415} 416 417/* 418=================== 419Key_Unbind_f 420=================== 421*/ 422void Key_Unbind_f (void) 423{ 424 int b; 425 426 if (Cmd_Argc() != 2) 427 { 428 Con_Printf ("unbind <key> : remove commands from a key\n"); 429 return; 430 } 431 432 b = Key_StringToKeynum (Cmd_Argv(1)); 433 if (b==-1) 434 { 435 Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); 436 return; 437 } 438 439 Key_SetBinding (b, ""); 440} 441 442void Key_Unbindall_f (void) 443{ 444 int i; 445 446 for (i=0 ; i<256 ; i++) 447 if (keybindings[i]) 448 Key_SetBinding (i, ""); 449} 450 451 452/* 453=================== 454Key_Bind_f 455=================== 456*/ 457void Key_Bind_f (void) 458{ 459 int i, c, b; 460 char cmd[1024]; 461 462 c = Cmd_Argc(); 463 464 if (c != 2 && c != 3) 465 { 466 Con_Printf ("bind <key> [command] : attach a command to a key\n"); 467 return; 468 } 469 b = Key_StringToKeynum (Cmd_Argv(1)); 470 if (b==-1) 471 { 472 Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); 473 return; 474 } 475 476 if (c == 2) 477 { 478 if (keybindings[b]) 479 Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] ); 480 else 481 Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); 482 return; 483 } 484 485// copy the rest of the command line 486 cmd[0] = 0; // start out with a null string 487 for (i=2 ; i< c ; i++) 488 { 489 if (i > 2) 490 strcat (cmd, " "); 491 strcat (cmd, Cmd_Argv(i)); 492 } 493 494 Key_SetBinding (b, cmd); 495} 496 497/* 498============ 499Key_WriteBindings 500 501Writes lines containing "bind key value" 502============ 503*/ 504void Key_WriteBindings (FILE *f) 505{ 506 int i; 507 508 for (i=0 ; i<256 ; i++) 509 if (keybindings[i]) 510 if (*keybindings[i]) 511 fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]); 512} 513 514 515/* 516=================== 517Key_Init 518=================== 519*/ 520void Key_Init (void) 521{ 522 int i; 523 524 for (i=0 ; i<32 ; i++) 525 { 526 key_lines[i][0] = ']'; 527 key_lines[i][1] = 0; 528 } 529 key_linepos = 1; 530 531// 532// init ascii characters in console mode 533// 534 for (i=32 ; i<128 ; i++) 535 consolekeys[i] = true; 536 consolekeys[K_ENTER] = true; 537 consolekeys[K_TAB] = true; 538 consolekeys[K_LEFTARROW] = true; 539 consolekeys[K_RIGHTARROW] = true; 540 consolekeys[K_UPARROW] = true; 541 consolekeys[K_DOWNARROW] = true; 542 consolekeys[K_BACKSPACE] = true; 543 consolekeys[K_PGUP] = true; 544 consolekeys[K_PGDN] = true; 545 consolekeys[K_SHIFT] = true; 546 consolekeys[K_MWHEELUP] = true; 547 consolekeys[K_MWHEELDOWN] = true; 548 consolekeys[(unsigned int) '`'] = false; 549 consolekeys[(unsigned int) '~'] = false; 550 551 for (i=0 ; i<256 ; i++) 552 keyshift[i] = i; 553 for (i='a' ; i<='z' ; i++) 554 keyshift[i] = i - 'a' + 'A'; 555 keyshift[(unsigned int) '1'] = '!'; 556 keyshift[(unsigned int) '2'] = '@'; 557 keyshift[(unsigned int) '3'] = '#'; 558 keyshift[(unsigned int) '4'] = '$'; 559 keyshift[(unsigned int) '5'] = '%'; 560 keyshift[(unsigned int) '6'] = '^'; 561 keyshift[(unsigned int) '7'] = '&'; 562 keyshift[(unsigned int) '8'] = '*'; 563 keyshift[(unsigned int) '9'] = '('; 564 keyshift[(unsigned int) '0'] = ')'; 565 keyshift[(unsigned int) '-'] = '_'; 566 keyshift[(unsigned int) '='] = '+'; 567 keyshift[(unsigned int) ','] = '<'; 568 keyshift[(unsigned int) '.'] = '>'; 569 keyshift[(unsigned int) '/'] = '?'; 570 keyshift[(unsigned int) ';'] = ':'; 571 keyshift[(unsigned int) '\''] = '"'; 572 keyshift[(unsigned int) '['] = '{'; 573 keyshift[(unsigned int) ']'] = '}'; 574 keyshift[(unsigned int) '`'] = '~'; 575 keyshift[(unsigned int) '\\'] = '|'; 576 577 menubound[K_ESCAPE] = true; 578 for (i=0 ; i<12 ; i++) 579 menubound[K_F1+i] = true; 580 581// 582// register our functions 583// 584 Cmd_AddCommand ("bind",Key_Bind_f); 585 Cmd_AddCommand ("unbind",Key_Unbind_f); 586 Cmd_AddCommand ("unbindall",Key_Unbindall_f); 587 588 589} 590 591/* 592=================== 593Key_Event 594 595Called by the system between frames for both key up and key down events 596Should NOT be called during an interrupt! 597=================== 598*/ 599void Key_Event (int key, qboolean down) 600{ 601 char *kb; 602 char cmd[1024]; 603 604 keydown[key] = down; 605 606 if (!down) 607 key_repeats[key] = 0; 608 609 key_lastpress = key; 610 key_count++; 611 if (key_count <= 0) 612 { 613 return; // just catching keys for Con_NotifyBox 614 } 615 616// update auto-repeat status 617 if (down) 618 { 619 key_repeats[key]++; 620 if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1) 621 { 622 return; // ignore most autorepeats 623 } 624 625 if (key >= 200 && !keybindings[key]) 626 Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) ); 627 } 628 629 if (key == K_SHIFT) 630 shift_down = down; 631 632// 633// handle escape specialy, so the user can never unbind it 634// 635 if (key == K_ESCAPE) 636 { 637 if (!down) 638 return; 639 switch (key_dest) 640 { 641 case key_message: 642 Key_Message (key); 643 break; 644 case key_menu: 645 M_Keydown (key); 646 break; 647 case key_game: 648 case key_console: 649 M_ToggleMenu_f (); 650 break; 651 default: 652 Sys_Error ("Bad key_dest"); 653 } 654 return; 655 } 656 657// 658// key up events only generate commands if the game key binding is 659// a button command (leading + sign). These will occur even in console mode, 660// to keep the character from continuing an action started before a console 661// switch. Button commands include the kenum as a parameter, so multiple 662// downs can be matched with ups 663// 664 if (!down) 665 { 666 kb = keybindings[key]; 667 if (kb && kb[0] == '+') 668 { 669 sprintf (cmd, "-%s %i\n", kb+1, key); 670 Cbuf_AddText (cmd); 671 } 672 if (keyshift[key] != key) 673 { 674 kb = keybindings[keyshift[key]]; 675 if (kb && kb[0] == '+') 676 { 677 sprintf (cmd, "-%s %i\n", kb+1, key); 678 Cbuf_AddText (cmd); 679 } 680 } 681 return; 682 } 683 684// 685// during demo playback, most keys bring up the main menu 686// 687 if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game) 688 { 689 M_ToggleMenu_f (); 690 return; 691 } 692 693// 694// if not a consolekey, send to the interpreter no matter what mode is 695// 696 if ( (key_dest == key_menu && menubound[key]) 697 || (key_dest == key_console && !consolekeys[key]) 698 || (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) ) 699 { 700 kb = keybindings[key]; 701 if (kb) 702 { 703 if (kb[0] == '+') 704 { // button commands add keynum as a parm 705 sprintf (cmd, "%s %i\n", kb, key); 706 Cbuf_AddText (cmd); 707 } 708 else 709 { 710 Cbuf_AddText (kb); 711 Cbuf_AddText ("\n"); 712 } 713 } 714 return; 715 } 716 717 if (!down) 718 return; // other systems only care about key down events 719 720 if (shift_down) 721 { 722 key = keyshift[key]; 723 } 724 725 switch (key_dest) 726 { 727 case key_message: 728 Key_Message (key); 729 break; 730 case key_menu: 731 M_Keydown (key); 732 break; 733 734 case key_game: 735 case key_console: 736 Key_Console (key); 737 break; 738 default: 739 Sys_Error ("Bad key_dest"); 740 } 741} 742 743 744/* 745=================== 746Key_ClearStates 747=================== 748*/ 749void Key_ClearStates (void) 750{ 751 int i; 752 753 for (i=0 ; i<256 ; i++) 754 { 755 keydown[i] = false; 756 key_repeats[i] = 0; 757 } 758} 759 760