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