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