1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "client.h"
26
27 /*
28
29 key up events are sent even if in console mode
30
31 */
32
33 char key_lines[32][MAXCMDLINE];
34 int key_linelen;
35 int key_linepos;
36 int shift_down=false;
37 int anykeydown;
38
39 int edit_line=0;
40 int history_line=0;
41
42 int key_waiting;
43 char *keybindings[256];
44 qboolean consolekeys[256]; // if true, can't be rebound while in console
45 qboolean menubound[256]; // if true, can't be rebound while in menu
46 int keyshift[256]; // key to map to if shift held down in console
47 int key_repeats[256]; // if > 1, it is autorepeating
48 qboolean keydown[256];
49
50 typedef struct
51 {
52 char *name;
53 int keynum;
54 } keyname_t;
55
56 keyname_t keynames[] =
57 {
58 {"TAB", K_TAB},
59 {"ENTER", K_ENTER},
60 {"ESCAPE", K_ESCAPE},
61 {"SPACE", K_SPACE},
62 {"BACKSPACE", K_BACKSPACE},
63 {"UPARROW", K_UPARROW},
64 {"DOWNARROW", K_DOWNARROW},
65 {"LEFTARROW", K_LEFTARROW},
66 {"RIGHTARROW", K_RIGHTARROW},
67
68 {"ALT", K_ALT},
69 {"CTRL", K_CTRL},
70 {"SHIFT", K_SHIFT},
71
72 {"F1", K_F1},
73 {"F2", K_F2},
74 {"F3", K_F3},
75 {"F4", K_F4},
76 {"F5", K_F5},
77 {"F6", K_F6},
78 {"F7", K_F7},
79 {"F8", K_F8},
80 {"F9", K_F9},
81 {"F10", K_F10},
82 {"F11", K_F11},
83 {"F12", K_F12},
84
85 {"INS", K_INS},
86 {"DEL", K_DEL},
87 {"PGDN", K_PGDN},
88 {"PGUP", K_PGUP},
89 {"HOME", K_HOME},
90 {"END", K_END},
91
92 {"MOUSE1", K_MOUSE1},
93 {"MOUSE2", K_MOUSE2},
94 {"MOUSE3", K_MOUSE3},
95 {"MOUSE4", K_MOUSE4},
96 {"MOUSE5", K_MOUSE5},
97 {"MOUSE6", K_MOUSE6},
98 {"MOUSE7", K_MOUSE7},
99 {"MOUSE8", K_MOUSE8},
100 {"MOUSE9", K_MOUSE9},
101
102 {"JOY1", K_JOY1},
103 {"JOY2", K_JOY2},
104 {"JOY3", K_JOY3},
105 {"JOY4", K_JOY4},
106
107 {"AUX1", K_AUX1},
108 {"AUX2", K_AUX2},
109 {"AUX3", K_AUX3},
110 {"AUX4", K_AUX4},
111 {"AUX5", K_AUX5},
112 {"AUX6", K_AUX6},
113 {"AUX7", K_AUX7},
114 {"AUX8", K_AUX8},
115 {"AUX9", K_AUX9},
116 {"AUX10", K_AUX10},
117 {"AUX11", K_AUX11},
118 {"AUX12", K_AUX12},
119 {"AUX13", K_AUX13},
120 {"AUX14", K_AUX14},
121 {"AUX15", K_AUX15},
122 {"AUX16", K_AUX16},
123 {"AUX17", K_AUX17},
124 {"AUX18", K_AUX18},
125 {"AUX19", K_AUX19},
126 {"AUX20", K_AUX20},
127 {"AUX21", K_AUX21},
128 {"AUX22", K_AUX22},
129 {"AUX23", K_AUX23},
130 {"AUX24", K_AUX24},
131 {"AUX25", K_AUX25},
132 {"AUX26", K_AUX26},
133 {"AUX27", K_AUX27},
134 {"AUX28", K_AUX28},
135 {"AUX29", K_AUX29},
136 {"AUX30", K_AUX30},
137 {"AUX31", K_AUX31},
138 {"AUX32", K_AUX32},
139
140 {"KP_HOME", K_KP_HOME },
141 {"KP_UPARROW", K_KP_UPARROW },
142 {"KP_PGUP", K_KP_PGUP },
143 {"KP_LEFTARROW", K_KP_LEFTARROW },
144 {"KP_5", K_KP_5 },
145 {"KP_RIGHTARROW", K_KP_RIGHTARROW },
146 {"KP_END", K_KP_END },
147 {"KP_DOWNARROW", K_KP_DOWNARROW },
148 {"KP_PGDN", K_KP_PGDN },
149 {"KP_ENTER", K_KP_ENTER },
150 {"KP_INS", K_KP_INS },
151 {"KP_DEL", K_KP_DEL },
152 {"KP_SLASH", K_KP_SLASH },
153 {"KP_MINUS", K_KP_MINUS },
154 {"KP_PLUS", K_KP_PLUS },
155
156 {"MWHEELUP", K_MWHEELUP },
157 {"MWHEELDOWN", K_MWHEELDOWN },
158
159 {"PAUSE", K_PAUSE},
160
161 {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
162
163 {NULL,0}
164 };
165
166 /*
167 ==============================================================================
168
169 LINE TYPING INTO THE CONSOLE
170
171 ==============================================================================
172 */
173
174
Key_ClearTyping(void)175 void Key_ClearTyping (void)
176 {
177 key_lines[edit_line][1] = 0; // clear any typing
178 key_linelen = key_linepos = 1;
179 }
180
181 qboolean Cmd_IsComplete(char *cmd);
182 extern void Q_strncpyz( char *dest, const char *src, size_t size );
CompleteCommand(void)183 void CompleteCommand (void)
184 {
185 char *cmd, *s;
186
187 s = key_lines[edit_line] + 1;
188 if (*s == '\\' || *s == '/')
189 s++;
190
191 cmd = Cmd_CompleteCommand(s);
192 if (cmd) {
193 key_lines[edit_line][1] = '/';
194 Q_strncpyz(key_lines[edit_line] + 2, cmd, sizeof(key_lines[0]));
195 key_linelen = key_linepos = strlen(cmd) + 2;
196 if (Cmd_IsComplete(cmd)) {
197 key_lines[edit_line][key_linepos] = ' ';
198 key_linepos++;
199 key_lines[edit_line][key_linepos] = 0;
200 key_linelen++;
201 } else {
202 key_lines[edit_line][key_linepos] = 0;
203 }
204 return;
205 }
206 }
207
208 /*
209 ====================
210 Key_Console
211
212 Interactive line editing and console scrollback
213 ====================
214 */
Key_Console(int key)215 void Key_Console (int key)
216 {
217 char buffer[MAXCMDLINE];
218
219 switch ( key )
220 {
221 case K_KP_SLASH:
222 key = '/';
223 break;
224 case K_KP_MINUS:
225 key = '-';
226 break;
227 case K_KP_PLUS:
228 key = '+';
229 break;
230 case K_KP_HOME:
231 key = '7';
232 break;
233 case K_KP_UPARROW:
234 key = '8';
235 break;
236 case K_KP_PGUP:
237 key = '9';
238 break;
239 case K_KP_LEFTARROW:
240 key = '4';
241 break;
242 case K_KP_5:
243 key = '5';
244 break;
245 case K_KP_RIGHTARROW:
246 key = '6';
247 break;
248 case K_KP_END:
249 key = '1';
250 break;
251 case K_KP_DOWNARROW:
252 key = '2';
253 break;
254 case K_KP_PGDN:
255 key = '3';
256 break;
257 case K_KP_INS:
258 key = '0';
259 break;
260 case K_KP_DEL:
261 key = '.';
262 break;
263 }
264
265 if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
266 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
267 {
268 char *cbd;
269
270 if ( ( cbd = Sys_GetClipboardData() ) != 0 )
271 {
272 int i, l;
273
274 // save the end of the line
275 l = 1 + key_linelen - key_linepos;
276 memcpy (buffer, key_lines[edit_line] + key_linepos, l);
277
278 i = 0;
279 while ( cbd[i] && key_linelen < MAXCMDLINE - 1 )
280 {
281 // only copy printable characters
282 if ( cbd[i] >= 32 )
283 {
284 key_lines[edit_line][key_linepos ++] = cbd[i];
285 key_linelen ++;
286 }
287 i++;
288 }
289
290 // restore the end of the line
291 memcpy (key_lines[edit_line] + key_linepos, buffer, l);
292
293 free( cbd );
294 }
295
296 return;
297 }
298
299 if ( key == K_ENTER || key == K_KP_ENTER )
300 {
301 Cbuf_AddText (key_lines[edit_line]+1);
302 Cbuf_AddText ("\n");
303
304 Com_Printf ("%s\n",key_lines[edit_line]);
305
306 edit_line = (edit_line + 1) & 31;
307 history_line = edit_line;
308 key_lines[edit_line][0] = ']';
309 key_linelen = key_linepos = 1;
310 if (cls.state == ca_disconnected)
311 SCR_UpdateScreen (); // force an update, because the command
312 // may take some time
313 return;
314 }
315
316 if (key == K_TAB)
317 { // command completion
318 CompleteCommand ();
319 return;
320 }
321
322 if ( key == K_DEL || key == K_KP_DEL )
323 {
324 // Del key, fakes a backspace from the next character
325 if ( key_linepos == key_linelen )
326 return;
327 key_linepos ++;
328 key = K_BACKSPACE;
329 }
330
331 if ( ( key == K_BACKSPACE ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
332 {
333 if (key_linepos > 1) {
334 // remove character at key_linepos
335 if ( key_linelen == key_linepos )
336 {
337 key_lines[edit_line][key_linelen - 1] = 0;
338 }
339 else
340 {
341 memcpy (buffer, key_lines[edit_line], key_linepos - 1);
342 memcpy (buffer + key_linepos - 1, key_lines[edit_line] + key_linepos, key_linelen - key_linepos);
343 buffer[key_linelen - 1] = 0;
344 memcpy (key_lines[edit_line], buffer, MAXCMDLINE);
345 }
346 key_linepos--;
347 key_linelen--;
348 }
349 return;
350 }
351
352 if ( ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) )
353 {
354 if (key_linepos > 1) {
355 if ( keydown[K_CTRL] )
356 {
357 qboolean found_char = false, printable = false;
358 while (key_linepos > 1)
359 {
360 key_linepos --;
361 printable = isalpha(key_lines[edit_line][key_linepos]);
362 found_char = found_char || printable;
363 if ( found_char && !printable )
364 {
365 key_linepos ++;
366 break;
367 }
368 }
369 }
370 else
371 {
372 key_linepos--;
373 }
374 }
375 return;
376 }
377
378 if ( ( key == K_RIGHTARROW ) || ( key == K_KP_RIGHTARROW ) )
379 {
380 if (key_linepos < key_linelen) {
381 if ( keydown[K_CTRL] )
382 {
383 qboolean found_char = false, printable = false;
384 while (key_linepos < key_linelen && (! found_char || printable))
385 {
386 key_linepos ++;
387 printable = isalpha(key_lines[edit_line][key_linepos]);
388 found_char = found_char || printable;
389 }
390 }
391 else
392 {
393 key_linepos++;
394 }
395 }
396 return;
397 }
398
399 if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
400 ( ( key == 'p' ) && keydown[K_CTRL] ) )
401 {
402 do
403 {
404 history_line = (history_line - 1) & 31;
405 } while (history_line != edit_line
406 && !key_lines[history_line][1]);
407 if (history_line == edit_line)
408 history_line = (edit_line+1)&31;
409 strcpy(key_lines[edit_line], key_lines[history_line]);
410 key_linelen = key_linepos = strlen(key_lines[edit_line]);
411 return;
412 }
413
414 if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
415 ( ( key == 'n' ) && keydown[K_CTRL] ) )
416 {
417 if (history_line == edit_line) return;
418 do
419 {
420 history_line = (history_line + 1) & 31;
421 }
422 while (history_line != edit_line
423 && !key_lines[history_line][1]);
424 if (history_line == edit_line)
425 {
426 key_lines[edit_line][0] = ']';
427 key_linelen = key_linepos = 1;
428 }
429 else
430 {
431 strcpy(key_lines[edit_line], key_lines[history_line]);
432 key_linelen = key_linepos = strlen(key_lines[edit_line]);
433 }
434 return;
435 }
436
437 if (key == K_PGUP || key == K_KP_PGUP || key == K_MWHEELUP )
438 {
439 CON_console.displayOffset += 64;
440 return;
441 }
442
443 if (key == K_PGDN || key == K_KP_PGDN || key == K_MWHEELDOWN )
444 {
445 if ( CON_console.displayOffset >= 64 ) {
446 CON_console.displayOffset -= 64;
447 } else {
448 CON_console.displayOffset = 0;
449 }
450 return;
451 }
452
453 if (key == K_HOME || key == K_KP_HOME )
454 {
455 if ( keydown[K_CTRL] )
456 CON_console.displayOffset = 0x7fffffff;
457 else
458 key_linepos = 1;
459 return;
460 }
461
462 if (key == K_END || key == K_KP_END )
463 {
464 if ( keydown[K_CTRL] )
465 CON_console.displayOffset = 0;
466 else
467 key_linepos = key_linelen;
468 return;
469 }
470
471 if (key < 32 || key > 127)
472 return; // non printable
473
474 if ( keydown[K_CTRL] )
475 {
476 switch ( key )
477 {
478 case 'a':
479 case 'A':
480 key_linepos = 1;
481 break;
482 case 'e':
483 case 'E':
484 key_linepos = key_linelen;
485 break;
486 case 'l':
487 case 'L':
488 Cbuf_AddText ("clear\n");
489 break;
490 case 'k':
491 case 'K':
492 key_linelen = key_linepos;
493 key_lines[edit_line][key_linepos + 1] = 0;
494 break;
495 }
496 return;
497 }
498
499 if (key_linelen < MAXCMDLINE-1)
500 {
501 if (key_linepos == key_linelen)
502 {
503 // end of the line, append character
504 key_lines[edit_line][key_linepos] = key;
505 key_lines[edit_line][key_linepos + 1] = 0;
506 }
507 else
508 {
509 // insert character
510 memcpy (buffer, key_lines[edit_line], key_linepos);
511 buffer[key_linepos] = key;
512 memcpy (buffer + key_linepos + 1, key_lines[edit_line] + key_linepos, key_linelen - key_linepos);
513 buffer[key_linelen + 1] = 0;
514 memcpy (key_lines[edit_line], buffer, MAXCMDLINE);
515 }
516 key_linepos++;
517 key_linelen++;
518 }
519
520 }
521
522 //============================================================================
523
524 qboolean chat_team;
525 qboolean chat_irc;
526 char chat_buffer[MAXCMDLINE];
527 int chat_bufferlen = 0;
528
Key_Message(int key)529 void Key_Message (int key)
530 {
531
532 if ( key == K_ENTER || key == K_KP_ENTER )
533 {
534 if (chat_team)
535 Cbuf_AddText ("say_team \"");
536 else if (chat_irc)
537 Cbuf_AddText ("irc_say \"");
538 else
539 Cbuf_AddText ("say \"");
540 Cbuf_AddText(chat_buffer);
541 Cbuf_AddText("\"\n");
542
543 cls.key_dest = key_game;
544 chat_bufferlen = 0;
545 chat_buffer[0] = 0;
546 return;
547 }
548
549 if (key == K_ESCAPE)
550 {
551 cls.key_dest = key_game;
552 chat_bufferlen = 0;
553 chat_buffer[0] = 0;
554 return;
555 }
556
557 if (key < 32 || key > 127)
558 return; // non printable
559
560 if (key == K_BACKSPACE)
561 {
562 if (chat_bufferlen)
563 {
564 chat_bufferlen--;
565 chat_buffer[chat_bufferlen] = 0;
566 }
567 return;
568 }
569
570 if (chat_bufferlen == sizeof(chat_buffer)-1)
571 return; // all full
572
573 chat_buffer[chat_bufferlen++] = key;
574 chat_buffer[chat_bufferlen] = 0;
575 }
576
577 //============================================================================
578
579
580 /*
581 ===================
582 Key_StringToKeynum
583
584 Returns a key number to be used to index keybindings[] by looking at
585 the given string. Single ascii characters return themselves, while
586 the K_* names are matched up.
587 ===================
588 */
Key_StringToKeynum(char * str)589 int Key_StringToKeynum (char *str)
590 {
591 keyname_t *kn;
592
593 if (!str || !str[0])
594 return -1;
595 if (!str[1])
596 return str[0];
597
598 for (kn=keynames ; kn->name ; kn++)
599 {
600 if (!Q_strcasecmp(str,kn->name))
601 return kn->keynum;
602 }
603 return -1;
604 }
605
606 /*
607 ===================
608 Key_KeynumToString
609
610 Returns a string (either a single ascii char, or a K_* name) for the
611 given keynum.
612 FIXME: handle quote special (general escape sequence?)
613 ===================
614 */
Key_KeynumToString(int keynum)615 char *Key_KeynumToString (int keynum)
616 {
617 keyname_t *kn;
618 static char tinystr[2];
619
620 if (keynum == -1)
621 return "<KEY NOT FOUND>";
622 if (keynum > 32 && keynum < 127)
623 { // printable ascii
624 tinystr[0] = keynum;
625 tinystr[1] = 0;
626 return tinystr;
627 }
628
629 for (kn=keynames ; kn->name ; kn++)
630 if (keynum == kn->keynum)
631 return kn->name;
632
633 return "<UNKNOWN KEYNUM>";
634 }
635
636
637 /*
638 ===================
639 Key_SetBinding
640 ===================
641 */
Key_SetBinding(int keynum,char * binding)642 void Key_SetBinding (int keynum, char *binding)
643 {
644 char *new;
645 int l;
646
647 if (keynum == -1)
648 return;
649
650 // free old bindings
651 if (keybindings[keynum])
652 {
653 Z_Free (keybindings[keynum]);
654 keybindings[keynum] = NULL;
655 }
656
657 // allocate memory for new binding
658 l = strlen (binding);
659 new = Z_Malloc (l+1);
660 strcpy (new, binding);
661 new[l] = 0;
662 keybindings[keynum] = new;
663 }
664
665 /*
666 ===================
667 Key_Unbind_f
668 ===================
669 */
Key_Unbind_f(void)670 void Key_Unbind_f (void)
671 {
672 int b;
673
674 if (Cmd_Argc() != 2)
675 {
676 Com_Printf ("unbind <key> : remove commands from a key\n");
677 return;
678 }
679
680 b = Key_StringToKeynum (Cmd_Argv(1));
681 if (b==-1)
682 {
683 Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
684 return;
685 }
686
687 Key_SetBinding (b, "");
688 }
689
Key_Unbindall_f(void)690 void Key_Unbindall_f (void)
691 {
692 int i;
693
694 for (i=0 ; i<256 ; i++)
695 if (keybindings[i])
696 Key_SetBinding (i, "");
697 }
698
699
700 /*
701 ===================
702 Key_Bind_f
703 ===================
704 */
Key_Bind_f(void)705 void Key_Bind_f (void)
706 {
707 int i, c, b;
708 char cmd[1024];
709
710 c = Cmd_Argc();
711
712 if (c < 2)
713 {
714 Com_Printf ("bind <key> [command] : attach a command to a key\n");
715 return;
716 }
717 b = Key_StringToKeynum (Cmd_Argv(1));
718 if (b==-1)
719 {
720 Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
721 return;
722 }
723
724 if (c == 2)
725 {
726 if (keybindings[b])
727 Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
728 else
729 Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
730 return;
731 }
732
733 // copy the rest of the command line
734 cmd[0] = 0; // start out with a null string
735 for (i=2 ; i< c ; i++)
736 {
737 strcat (cmd, Cmd_Argv(i));
738 if (i != (c-1))
739 strcat (cmd, " ");
740 }
741
742 Key_SetBinding (b, cmd);
743 }
744
745 /*
746 ============
747 Key_WriteBindings
748
749 Writes lines containing "bind key value"
750 ============
751 */
Key_WriteBindings(FILE * f)752 void Key_WriteBindings (FILE *f)
753 {
754 int i;
755
756 for (i=0 ; i<256 ; i++)
757 if (keybindings[i] && keybindings[i][0])
758 fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
759 }
760
761
762 /*
763 ============
764 Key_Bindlist_f
765
766 ============
767 */
Key_Bindlist_f(void)768 void Key_Bindlist_f (void)
769 {
770 int i;
771
772 for (i=0 ; i<256 ; i++)
773 if (keybindings[i] && keybindings[i][0])
774 Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
775 }
776
777
778 /*
779 ===================
780 Key_Init
781 ===================
782 */
Key_Init(void)783 void Key_Init (void)
784 {
785 int i;
786
787 for (i=0 ; i<32 ; i++)
788 {
789 key_lines[i][0] = ']';
790 key_lines[i][1] = 0;
791 }
792 key_linelen = key_linepos = 1;
793
794 //
795 // init ascii characters in console mode
796 //
797 for (i=32 ; i<128 ; i++)
798 consolekeys[i] = true;
799 consolekeys[K_ENTER] = true;
800 consolekeys[K_KP_ENTER] = true;
801 consolekeys[K_TAB] = true;
802 consolekeys[K_LEFTARROW] = true;
803 consolekeys[K_KP_LEFTARROW] = true;
804 consolekeys[K_RIGHTARROW] = true;
805 consolekeys[K_KP_RIGHTARROW] = true;
806 consolekeys[K_UPARROW] = true;
807 consolekeys[K_KP_UPARROW] = true;
808 consolekeys[K_DOWNARROW] = true;
809 consolekeys[K_KP_DOWNARROW] = true;
810 consolekeys[K_BACKSPACE] = true;
811 consolekeys[K_HOME] = true;
812 consolekeys[K_KP_HOME] = true;
813 consolekeys[K_END] = true;
814 consolekeys[K_KP_END] = true;
815 consolekeys[K_PGUP] = true;
816 consolekeys[K_KP_PGUP] = true;
817 consolekeys[K_PGDN] = true;
818 consolekeys[K_KP_PGDN] = true;
819 consolekeys[K_SHIFT] = true;
820 consolekeys[K_INS] = true;
821 consolekeys[K_DEL] = true;
822 consolekeys[K_KP_INS] = true;
823 consolekeys[K_KP_DEL] = true;
824 consolekeys[K_KP_SLASH] = true;
825 consolekeys[K_KP_PLUS] = true;
826 consolekeys[K_KP_MINUS] = true;
827 consolekeys[K_KP_5] = true;
828 consolekeys[K_MWHEELUP] = true;
829 consolekeys[K_MWHEELDOWN] = true;
830
831 consolekeys['`'] = false;
832 consolekeys['~'] = false;
833
834 for (i=0 ; i<256 ; i++)
835 keyshift[i] = i;
836 for (i='a' ; i<='z' ; i++)
837 keyshift[i] = i - 'a' + 'A';
838 keyshift['1'] = '!';
839 keyshift['2'] = '@';
840 keyshift['3'] = '#';
841 keyshift['4'] = '$';
842 keyshift['5'] = '%';
843 keyshift['6'] = '^';
844 keyshift['7'] = '&';
845 keyshift['8'] = '*';
846 keyshift['9'] = '(';
847 keyshift['0'] = ')';
848 keyshift['-'] = '_';
849 keyshift['='] = '+';
850 keyshift[','] = '<';
851 keyshift['.'] = '>';
852 keyshift['/'] = '?';
853 keyshift[';'] = ':';
854 keyshift['\''] = '"';
855 keyshift['['] = '{';
856 keyshift[']'] = '}';
857 keyshift['`'] = '~';
858 keyshift['\\'] = '|';
859
860 menubound[K_ESCAPE] = true;
861 for (i=0 ; i<12 ; i++)
862 menubound[K_F1+i] = true;
863
864 //
865 // register our functions
866 //
867 Cmd_AddCommand ("bind",Key_Bind_f);
868 Cmd_AddCommand ("unbind",Key_Unbind_f);
869 Cmd_AddCommand ("unbindall",Key_Unbindall_f);
870 Cmd_AddCommand ("bindlist",Key_Bindlist_f);
871 }
872
873 /*
874 ===================
875 Key_Event
876
877 Called by the system between frames for both key up and key down events
878 Should NOT be called during an interrupt!
879 ===================
880 */
881
Key_Event(int key,qboolean down,unsigned time)882 void Key_Event (int key, qboolean down, unsigned time)
883 {
884 char *kb;
885 char cmd[1024];
886
887 // hack for modal presses
888 if (key_waiting == -1)
889 {
890 if (down)
891 key_waiting = key;
892 return;
893 }
894
895 // update auto-repeat status
896 if (down)
897 {
898 key_repeats[key]++;
899 if (key != K_BACKSPACE
900 && key != K_PAUSE
901 && key != K_PGUP
902 && key != K_KP_PGUP
903 && key != K_PGDN
904 && key != K_KP_PGDN
905 && key_repeats[key] > 1)
906 return; // ignore most autorepeats
907
908 if (key >= 200 && !keybindings[key])
909 Com_Printf ("%s is not bound to a command.\n", Key_KeynumToString (key) );
910 }
911 else
912 {
913 key_repeats[key] = 0;
914 }
915
916 if (key == K_SHIFT)
917 shift_down = down;
918
919 // console key is hardcoded, so the user can never unbind it
920 if (key == '`' || key == '~')
921 {
922 if (!down)
923 return;
924 if (cls.key_dest == key_console && cls.state == ca_disconnected) {
925 M_Menu_Main_f ();
926 return;
927 }
928
929 CON_ToggleConsole( );
930 return;
931 }
932
933 // menu key is hardcoded, so the user can never unbind it
934 if (key == K_ESCAPE)
935 {
936 if (!down)
937 return;
938
939 if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
940 { // put away help computer / inventory
941 Cbuf_AddText ("cmd putaway\n");
942 return;
943 }
944 switch (cls.key_dest)
945 {
946 case key_message:
947 Key_Message (key);
948 break;
949 case key_menu:
950 M_Keydown (key);
951 break;
952 case key_game:
953 case key_console:
954 M_Menu_Main_f ();
955 break;
956 default:
957 Com_Error (ERR_FATAL, "Bad cls.key_dest");
958 }
959 return;
960 }
961
962 // track if any key is down for BUTTON_ANY
963 keydown[key] = down;
964 if (down)
965 {
966 if (key_repeats[key] == 1)
967 anykeydown++;
968 }
969 else
970 {
971 anykeydown--;
972 if (anykeydown < 0)
973 anykeydown = 0;
974 }
975
976 //
977 // key up events only generate commands if the game key binding is
978 // a button command (leading + sign). These will occur even in console mode,
979 // to keep the character from continuing an action started before a console
980 // switch. Button commands include the kenum as a parameter, so multiple
981 // downs can be matched with ups
982 //
983 if (!down)
984 {
985 kb = keybindings[key];
986 if (kb && kb[0] == '+')
987 {
988 Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
989 Cbuf_AddText (cmd);
990 }
991 if (keyshift[key] != key)
992 {
993 kb = keybindings[keyshift[key]];
994 if (kb && kb[0] == '+')
995 {
996 Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
997 Cbuf_AddText (cmd);
998 }
999 }
1000 return;
1001 }
1002
1003 //
1004 // if not a consolekey, send to the interpreter no matter what mode is
1005 //
1006 if ( (cls.key_dest == key_menu && menubound[key])
1007 || (cls.key_dest == key_console && !consolekeys[key])
1008 || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
1009 {
1010 kb = keybindings[key];
1011 if (kb)
1012 {
1013 if (kb[0] == '+')
1014 { // button commands add keynum and time as a parm
1015 Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
1016 Cbuf_AddText (cmd);
1017 }
1018 else
1019 {
1020 Cbuf_AddText (kb);
1021 Cbuf_AddText ("\n");
1022 }
1023 }
1024 return;
1025 }
1026
1027 if (!down)
1028 return; // other systems only care about key down events
1029
1030 if (shift_down)
1031 key = keyshift[key];
1032
1033 switch (cls.key_dest)
1034 {
1035 case key_message:
1036 Key_Message (key);
1037 break;
1038 case key_menu:
1039 M_Keydown (key);
1040 break;
1041
1042 case key_game:
1043 case key_console:
1044 Key_Console (key);
1045 break;
1046 default:
1047 Com_Error (ERR_FATAL, "Bad cls.key_dest");
1048 }
1049 }
1050
1051 /*
1052 ===================
1053 Key_ClearStates
1054 ===================
1055 */
Key_ClearStates(void)1056 void Key_ClearStates (void)
1057 {
1058 int i;
1059
1060 anykeydown = false;
1061
1062 for (i=0 ; i<256 ; i++)
1063 {
1064 if ( keydown[i] || key_repeats[i] )
1065 Key_Event( i, false, 0 );
1066 keydown[i] = 0;
1067 key_repeats[i] = 0;
1068 }
1069 }
1070
1071
1072 /*
1073 ===================
1074 Key_GetKey
1075 ===================
1076 */
Key_GetKey(void)1077 int Key_GetKey (void)
1078 {
1079 key_waiting = -1;
1080
1081 while (key_waiting == -1)
1082 Sys_SendKeyEvents ();
1083
1084 return key_waiting;
1085 }
1086