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