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
CheckForCommand(void)171 static qboolean CheckForCommand (void)
172 {
173 char command[128], *s;
174 int i;
175
176 s = key_lines[edit_line] + 1;
177
178 command[0] = '\0';
179 for (i = 0; i < 127; i++)
180 {
181 if (s[i] <= ' ')
182 break;
183 command[i] = s[i];
184 }
185
186 command[i] = 0;
187
188 return Cmd_CheckCommand (command);
189 }
190
CompleteCommand(void)191 static void CompleteCommand (void)
192 {
193 char *matches[MAX_MATCHES];
194 char backup[MAXCMDLINE];
195 char c, *prefix, *workline;
196 qboolean editing;
197 int count, i;
198 size_t len1, len2;
199
200 if (key_linepos < 2)
201 return;
202
203 workline = key_lines[edit_line];
204 c = workline[key_linepos];
205 editing = (c != 0);
206
207 if (editing)
208 {
209 // make a copy of the text starting from the
210 // cursor position (see below)
211 q_strlcpy(backup, workline + key_linepos, sizeof(backup));
212 }
213
214 // complete the text only up to the cursor position:
215 // bash style. cut off the rest for now.
216 workline[key_linepos] = 0;
217 prefix = workline + 1;
218
219 // skip the leading whitespace and command markers
220 while (*prefix)
221 {
222 if (*prefix != '\\' && *prefix != '/' && *prefix > ' ')
223 break;
224 ++prefix;
225 }
226
227 // if the remainder line has no length or has
228 // spaces in it, don't bother
229 if (!*prefix || strstr(prefix," "))
230 {
231 workline[key_linepos] = c;
232 return;
233 }
234
235 // store the length of the relevant partial
236 len1 = len2 = strlen(prefix);
237
238 // start checking for matches, finally...
239 count = 0;
240 count += ListCommands(prefix, (const char**)matches, count);
241 count += ListCvars (prefix, (const char**)matches, count);
242 count += ListAlias (prefix, (const char**)matches, count);
243
244 if (count)
245 {
246 // do not do a full auto-complete
247 // unless there is only one match
248 if (count == 1)
249 {
250 workline[1] = '/';
251 q_strlcpy (workline + 2, matches[0], MAXCMDLINE-2);
252 key_linepos = 2 + strlen(matches[0]);
253 // q_strlcpy (workline + 1, matches[0], MAXCMDLINE-1);
254 // key_linepos = 1 + strlen(matches[0]);
255 workline[key_linepos] = ' ';
256 key_linepos++;
257 }
258 else
259 {
260 // more than one match, sort and list all of them
261 qsort (matches, count, sizeof(char *), COM_StrCompare);
262 Con_Printf("\n");
263 #if 0
264 // plain listing
265 for (i = 0; i < count && i < MAX_MATCHES; i++)
266 Con_Printf ("%s\n", matches[i]);
267 Con_Printf("\n%d matches found\n\n", count);
268 #else
269 // S.A.: columnize the listing.
270 Con_Printf("%d possible completions:\n\n", count);
271 Con_ShowList (count, (const char**) matches);
272 Con_Printf("\n");
273 #endif
274
275 // cycle throgh all matches and see
276 // if there is a partial completion
277 _search:
278 for (i = 1; i < count && i < MAX_MATCHES; i++)
279 {
280 if (matches[0][len2] != matches[i][len2])
281 goto _check;
282 }
283 ++len2;
284 goto _search;
285 _check:
286 if (len2 > len1) // found a partial match
287 {
288 workline[1] = '/';
289 strncpy (workline + 2, matches[0], len2);
290 key_linepos = len2 + 2;
291 // strncpy (workline + 1, matches[0], len2);
292 // key_linepos = len2 + 1;
293 }
294 }
295
296 workline[key_linepos] = 0;
297 }
298
299 // put back the remainder of the original text
300 // which was lost after the trimming
301 if (editing)
302 q_strlcpy (workline + key_linepos, backup, MAXCMDLINE-key_linepos);
303 }
304
PasteToConsole(void)305 static void PasteToConsole (void)
306 {
307 char *cbd, *p, *workline;
308 int mvlen, inslen;
309
310 if (key_linepos == MAXCMDLINE - 1)
311 return;
312
313 if ((cbd = Sys_GetClipboardData()) == NULL)
314 return;
315
316 p = cbd;
317 while (*p)
318 {
319 if (*p == '\n' || *p == '\r' || *p == '\b')
320 {
321 *p = 0;
322 break;
323 }
324 p++;
325 }
326
327 inslen = (int) (p - cbd);
328 if (inslen + key_linepos > MAXCMDLINE - 1)
329 inslen = MAXCMDLINE - 1 - key_linepos;
330 if (inslen <= 0) goto done;
331
332 workline = key_lines[edit_line];
333 workline += key_linepos;
334 mvlen = (int) strlen(workline);
335 if (mvlen + inslen + key_linepos > MAXCMDLINE - 1)
336 {
337 mvlen = MAXCMDLINE - 1 - key_linepos - inslen;
338 if (mvlen < 0) mvlen = 0;
339 }
340
341 // insert the string
342 if (mvlen != 0)
343 memmove (workline + inslen, workline, mvlen);
344 memcpy (workline, cbd, inslen);
345 key_linepos += inslen;
346 workline[mvlen + inslen] = '\0';
347 done:
348 Z_Free(cbd);
349 }
350
351 /*
352 ====================
353 Key_Console
354
355 Interactive line editing and console scrollback
356 ====================
357 */
Key_Console(int key)358 static void Key_Console (int key)
359 {
360 int history_line_last;
361 size_t len;
362 char *workline = key_lines[edit_line];
363
364 switch (key)
365 {
366 case K_ENTER:
367 // backslash text are commands, else chat
368 if (workline[1] == '\\' || workline[1] == '/')
369 Cbuf_AddText (workline + 2); // skip the >
370 else if (CheckForCommand())
371 Cbuf_AddText (workline + 1); // valid command
372 else
373 { // convert to a chat message
374 if (cls.state >= ca_connected)
375 Cbuf_AddText ("say ");
376 Cbuf_AddText (workline + 1); // skip the >
377 }
378
379 Cbuf_AddText ("\n");
380 Con_Printf ("%s\n", workline);
381 edit_line = (edit_line + 1) & 31;
382 history_line = edit_line;
383 key_lines[edit_line][0] = ']';
384 key_lines[edit_line][1] = 0;
385 key_linepos = 1;
386 if (cls.state == ca_disconnected)
387 SCR_UpdateScreen (); // force an update, because the command
388 // may take some time
389 return;
390
391 case K_TAB:
392 CompleteCommand ();
393 return;
394
395 case K_LEFTARROW:
396 if (key_linepos < 2)
397 return;
398 if (keydown[K_CTRL])
399 {
400 /* ctrl - left, word processor style: first,
401 * move to the ending of previous word, then
402 * move to its beginning
403 */
404 char *p = workline + key_linepos - 1;
405 while (p != workline && *p == ' ')
406 --p;
407 while (p != workline)
408 {
409 if (*--p == ' ')
410 break;
411 }
412 key_linepos = (int)(p - workline) + 1;
413 }
414 else /* simple cursor-to-left, only. */
415 {
416 --key_linepos;
417 }
418 return;
419
420 case K_RIGHTARROW:
421 if (!workline[key_linepos])
422 return;
423 if (keydown[K_CTRL])
424 {
425 /* ctrl - right, word processor style: if
426 * we are on a text move to its end, then
427 * move to the beginning of the next word
428 */
429 char *p = workline + key_linepos;
430 while (*p && *p != ' ')
431 ++p;
432 while (*p && *p == ' ')
433 ++p;
434 key_linepos = (int)(p - workline);
435 }
436 else /* simple cursor-to-right only. */
437 {
438 ++key_linepos;
439 }
440 return;
441
442 case K_BACKSPACE:
443 if (key_linepos > 1)
444 {
445 workline += key_linepos - 1;
446 if (workline[1])
447 {
448 len = strlen(workline);
449 memmove (workline, workline + 1, len);
450 }
451 else *workline = 0;
452
453 key_linepos--;
454 }
455 return;
456
457 case K_DEL:
458 workline += key_linepos;
459 if (*workline)
460 {
461 if (workline[1])
462 {
463 len = strlen(workline);
464 memmove (workline, workline + 1, len);
465 }
466 else *workline = 0;
467 }
468 return;
469
470 case K_UPARROW:
471 history_line_last = history_line;
472 do
473 {
474 history_line = (history_line - 1) & 31;
475 } while (history_line != edit_line && !key_lines[history_line][1]);
476
477 if (history_line == edit_line)
478 history_line = history_line_last;
479
480 strcpy(workline, key_lines[history_line]);
481 key_linepos = strlen(workline);
482 return;
483
484 case K_DOWNARROW:
485 if (history_line == edit_line)
486 return;
487 do
488 {
489 history_line = (history_line + 1) & 31;
490 } while (history_line != edit_line && !key_lines[history_line][1]);
491
492 if (history_line == edit_line)
493 {
494 workline[0] = ']';
495 workline[1] = 0;
496 key_linepos = 1;
497 }
498 else
499 {
500 strcpy(workline, key_lines[history_line]);
501 key_linepos = strlen(workline);
502 }
503 return;
504
505 case K_PGUP:
506 case K_MWHEELUP:
507 con->display -= 2;
508 return;
509
510 case K_PGDN:
511 case K_MWHEELDOWN:
512 con->display += 2;
513 if (con->display > con->current)
514 con->display = con->current;
515 return;
516
517 case K_HOME:
518 if (keydown[K_CTRL])
519 con->display = con->current - con_totallines + 10;
520 else key_linepos = 1;
521 return;
522
523 case K_END:
524 if (keydown[K_CTRL])
525 con->display = con->current;
526 else key_linepos = strlen(workline);
527 return;
528
529 case K_INS:
530 if (keydown[K_SHIFT]) /* Shift+Ins paste */
531 PasteToConsole();
532 else key_insert ^= 1;
533 return;
534
535 case 'v':
536 case 'V':
537 #if defined(PLATFORM_OSX) || defined(PLATFORM_MAC)
538 if (keydown[K_COMMAND]) { /* Cmd+V paste (Mac-only) */
539 PasteToConsole();
540 return;
541 }
542 #endif
543 if (keydown[K_CTRL]) { /* Ctrl+v paste */
544 PasteToConsole();
545 return;
546 }
547 break;
548
549 case 'c':
550 case 'C':
551 if (keydown[K_CTRL]) { /* Ctrl+C: abort the line -- S.A */
552 Con_Printf ("%s\n", workline);
553 workline[0] = ']';
554 workline[1] = 0;
555 key_linepos = 1;
556 history_line= edit_line;
557 return;
558 }
559 break;
560 }
561
562 if (key < 32 || key > 127)
563 return; // non printable
564
565 if (key_linepos < MAXCMDLINE - 1)
566 {
567 qboolean endpos = !workline[key_linepos];
568 // if inserting, move the text to the right
569 if (key_insert && !endpos)
570 {
571 workline[MAXCMDLINE - 2] = 0;
572 workline += key_linepos;
573 len = strlen(workline) + 1;
574 memmove (workline + 1, workline, len);
575 *workline = key;
576 }
577 else
578 {
579 workline += key_linepos;
580 *workline = key;
581 // null terminate if at the end
582 if (endpos)
583 workline[1] = 0;
584 }
585 key_linepos++;
586 }
587 }
588
589 //============================================================================
590
591 qboolean chat_team = false;
592 static char chat_buffer[MAXCMDLINE];
593 static int chat_bufferlen = 0;
594
Key_GetChatBuffer(void)595 const char *Key_GetChatBuffer (void)
596 {
597 return chat_buffer;
598 }
599
Key_GetChatMsgLen(void)600 int Key_GetChatMsgLen (void)
601 {
602 return chat_bufferlen;
603 }
604
Key_EndChat(void)605 void Key_EndChat (void)
606 {
607 Key_SetDest (key_game);
608 chat_bufferlen = 0;
609 chat_buffer[0] = 0;
610 }
611
Key_Message(int key)612 static void Key_Message (int key)
613 {
614 if (key == K_ENTER)
615 {
616 if (chat_team)
617 Cbuf_AddText ("say_team \"");
618 else
619 Cbuf_AddText ("say \"");
620 Cbuf_AddText(chat_buffer);
621 Cbuf_AddText("\"\n");
622
623 Key_EndChat ();
624 return;
625 }
626
627 if (key == K_ESCAPE)
628 {
629 Key_EndChat ();
630 return;
631 }
632
633 if (key == K_BACKSPACE)
634 {
635 if (chat_bufferlen)
636 chat_buffer[--chat_bufferlen] = 0;
637 return;
638 }
639
640 if (key < 32 || key > 127)
641 return; // non printable
642
643 if (chat_bufferlen == sizeof(chat_buffer) - 1)
644 return; // all full
645
646 chat_buffer[chat_bufferlen++] = key;
647 chat_buffer[chat_bufferlen] = 0;
648 }
649
650 //============================================================================
651
652
653 /*
654 ===================
655 Key_StringToKeynum
656
657 Returns a key number to be used to index keybindings[] by looking at
658 the given string. Single ascii characters return themselves, while
659 the K_* names are matched up.
660 ===================
661 */
Key_StringToKeynum(const char * str)662 static int Key_StringToKeynum (const char *str)
663 {
664 keyname_t *kn;
665
666 if (!str || !str[0])
667 return -1;
668 if (!str[1])
669 return str[0];
670
671 for (kn = keynames; kn->name; kn++)
672 {
673 if (!q_strcasecmp(str,kn->name))
674 return kn->keynum;
675 }
676 return -1;
677 }
678
679 /*
680 ===================
681 Key_KeynumToString
682
683 Returns a string (either a single ascii char, or a K_* name) for the
684 given keynum.
685 FIXME: handle quote special (general escape sequence?)
686 ===================
687 */
Key_KeynumToString(int keynum)688 const char *Key_KeynumToString (int keynum)
689 {
690 static char tinystr[2];
691 keyname_t *kn;
692
693 if (keynum == -1)
694 return "<KEY NOT FOUND>";
695 if (keynum > 32 && keynum < 127)
696 { // printable ascii
697 tinystr[0] = keynum;
698 tinystr[1] = 0;
699 return tinystr;
700 }
701
702 for (kn = keynames; kn->name; kn++)
703 {
704 if (keynum == kn->keynum)
705 return kn->name;
706 }
707
708 return "<UNKNOWN KEYNUM>";
709 }
710
711
712 /*
713 ===================
714 Key_SetBinding
715 ===================
716 */
Key_SetBinding(int keynum,const char * binding)717 void Key_SetBinding (int keynum, const char *binding)
718 {
719 if (keynum == -1)
720 return;
721 if (keyreserved[keynum])
722 return;
723
724 // free old bindings
725 if (keybindings[keynum])
726 {
727 Z_Free (keybindings[keynum]);
728 keybindings[keynum] = NULL;
729 }
730
731 // allocate memory for new binding
732 if (binding)
733 keybindings[keynum] = Z_Strdup(binding);
734 }
735
736 /*
737 ===================
738 Key_Unbind_f
739 ===================
740 */
Key_Unbind_f(void)741 static void Key_Unbind_f (void)
742 {
743 int b;
744
745 if (Cmd_Argc() != 2)
746 {
747 Con_Printf ("unbind <key> : remove commands from a key\n");
748 return;
749 }
750
751 b = Key_StringToKeynum (Cmd_Argv(1));
752 if (b == -1)
753 {
754 Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
755 return;
756 }
757
758 Key_SetBinding (b, NULL);
759 }
760
Key_Unbindall_f(void)761 static void Key_Unbindall_f (void)
762 {
763 int i;
764
765 for (i = 0; i < 256; i++)
766 Key_SetBinding(i, NULL);
767 }
768
769
770 /*
771 ===================
772 Key_Bind_f
773 ===================
774 */
Key_Bind_f(void)775 static void Key_Bind_f (void)
776 {
777 int i, c, b;
778 char cmd[1024];
779
780 c = Cmd_Argc();
781
782 if (c != 2 && c != 3)
783 {
784 Con_Printf ("bind <key> [command] : attach a command to a key\n");
785 return;
786 }
787 b = Key_StringToKeynum (Cmd_Argv(1));
788 if (b == -1)
789 {
790 Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
791 return;
792 }
793
794 if (c == 2)
795 {
796 if (keybindings[b])
797 Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
798 else
799 Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
800 return;
801 }
802
803 // copy the rest of the command line
804 cmd[0] = 0;
805 for (i = 2; i < c; i++)
806 {
807 q_strlcat (cmd, Cmd_Argv(i), sizeof(cmd));
808 if (i != (c-1))
809 q_strlcat (cmd, " ", sizeof(cmd));
810 }
811
812 Key_SetBinding (b, cmd);
813 }
814
815 /*
816 ============
817 Key_WriteBindings
818
819 Writes lines containing "bind key value"
820 ============
821 */
Key_WriteBindings(FILE * f)822 void Key_WriteBindings (FILE *f)
823 {
824 int i;
825
826 // unbindall before loading stored bindings:
827 if (cfg_unbindall.integer)
828 fprintf (f, "unbindall\n");
829 for (i = 0; i < 256; i++)
830 {
831 if (keybindings[i] && *keybindings[i])
832 fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
833 }
834 }
835
836
837 /*
838 ===================
839 Key_Init
840 ===================
841 */
Key_Init(void)842 void Key_Init (void)
843 {
844 int i;
845
846 for (i = 0; i < 32; i++)
847 {
848 key_lines[i][0] = ']';
849 key_lines[i][1] = 0;
850 }
851 key_linepos = 1;
852
853 memset (consolekeys, 0, sizeof(consolekeys));
854 memset (menubound, 0, sizeof(menubound));
855 memset (keyreserved, 0, sizeof(keyreserved));
856
857 // init ascii characters in console mode
858 for (i = 32; i < 128; i++)
859 consolekeys[i] = true;
860 consolekeys[K_ENTER] = true;
861 consolekeys[K_TAB] = true;
862 consolekeys[K_LEFTARROW] = true;
863 consolekeys[K_RIGHTARROW] = true;
864 consolekeys[K_UPARROW] = true;
865 consolekeys[K_DOWNARROW] = true;
866 consolekeys[K_BACKSPACE] = true;
867 consolekeys[K_DEL] = true;
868 consolekeys[K_INS] = true;
869 consolekeys[K_HOME] = true;
870 consolekeys[K_END] = true;
871 consolekeys[K_PGUP] = true;
872 consolekeys[K_PGDN] = true;
873 consolekeys[K_SHIFT] = true;
874 consolekeys[K_MWHEELUP] = true;
875 consolekeys[K_MWHEELDOWN] = true;
876 consolekeys['`'] = false;
877 consolekeys['~'] = false;
878
879 for (i = 0; i < 256; i++)
880 keyshift[i] = i;
881 for (i = 'a'; i <= 'z'; i++)
882 keyshift[i] = i - 'a' + 'A';
883 keyshift['1'] = '!';
884 keyshift['2'] = '@';
885 keyshift['3'] = '#';
886 keyshift['4'] = '$';
887 keyshift['5'] = '%';
888 keyshift['6'] = '^';
889 keyshift['7'] = '&';
890 keyshift['8'] = '*';
891 keyshift['9'] = '(';
892 keyshift['0'] = ')';
893 keyshift['-'] = '_';
894 keyshift['='] = '+';
895 keyshift[','] = '<';
896 keyshift['.'] = '>';
897 keyshift['/'] = '?';
898 keyshift[';'] = ':';
899 keyshift['\''] = '"';
900 keyshift['['] = '{';
901 keyshift[']'] = '}';
902 keyshift['`'] = '~';
903 keyshift['\\'] = '|';
904
905 menubound[K_ESCAPE] = true;
906 for (i = 0; i < 12; i++)
907 menubound[K_F1+i] = true;
908
909 memset (key_repeats, 0, sizeof(key_repeats));
910
911 // bind our reserved keys
912 Key_SetBinding ('`', "toggleconsole");
913 Key_SetBinding ('~', "toggleconsole");
914 Key_SetBinding (K_PAUSE, "pause");
915 keyreserved['`'] = true;
916 keyreserved['~'] = true;
917 keyreserved[K_KP_NUMLOCK] = true;
918 keyreserved[K_PAUSE] = true;
919
920 // register our functions
921 Cmd_AddCommand ("bind",Key_Bind_f);
922 Cmd_AddCommand ("unbind",Key_Unbind_f);
923 Cmd_AddCommand ("unbindall",Key_Unbindall_f);
924 }
925
926 /*
927 ===================
928 Key_Event
929
930 Called by the system between frames for both key up and key down events
931 Should NOT be called during an interrupt!
932 ===================
933 */
Key_Event(int key,qboolean down)934 void Key_Event (int key, qboolean down)
935 {
936 char *kb;
937 char cmd[1024];
938
939 keydown[key] = down;
940
941 if (!down)
942 key_repeats[key] = 0;
943
944 key_lastpress = key;
945 key_count++;
946 if (key_count <= 0)
947 return; // just catching keys for Con_NotifyBox
948
949 // update auto-repeat status
950 if (down)
951 {
952 /* Pause key doesn't generate a scancode when released,
953 * never increment its auto-repeat status.
954 */
955 if (key != K_PAUSE && key != K_KP_NUMLOCK)
956 key_repeats[key]++;
957 #if 0
958 if (key != K_BACKSPACE && key != K_PGUP && key != K_PGDN &&
959 key_repeats[key] > 1)
960 return; // ignore most autorepeats
961 #endif
962 if (key_repeats[key] > 1)
963 {
964 if (key_dest == key_game && !con_forcedup)
965 return; // ignore autorepeats in game mode
966 }
967 else if (key >= 200 && !keybindings[key])
968 Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString(key));
969 }
970
971 if (key == K_SHIFT)
972 shift_down = down;
973
974 // handle escape specialy, so the user can never unbind it
975 if (key == K_ESCAPE)
976 {
977 if (!down)
978 return;
979 switch (key_dest)
980 {
981 case key_message:
982 Key_Message (key);
983 break;
984 case key_menu:
985 M_Keydown (key);
986 break;
987 case key_menubind:
988 M_Keybind (key);
989 break;
990 case key_game:
991 case key_console:
992 M_ToggleMenu_f ();
993 break;
994 default:
995 Sys_Error ("Bad key_dest");
996 }
997 return;
998 }
999
1000 // key up events only generate commands if the game key binding is
1001 // a button command (leading + sign). These will occur even in console mode,
1002 // to keep the character from continuing an action started before a console
1003 // switch. Button commands include the kenum as a parameter, so multiple
1004 // downs can be matched with ups
1005 if (!down)
1006 {
1007 kb = keybindings[key];
1008 if (kb && kb[0] == '+')
1009 {
1010 sprintf (cmd, "-%s %i\n", kb+1, key);
1011 Cbuf_AddText (cmd);
1012 }
1013 if (keyshift[key] != key)
1014 {
1015 kb = keybindings[keyshift[key]];
1016 if (kb && kb[0] == '+')
1017 {
1018 sprintf (cmd, "-%s %i\n", kb+1, key);
1019 Cbuf_AddText (cmd);
1020 }
1021 }
1022 return;
1023 }
1024
1025 // during demo playback, most keys bring up the main menu
1026 if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
1027 {
1028 M_ToggleMenu_f ();
1029 return;
1030 }
1031
1032 // if not a consolekey, send to the interpreter no matter what mode is
1033 if (((key_dest & key_menu) && menubound[key]) ||
1034 (key_dest == key_console && !consolekeys[key]) ||
1035 (key_dest == key_game && (!con_forcedup || !consolekeys[key])))
1036 {
1037 kb = keybindings[key];
1038 if (kb)
1039 {
1040 if (kb[0] == '+')
1041 { // button commands add keynum as a parm
1042 sprintf (cmd, "%s %i\n", kb, key);
1043 Cbuf_AddText (cmd);
1044 }
1045 else
1046 {
1047 Cbuf_AddText (kb);
1048 Cbuf_AddText ("\n");
1049 }
1050 }
1051 return;
1052 }
1053
1054 if (!down)
1055 return; // other systems only care about key down events
1056
1057 if (shift_down)
1058 key = keyshift[key];
1059
1060 switch (key_dest)
1061 {
1062 case key_message:
1063 Key_Message (key);
1064 break;
1065 case key_menu:
1066 M_Keydown (key);
1067 break;
1068 case key_menubind:
1069 M_Keybind (key);
1070 break;
1071 case key_game:
1072 case key_console:
1073 Key_Console (key);
1074 break;
1075 default:
1076 Sys_Error ("Bad key_dest");
1077 }
1078 }
1079
1080 /*
1081 ===================
1082 Key_ClearStates
1083 ===================
1084 */
Key_ClearStates(void)1085 void Key_ClearStates (void)
1086 {
1087 int i;
1088
1089 for (i = 0; i < 256; i++)
1090 {
1091 if (keydown[i])
1092 Key_Event (i, false);
1093 }
1094 }
1095
Key_IsGameKey(void)1096 qboolean Key_IsGameKey (void)
1097 {
1098 return ((key_dest == key_game && !con_forcedup) || (key_dest == key_menubind));
1099 }
1100
Key_GetDest(void)1101 keydest_t Key_GetDest (void)
1102 {
1103 return key_dest;
1104 }
1105
Key_SetDest(keydest_t dest)1106 void Key_SetDest (keydest_t dest)
1107 {
1108 key_dest = dest;
1109 if ((key_gamekey = Key_IsGameKey()) != prev_gamekey)
1110 {
1111 prev_gamekey = key_gamekey;
1112 Key_ClearStates();
1113 }
1114 }
1115
1116