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