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