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 char	key_lines[32][MAXCMDLINE];
29 int		key_linepos;
30 int		shift_down=false;
31 int	anykeydown;
32 
33 int		edit_line=0;
34 int		history_line=0;
35 
36 //int		key_waiting;
37 char		*keybindings[256];
38 qboolean	consolekeys[256];	// if true, can't be rebound while in console
39 qboolean	menubound[256];	// if true, can't be rebound while in menu
40 qboolean	buttondown[256];
41 int			keyshift[256];		// key to map to if shift held down in console
42 int			key_repeats[256];	// if > 1, it is autorepeating
43 int			keydown[256];
44 
45 unsigned int			key_lastrepeat[256];
46 
47 int			key_repeatrate;
48 int			key_repeatdelay;
49 
50 cvar_t	*cl_cmdcomplete;
51 
52 typedef struct
53 {
54 	char	/*@null@*/ *name;
55 	int		keynum;
56 } keyname_t;
57 
58 keyname_t keynames[] =
59 {
60 	{"TAB", K_TAB},
61 	{"ENTER", K_ENTER},
62 	{"ESCAPE", K_ESCAPE},
63 	{"SPACE", K_SPACE},
64 	{"BACKSPACE", K_BACKSPACE},
65 	{"UPARROW", K_UPARROW},
66 	{"DOWNARROW", K_DOWNARROW},
67 	{"LEFTARROW", K_LEFTARROW},
68 	{"RIGHTARROW", K_RIGHTARROW},
69 
70 	{"ALT", K_ALT},
71 	{"CTRL", K_CTRL},
72 	{"SHIFT", K_SHIFT},
73 
74 	{"F1", K_F1},
75 	{"F2", K_F2},
76 	{"F3", K_F3},
77 	{"F4", K_F4},
78 	{"F5", K_F5},
79 	{"F6", K_F6},
80 	{"F7", K_F7},
81 	{"F8", K_F8},
82 	{"F9", K_F9},
83 	{"F10", K_F10},
84 	{"F11", K_F11},
85 	{"F12", K_F12},
86 
87 	{"INS", K_INS},
88 	{"DEL", K_DEL},
89 	{"PGDN", K_PGDN},
90 	{"PGUP", K_PGUP},
91 	{"HOME", K_HOME},
92 	{"END", K_END},
93 
94 	{"MOUSE1", K_MOUSE1},
95 	{"MOUSE2", K_MOUSE2},
96 	{"MOUSE3", K_MOUSE3},
97 	{"MOUSE4", K_MOUSE4},
98 	{"MOUSE5", K_MOUSE5},
99 	{"MOUSE6", K_MOUSE6},
100 	{"MOUSE7", K_MOUSE7},
101 	{"MOUSE8", K_MOUSE8},
102 	{"MOUSE9", K_MOUSE9},
103 
104 	{"JOY1", K_JOY1},
105 	{"JOY2", K_JOY2},
106 	{"JOY3", K_JOY3},
107 	{"JOY4", K_JOY4},
108 
109 	{"AUX1", K_AUX1},
110 	{"AUX2", K_AUX2},
111 	{"AUX3", K_AUX3},
112 	{"AUX4", K_AUX4},
113 	{"AUX5", K_AUX5},
114 	{"AUX6", K_AUX6},
115 	{"AUX7", K_AUX7},
116 	{"AUX8", K_AUX8},
117 	{"AUX9", K_AUX9},
118 	{"AUX10", K_AUX10},
119 	{"AUX11", K_AUX11},
120 	{"AUX12", K_AUX12},
121 	{"AUX13", K_AUX13},
122 	{"AUX14", K_AUX14},
123 	{"AUX15", K_AUX15},
124 	{"AUX16", K_AUX16},
125 	{"AUX17", K_AUX17},
126 	{"AUX18", K_AUX18},
127 	{"AUX19", K_AUX19},
128 	{"AUX20", K_AUX20},
129 	{"AUX21", K_AUX21},
130 	{"AUX22", K_AUX22},
131 	{"AUX23", K_AUX23},
132 	{"AUX24", K_AUX24},
133 	{"AUX25", K_AUX25},
134 	{"AUX26", K_AUX26},
135 	{"AUX27", K_AUX27},
136 	{"AUX28", K_AUX28},
137 	{"AUX29", K_AUX29},
138 	{"AUX30", K_AUX30},
139 	{"AUX31", K_AUX31},
140 	{"AUX32", K_AUX32},
141 
142 	{"KP_HOME",			K_KP_HOME },
143 	{"KP_UPARROW",		K_KP_UPARROW },
144 	{"KP_PGUP",			K_KP_PGUP },
145 	{"KP_LEFTARROW",	K_KP_LEFTARROW },
146 	{"KP_5",			K_KP_5 },
147 	{"KP_RIGHTARROW",	K_KP_RIGHTARROW },
148 	{"KP_END",			K_KP_END },
149 	{"KP_DOWNARROW",	K_KP_DOWNARROW },
150 	{"KP_PGDN",			K_KP_PGDN },
151 	{"KP_ENTER",		K_KP_ENTER },
152 	{"KP_INS",			K_KP_INS },
153 	{"KP_DEL",			K_KP_DEL },
154 	{"KP_SLASH",		K_KP_SLASH },
155 	{"KP_MINUS",		K_KP_MINUS },
156 	{"KP_PLUS",			K_KP_PLUS },
157 
158 	{"NUMLOCK",			K_NUMLOCK },
159 	{"SCROLLLOCK",		K_SCROLLLOCK },
160 	{"CAPSLOCK",		K_CAPSLOCK },
161 	{"PRINTSCREEN",		K_PRTSCR },
162 	{"LWINKEY",			K_LWINKEY },
163 	{"RWINKEY",			K_RWINKEY },
164 	{"APP",				K_APP },
165 
166 	{"MWHEELUP", K_MWHEELUP },
167 	{"MWHEELDOWN", K_MWHEELDOWN },
168 
169 	{"PAUSE", K_PAUSE},
170 
171 	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands
172 
173 	{NULL,0}
174 };
175 
176 /*
177 ==============================================================================
178 
179 			LINE TYPING INTO THE CONSOLE
180 
181 ==============================================================================
182 */
183 
Key_CompleteCommandOld(void)184 void Key_CompleteCommandOld (void)
185 {
186 	const char	*cmd;
187 	char		*s;
188 
189 	s = key_lines[edit_line]+1;
190 	if (*s == '\\' || *s == '/')
191 		s++;
192 
193 	cmd = Cmd_CompleteCommandOld (s);
194 	if (!cmd)
195 		cmd = Cvar_CompleteVariable (s);
196 	if (cmd)
197 	{
198 		key_lines[edit_line][1] = '/';
199 		strcpy (key_lines[edit_line]+2, cmd);
200 		key_linepos = (int)strlen(cmd)+2;
201 		key_lines[edit_line][key_linepos] = ' ';
202 		key_linepos++;
203 		key_lines[edit_line][key_linepos] = 0;
204 		return;
205 	}
206 }
207 
208 /*
209 ====================
210 Key_CompleteCommand
211 Stolen from Echon's EGL, echon.org but I'm sure he stole it from elsewhere :P
212 ====================
213 */
214 extern cmdalias_t	*cmd_alias;
215 extern cmd_function_t *cmd_functions;
216 
Key_CompleteCommand(void)217 static void Key_CompleteCommand (void) {
218 	cmd_function_t	*cmd, *cmdFound;
219 	cmdalias_t		*alias, *aliasFound;
220 	cvar_t			*cvar, *cvarFound;
221 	const char		*cmdName;
222 	char			*partial;
223 	int				aliasCnt, cmdCnt, cvarCnt, len, offset;
224 	qboolean		checkCmds = true;
225 
226 	partial = key_lines[edit_line]+1;
227 	// skip '/' and '\'
228 	if ((*partial == '\\') || (*partial == '/'))
229 	{
230 		offset = 1;
231 		partial++;
232 	}
233 	else
234 	{
235 		offset = 0;
236 	}
237 
238 	//r1ch: hack set completion
239 	if (!Q_strncasecmp (partial, "set ", 4))
240 	{
241 		checkCmds = false;
242 		partial += 4;
243 		offset += 4;
244 	}
245 	else if (!Q_strncasecmp (partial, "cvarhelp ", 9))
246 	{
247 		checkCmds = false;
248 		partial += 9;
249 		offset += 9;
250 	}
251 
252 	len = (int)strlen (partial);
253 
254 	if (!len)
255 		return;
256 
257 	cmdName = NULL;
258 
259 	cmd = cmdFound = NULL;
260 	alias = aliasFound = NULL;
261 	cvar = cvarFound = NULL;
262 	aliasCnt = cmdCnt = cvarCnt = 0;
263 
264 	//
265 	// check for exact match
266 	//
267 	if (checkCmds)
268 	{
269 		for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
270 		{
271 			if (!Q_stricmp (partial, cmd->name)) {
272 				///if (cmdCnt == 0)
273 				//{
274 					cmdCnt++;
275 					cmdFound = cmd;
276 				//}
277 				/*if (cmd->compFrame != compFrame)
278 					cmdCnt++;
279 				cmd->compFrame = compFrame;*/
280 			}
281 		}
282 
283 		for (alias=cmd_alias ; alias ; alias=alias->next)
284 		{
285 			if (!Q_stricmp (partial, alias->name)) {
286 				//if (aliasCnt == 0)
287 				//{
288 					aliasCnt++;
289 					aliasFound = alias;
290 				//}
291 				/*if (alias->compFrame != compFrame)
292 					aliasCnt++;
293 				alias->compFrame = compFrame;*/
294 			}
295 		}
296 	}
297 
298 	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
299 	{
300 		if (!Q_stricmp (partial, cvar->name)) {
301 			//if (cvarCnt == 0)
302 			//{
303 				cvarFound = cvar;
304 				cvarCnt++;
305 			//}
306 			/*if (cvar->compFrame != compFrame)
307 				cvarCnt++;
308 			cvar->compFrame = compFrame;*/
309 		}
310 	}
311 
312 	//
313 	// check for partial match
314 	//
315 	if (checkCmds)
316 	{
317 		for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
318 		{
319 			if (!Q_strncasecmp (partial, cmd->name, len)) {
320 				//if (cmdCnt == 0)
321 				//{
322 					cmdFound = cmd;
323 					cmdCnt++;
324 				//}
325 
326 				/*if (cmd->compFrame != compFrame)
327 					cmdCnt++;
328 				cmd->compFrame = compFrame;*/
329 			}
330 		}
331 
332 		for (alias=cmd_alias ; alias ; alias=alias->next)
333 		{
334 			if (!Q_strncasecmp (partial, alias->name, len)) {
335 				//if (aliasCnt == 0)
336 				//{
337 					aliasFound = alias;
338 					aliasCnt++;
339 				//}
340 				/*if (alias->compFrame != compFrame)
341 					aliasCnt++;
342 				alias->compFrame = compFrame;*/
343 			}
344 		}
345 	}
346 
347 	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
348 	{
349 		if (!Q_strncasecmp (partial, cvar->name, len)) {
350 			//if (cvarCnt == 0)
351 			//{
352 				cvarFound = cvar;
353 				cvarCnt++;
354 			//}
355 			/*if (cvar->compFrame != compFrame)
356 				cvarCnt++;
357 			cvar->compFrame = compFrame;*/
358 		}
359 	}
360 
361 	//
362 	// return a match if only one was found, otherwise list matches
363 	//
364 	if ((aliasCnt + cmdCnt + cvarCnt) == 1) {
365 		if (cmdFound)
366 			cmdName = cmdFound->name;
367 		else if (aliasFound)
368 			cmdName = aliasFound->name;
369 		else if (cvarFound)
370 			cmdName = cvarFound->name;
371 		else
372 			cmdName = NULL;
373 	} else {
374 		if (aliasCnt + cmdCnt + cvarCnt)
375 			Com_Printf ("\nPossible matches:\n", LOG_CLIENT);
376 		if (aliasCnt > 0) {
377 			//Cbuf_AddText ("echo ----\n echo Matching aliases:\n echo ----\n");
378 			Cbuf_AddText (va ("aliaslist %s\n", partial));
379 		}
380 
381 		if (cmdCnt > 0) {
382 			//Cbuf_AddText ("echo ----\n echo Matching commands:\n echo ----\n");
383 			Cbuf_AddText (va ("cmdlist %s\n", partial));
384 		}
385 
386 		if (cvarCnt > 0) {
387 			//Cbuf_AddText ("echo ----\n echo Matching cvars:\n echo ----\n");
388 			Cbuf_AddText (va ("cvarlist %s\n", partial));
389 		}
390 	}
391 
392 	if (cmdName)
393 	{
394 		int cmdLen;
395 		cmdLen = (int)strlen(cmdName);
396 		if (cmdLen + offset + 2 >= MAXCMDLINE)
397 		{
398 			Com_DPrintf ("Key_CompleteCommand: expansion would overflow command buffer\n");
399 			return;
400 		}
401 		//key_lines[edit_line][1] = '/';
402 		//memmove (key_lines[edit_line]+offset+1, key_lines[edit_line]+offset+1+cmdLen, offset);
403 		strcpy (key_lines[edit_line]+offset+1, cmdName);
404 		key_linepos = 1 + offset + cmdLen;
405 		key_lines[edit_line][key_linepos] = ' ';
406 		key_linepos++;
407 		key_lines[edit_line][key_linepos] = 0;
408 	}
409 }
410 
411 /*
412 ====================
413 Key_Console
414 
415 Interactive line editing and console scrollback
416 ====================
417 */
Key_Console(int key)418 void Key_Console (int key)
419 {
420 
421 	switch ( key )
422 	{
423 	case K_KP_SLASH:
424 		key = '/';
425 		break;
426 	case K_KP_MINUS:
427 		key = '-';
428 		break;
429 	case K_KP_PLUS:
430 		key = '+';
431 		break;
432 	case K_KP_HOME:
433 		key = '7';
434 		break;
435 	case K_KP_UPARROW:
436 		key = '8';
437 		break;
438 	case K_KP_PGUP:
439 		key = '9';
440 		break;
441 	case K_KP_LEFTARROW:
442 		key = '4';
443 		break;
444 	case K_KP_5:
445 		key = '5';
446 		break;
447 	case K_KP_RIGHTARROW:
448 		key = '6';
449 		break;
450 	case K_KP_END:
451 		key = '1';
452 		break;
453 	case K_KP_DOWNARROW:
454 		key = '2';
455 		break;
456 	case K_KP_PGDN:
457 		key = '3';
458 		break;
459 	case K_KP_INS:
460 		key = '0';
461 		break;
462 	case K_KP_DEL:
463 		key = '.';
464 		break;
465 	}
466 
467 	if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
468 		 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
469 	{
470 		char *cbd;
471 
472 		if ( ( cbd = Sys_GetClipboardData() ) != 0 )
473 		{
474 			int		i;
475 			char	*p, *s;
476 
477 			p = cbd;
478 			while ((p = strchr (p, '\r')))
479 				p[0] = ' ';
480 
481 			//r1: multiline paste
482 			p = strrchr (cbd, '\n');
483 			if (p)
484 			{
485 				s = strrchr (p, '\n');
486 				if (s)
487 				{
488 					s[0] = 0;
489 					p++;
490 					if (cbd[0])
491 					{
492 						Cbuf_AddText (cbd);
493 						Cbuf_AddText ("\n");
494 						Com_Printf ("%s\n", LOG_GENERAL, cbd);
495 					}
496 				}
497 			}
498 			else
499 				p = cbd;
500 
501 			i = (int)strlen( p );
502 
503 			//r1: save byte for null terminator!!
504 			if ( i + key_linepos >= MAXCMDLINE - 1)
505 				i = MAXCMDLINE - key_linepos - 1;
506 
507 			if ( i > 0 )
508 			{
509 				p[i]=0;
510 				strcat( key_lines[edit_line], p );
511 				key_linepos += i;
512 			}
513 			free( cbd );
514 		}
515 
516 		return;
517 	}
518 
519 	if ( key == 'l' )
520 	{
521 		if ( keydown[K_CTRL] )
522 		{
523 			Cbuf_AddText ("clear\n");
524 			return;
525 		}
526 	}
527 
528 	if ( key == K_ENTER || key == K_KP_ENTER )
529 	{	// backslash text are commands, else chat
530 		if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
531 			Cbuf_AddText (key_lines[edit_line]+2);	// skip the >
532 		else
533 			Cbuf_AddText (key_lines[edit_line]+1);	// valid command
534 
535 		Cbuf_AddText ("\n");
536 		Com_Printf ("%s\n", LOG_CLIENT,key_lines[edit_line]);
537 		edit_line = (edit_line + 1) & 31;
538 		history_line = edit_line;
539 		memset (key_lines[edit_line], 0, sizeof(key_lines[edit_line]));
540 		key_lines[edit_line][0] = ']';
541 		//key_lines[edit_line][1] = '\0';
542 		key_linepos = 1;
543 		if (cls.state == ca_disconnected)
544 			SCR_UpdateScreen ();	// force an update, because the command
545 									// may take some time
546 		return;
547 	}
548 
549 	//r1: command completion stolen from proquake
550 	if (key == K_TAB)
551 	{	// command completion
552 		if (cl_cmdcomplete->intvalue == 1)
553 		{
554 			const char *cmd;
555 			int len, i;
556 			char *fragment;
557 			cvar_t *var;
558 			const char *best = "~";
559 			const char *least = "~";
560 
561 			len = (int)strlen(key_lines[edit_line]);
562 			for (i = 0 ; i < len - 1 ; i++)
563 			{
564 				if (key_lines[edit_line][i] == ' ')
565 					return;
566 			}
567 			fragment = key_lines[edit_line] + 1;
568 
569 			len--;
570 			for (var = cvar_vars->next ; var ; var = var->next)
571 			{
572 				if (strcmp(var->name, fragment) >= 0 && strcmp(best, var->name) > 0)
573 					best = var->name;
574 				if (strcmp(var->name, least) < 0)
575 					least = var->name;
576 			}
577 			cmd = Cmd_CompleteCommand(fragment);
578 			//if (strcmp(cmd, fragment) >= 0 && strcmp(best, cmd) > 0)
579 			if (cmd)
580 				best = cmd;
581 			if (best[0] == '~')
582 			{
583 				cmd = Cmd_CompleteCommand(" ");
584 				if (strcmp(cmd, least) < 0)
585 					best = cmd;
586 				else
587 					best = least;
588 			}
589 
590 			//r1: maybe completing cvar/cmd from net?
591 			snprintf(key_lines[edit_line], sizeof(key_lines[edit_line])-1, "]%s ", best);
592 			key_lines[edit_line][sizeof(key_lines[edit_line])-1] = 0;
593 
594 			key_linepos = (int)strlen(key_lines[edit_line]);
595 		}
596 		else if (cl_cmdcomplete->value == 2)
597 		{
598 			Key_CompleteCommand();
599 		}
600 		else
601 		{
602 			Key_CompleteCommandOld();
603 		}
604 		return;
605 	}
606 
607 	if ( key == K_LEFTARROW )
608 	{
609 		if (key_linepos > 1)
610 			key_linepos--;
611 		return;
612 	}
613 
614 	if (key == K_RIGHTARROW)
615 	{
616 		if (key_lines[edit_line][key_linepos])
617 			key_linepos++;
618 		return;
619 	}
620 
621 	if ( ( key == K_BACKSPACE ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
622 	{
623 		if (key_linepos > 1)
624 		{
625 			memmove (key_lines[edit_line] + key_linepos-1, key_lines[edit_line] + key_linepos, sizeof(key_lines[edit_line])-key_linepos);
626 			key_linepos--;
627 		}
628 		return;
629 	}
630 
631 	if ( key == K_DEL )
632 	{
633 		memmove (key_lines[edit_line] + key_linepos, key_lines[edit_line] + key_linepos + 1, sizeof(key_lines[edit_line])-key_linepos-1);
634 		return;
635 	}
636 
637 	if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
638 		 ( ( key == 'p' ) && keydown[K_CTRL] ) )
639 	{
640 		do
641 		{
642 			history_line = (history_line - 1) & 31;
643 		} while (history_line != edit_line
644 				&& !key_lines[history_line][1]);
645 		if (history_line == edit_line)
646 			history_line = (edit_line+1)&31;
647 		strcpy(key_lines[edit_line], key_lines[history_line]);
648 		key_linepos = (int)strlen(key_lines[edit_line]);
649 		return;
650 	}
651 
652 	if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
653 		 ( ( key == 'n' ) && keydown[K_CTRL] ) )
654 	{
655 		if (history_line == edit_line) return;
656 		do
657 		{
658 			history_line = (history_line + 1) & 31;
659 		}
660 		while (history_line != edit_line
661 			&& !key_lines[history_line][1]);
662 		if (history_line == edit_line)
663 		{
664 			key_lines[edit_line][0] = ']';
665 			key_lines[edit_line][1] = '\0';
666 			key_linepos = 1;
667 		}
668 		else
669 		{
670 			strcpy(key_lines[edit_line], key_lines[history_line]);
671 			key_linepos = (int)strlen(key_lines[edit_line]);
672 		}
673 		return;
674 	}
675 
676 	if (key == K_PGUP || key == K_KP_PGUP )
677 	{
678 		con.display -= 2;
679 		return;
680 	}
681 
682 	if (key == K_PGDN || key == K_KP_PGDN )
683 	{
684 		con.display += 2;
685 		if (con.display > con.current)
686 			con.display = con.current;
687 		return;
688 	}
689 
690 	if (key == K_HOME || key == K_KP_HOME )
691 	{
692 		if (keydown[K_CTRL] || !key_lines[edit_line][1] || key_linepos == 1)
693 			con.display = con.current - con.totallines + 10;
694 		else
695 			key_linepos = 1;
696 		return;
697 	}
698 
699 	if (key == K_END || key == K_KP_END )
700 	{
701 		int		len;
702 
703 		len = (int)strlen(key_lines[edit_line]);
704 
705 		if (keydown[K_CTRL] || !key_lines[edit_line][1] || key_linepos == len)
706 			con.display = con.current;
707 		else
708 			key_linepos = len;
709 		return;
710 	}
711 
712 	if (key < 32 || key > 127)
713 		return;	// non printable
714 
715 	if (key_linepos < MAXCMDLINE-1)
716 	{
717 		int		last;
718 		int		length;
719 
720 		length = (int)strlen(key_lines[edit_line]);
721 
722 		if (length >= MAXCMDLINE-1)
723 			return;
724 
725 		last = key_lines[edit_line][length];
726 
727 		memmove (key_lines[edit_line] + key_linepos+1, key_lines[edit_line] + key_linepos, length - key_linepos);
728 
729 		key_lines[edit_line][key_linepos] = key;
730 		key_linepos++;
731 
732 		if (!last)
733 			key_lines[edit_line][length+1] = 0;
734 	}
735 }
736 
737 //============================================================================
738 
739 char		chat_custom_cmd[32];
740 char		chat_custom_prompt[32];
741 int			chat_mode;
742 char		chat_buffer[8][MAXCMDLINE];
743 int			chat_curbuffer = 0;
744 int			chat_bufferlen = 0;
745 int			chat_cursorpos = 0;
746 int			chat_editbuffer = 0;
747 
Key_Message(int key)748 void Key_Message (int key)
749 {
750 	char	last;
751 
752 	if ( key == K_ENTER || key == K_KP_ENTER )
753 	{
754 		switch (chat_mode)
755 		{
756 		case CHAT_MODE_PUBLIC:
757 			Cbuf_AddText ("say \"");
758 			break;
759 		case CHAT_MODE_TEAM:
760 			Cbuf_AddText ("say_team \"");
761 			break;
762 		case CHAT_MODE_CUSTOM:
763 			Cbuf_AddText (chat_custom_cmd);
764 			Cbuf_AddText (" \"");
765 			break;
766 		default:
767 			Com_Error (ERR_DROP, "Bad chat_mode");
768 			break;
769 		}
770 		Cbuf_AddText(chat_buffer[chat_curbuffer]);
771 		Cbuf_AddText("\"\n");
772 
773 		cls.key_dest = key_game;
774 
775 		chat_curbuffer = (chat_curbuffer + 1) & 7;
776 		chat_editbuffer = chat_curbuffer;
777 
778 		chat_bufferlen = 0;
779 		chat_buffer[chat_curbuffer][0] = 0;
780 		chat_cursorpos = 0;
781 		return;
782 	}
783 
784 	if (key == K_UPARROW)
785 	{
786 		chat_curbuffer--;
787 		if (chat_curbuffer < 0)
788 			chat_curbuffer = 7;
789 
790 		//ugly :E
791 		if (chat_curbuffer == chat_editbuffer)
792 		{
793 			chat_curbuffer++;
794 			if (chat_curbuffer > 7)
795 				chat_curbuffer = 0;
796 		}
797 
798 		chat_bufferlen = chat_cursorpos = (int)strlen(chat_buffer[chat_curbuffer]);
799 		return;
800 	}
801 
802 	if (key == K_DOWNARROW)
803 	{
804 		if (chat_curbuffer == chat_editbuffer)
805 			return;
806 
807 		chat_curbuffer++;
808 		if (chat_curbuffer > 7)
809 			chat_curbuffer = 0;
810 
811 		chat_bufferlen = chat_cursorpos = (int)strlen(chat_buffer[chat_curbuffer]);
812 		return;
813 	}
814 
815 	if (key == K_ESCAPE)
816 	{
817 		cls.key_dest = key_game;
818 		chat_cursorpos = 0;
819 		chat_bufferlen = 0;
820 		chat_buffer[chat_curbuffer][0] = 0;
821 		return;
822 	}
823 
824 	if (key == K_BACKSPACE)
825 	{
826 		if (chat_cursorpos)
827 		{
828 			//chat_bufferlen--;
829 			//chat_buffer[chat_bufferlen] = 0;
830 			memmove (chat_buffer[chat_curbuffer] + chat_cursorpos - 1, chat_buffer[chat_curbuffer] + chat_cursorpos, chat_bufferlen - chat_cursorpos + 1);
831 			chat_cursorpos--;
832 			chat_bufferlen--;
833 		}
834 		return;
835 	}
836 
837 	if (key == K_DEL)
838 	{
839 		if (chat_bufferlen && chat_cursorpos != chat_bufferlen)
840 		{
841 			memmove (chat_buffer[chat_curbuffer] + chat_cursorpos, chat_buffer[chat_curbuffer] + chat_cursorpos + 1, chat_bufferlen - chat_cursorpos + 1);
842 			chat_bufferlen--;
843 		}
844 		return;
845 	}
846 
847 	if (key == K_LEFTARROW)
848 	{
849 		if (chat_cursorpos > 0)
850 			chat_cursorpos--;
851 		return;
852 	}
853 
854 	if (key == K_HOME)
855 	{
856 		chat_cursorpos = 0;
857 		return;
858 	}
859 
860 	if (key == K_END)
861 	{
862 		chat_cursorpos = chat_bufferlen;
863 		return;
864 	}
865 
866 	if (key == K_RIGHTARROW)
867 	{
868 		if (chat_buffer[chat_curbuffer][chat_cursorpos])
869 			chat_cursorpos++;
870 		return;
871 	}
872 
873 	if (key < 32 || key > 127)
874 		return;	// non printable
875 
876 	if (chat_bufferlen == sizeof(chat_buffer[chat_curbuffer])-1)
877 		return; // all full
878 
879 	memmove (chat_buffer[chat_curbuffer] + chat_cursorpos + 1, chat_buffer[chat_curbuffer] + chat_cursorpos, chat_bufferlen - chat_cursorpos + 1);
880 
881 	last = chat_buffer[chat_curbuffer][chat_cursorpos];
882 
883 	chat_buffer[chat_curbuffer][chat_cursorpos] = key;
884 
885 	chat_bufferlen++;
886 	chat_cursorpos++;
887 
888 	if (!last)
889 	{
890 		chat_buffer[chat_curbuffer][chat_cursorpos] = 0;
891 	}
892 }
893 
894 //============================================================================
895 
896 
897 /*
898 ===================
899 Key_StringToKeynum
900 
901 Returns a key number to be used to index keybindings[] by looking at
902 the given string.  Single ascii characters return themselves, while
903 the K_* names are matched up.
904 ===================
905 */
Key_StringToKeynum(char * str)906 int Key_StringToKeynum (char *str)
907 {
908 	keyname_t	*kn;
909 
910 	if (!str || !str[0])
911 		return -1;
912 	if (!str[1])
913 		return str[0];
914 
915 	for (kn=keynames ; kn->name ; kn++)
916 	{
917 		if (!Q_stricmp(str,kn->name))
918 			return kn->keynum;
919 	}
920 	return -1;
921 }
922 
923 /*
924 ===================
925 Key_KeynumToString
926 
927 Returns a string (either a single ascii char, or a K_* name) for the
928 given keynum.
929 FIXME: handle quote special (general escape sequence?)
930 ===================
931 */
Key_KeynumToString(int keynum)932 char *Key_KeynumToString (int keynum)
933 {
934 	keyname_t	*kn;
935 	static	char	tinystr[2] = {0};
936 
937 	if (keynum == -1)
938 		return "<KEY NOT FOUND>";
939 
940 	if (keynum > 32 && keynum < 127)
941 	{	// printable ascii
942 		tinystr[0] = keynum;
943 		//tinystr[1] = 0;
944 		return tinystr;
945 	}
946 
947 	for (kn=keynames ; kn->name ; kn++)
948 		if (keynum == kn->keynum)
949 			return kn->name;
950 
951 	return "<UNKNOWN KEYNUM>";
952 }
953 
954 
955 /*
956 ===================
957 Key_SetBinding
958 ===================
959 */
Key_SetBinding(int keynum,char * binding)960 void Key_SetBinding (int keynum, char *binding)
961 {
962 	char	*newKey;
963 
964 	if (keynum == -1)
965 		return;
966 
967 // free old bindings
968 	if (keybindings[keynum])
969 	{
970 		Z_Free (keybindings[keynum]);
971 		keybindings[keynum] = NULL;
972 	}
973 
974 // allocate memory for new binding
975 	//l = strlen (binding);
976 	//newKey = Z_TagMalloc (l+1, TAGMALLOC_CLIENT_KEYBIND);
977 	//strcpy (newKey, binding);
978 	//newKey[l] = 0;
979 	newKey = CopyString (binding, TAGMALLOC_CLIENT_KEYBIND);
980 	keybindings[keynum] = newKey;
981 }
982 
983 /*
984 ===================
985 Key_Unbind_f
986 ===================
987 */
Key_Unbind_f(void)988 void Key_Unbind_f (void)
989 {
990 	int		b;
991 
992 	if (Cmd_Argc() != 2)
993 	{
994 		Com_Printf ("unbind <key> : remove commands from a key\n", LOG_CLIENT);
995 		return;
996 	}
997 
998 	b = Key_StringToKeynum (Cmd_Argv(1));
999 	if (b==-1)
1000 	{
1001 		Com_Printf ("\"%s\" isn't a valid key\n", LOG_CLIENT, Cmd_Argv(1));
1002 		return;
1003 	}
1004 
1005 	Key_SetBinding (b, "");
1006 }
1007 
Key_Unbindall_f(void)1008 void Key_Unbindall_f (void)
1009 {
1010 	int		i;
1011 
1012 	for (i=0 ; i<256 ; i++)
1013 		if (keybindings[i])
1014 			Key_SetBinding (i, "");
1015 }
1016 
1017 
1018 /*
1019 ===================
1020 Key_Bind_f
1021 ===================
1022 */
Key_Bind_f(void)1023 void Key_Bind_f (void)
1024 {
1025 	int			i, c, b;
1026 	char		cmd[1024];
1027 
1028 	c = Cmd_Argc();
1029 
1030 	if (c < 2)
1031 	{
1032 		Com_Printf ("bind <key> [command] : attach a command to a key\n", LOG_CLIENT);
1033 		return;
1034 	}
1035 	b = Key_StringToKeynum (Cmd_Argv(1));
1036 	if (b==-1)
1037 	{
1038 		Com_Printf ("\"%s\" isn't a valid key\n", LOG_CLIENT, Cmd_Argv(1));
1039 		return;
1040 	}
1041 
1042 	if (c == 2)
1043 	{
1044 		if (keybindings[b])
1045 			Com_Printf ("\"%s\" = \"%s\"\n", LOG_CLIENT, Cmd_Argv(1), keybindings[b] );
1046 		else
1047 			Com_Printf ("\"%s\" is not bound\n", LOG_CLIENT, Cmd_Argv(1) );
1048 		return;
1049 	}
1050 
1051 // copy the rest of the command line
1052 	cmd[0] = 0;		// start out with a null string
1053 	for (i=2 ; i< c ; i++)
1054 	{
1055 		strcat (cmd, Cmd_Argv(i));
1056 		if (i != (c-1))
1057 			strcat (cmd, " ");
1058 	}
1059 
1060 	Key_SetBinding (b, cmd);
1061 }
1062 
1063 /*
1064 ============
1065 Key_WriteBindings
1066 
1067 Writes lines containing "bind key value"
1068 ============
1069 */
Key_WriteBindings(FILE * f)1070 void Key_WriteBindings (FILE *f)
1071 {
1072 	int		i;
1073 
1074 	for (i=0 ; i<256 ; i++)
1075 		if (keybindings[i] && keybindings[i][0])
1076 			fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
1077 }
1078 
1079 
1080 /*
1081 ============
1082 Key_Bindlist_f
1083 
1084 ============
1085 */
Key_Bindlist_f(void)1086 void Key_Bindlist_f (void)
1087 {
1088 	int		i;
1089 
1090 	for (i=0 ; i<256 ; i++)
1091 		if (keybindings[i] && keybindings[i][0])
1092 			Com_Printf ("%s \"%s\"\n", LOG_CLIENT, Key_KeynumToString(i), keybindings[i]);
1093 }
1094 
1095 
1096 /*
1097 ===================
1098 Key_Init
1099 ===================
1100 */
Key_Init(void)1101 void Key_Init (void)
1102 {
1103 	int		i;
1104 
1105 	for (i=0 ; i<32 ; i++)
1106 	{
1107 		key_lines[i][0] = ']';
1108 		key_lines[i][1] = 0;
1109 	}
1110 	key_linepos = 1;
1111 
1112 //
1113 // init ascii characters in console mode
1114 //
1115 	for (i=32 ; i<128 ; i++)
1116 		consolekeys[i] = true;
1117 	consolekeys[K_ENTER] = true;
1118 	consolekeys[K_KP_ENTER] = true;
1119 	consolekeys[K_TAB] = true;
1120 	consolekeys[K_LEFTARROW] = true;
1121 	consolekeys[K_KP_LEFTARROW] = true;
1122 	consolekeys[K_RIGHTARROW] = true;
1123 	consolekeys[K_KP_RIGHTARROW] = true;
1124 	consolekeys[K_UPARROW] = true;
1125 	consolekeys[K_KP_UPARROW] = true;
1126 	consolekeys[K_DOWNARROW] = true;
1127 	consolekeys[K_KP_DOWNARROW] = true;
1128 	consolekeys[K_BACKSPACE] = true;
1129 	consolekeys[K_HOME] = true;
1130 	consolekeys[K_KP_HOME] = true;
1131 	consolekeys[K_END] = true;
1132 	consolekeys[K_KP_END] = true;
1133 	consolekeys[K_PGUP] = true;
1134 	consolekeys[K_KP_PGUP] = true;
1135 	consolekeys[K_PGDN] = true;
1136 	consolekeys[K_KP_PGDN] = true;
1137 	consolekeys[K_SHIFT] = true;
1138 	consolekeys[K_INS] = true;
1139 	consolekeys[K_KP_INS] = true;
1140 	consolekeys[K_KP_DEL] = true;
1141 	consolekeys[K_KP_SLASH] = true;
1142 	consolekeys[K_KP_PLUS] = true;
1143 	consolekeys[K_KP_MINUS] = true;
1144 	consolekeys[K_KP_5] = true;
1145 
1146 	consolekeys['`'] = true;
1147 	consolekeys['~'] = true;
1148 	consolekeys[K_DEL] = true;
1149 
1150 	for (i=0 ; i<256 ; i++)
1151 		keyshift[i] = i;
1152 	for (i='a' ; i<='z' ; i++)
1153 		keyshift[i] = i - 'a' + 'A';
1154 	keyshift['1'] = '!';
1155 	keyshift['2'] = '@';
1156 	keyshift['3'] = '#';
1157 	keyshift['4'] = '$';
1158 	keyshift['5'] = '%';
1159 	keyshift['6'] = '^';
1160 	keyshift['7'] = '&';
1161 	keyshift['8'] = '*';
1162 	keyshift['9'] = '(';
1163 	keyshift['0'] = ')';
1164 	keyshift['-'] = '_';
1165 	keyshift['='] = '+';
1166 	keyshift[','] = '<';
1167 	keyshift['.'] = '>';
1168 	keyshift['/'] = '?';
1169 	keyshift[';'] = ':';
1170 	keyshift['\''] = '"';
1171 	keyshift['['] = '{';
1172 	keyshift[']'] = '}';
1173 	keyshift['`'] = '~';
1174 	keyshift['\\'] = '|';
1175 
1176 	menubound[K_ESCAPE] = true;
1177 	for (i=0 ; i<12 ; i++)
1178 		menubound[K_F1+i] = true;
1179 
1180 //
1181 // register our functions
1182 //
1183 	Cmd_AddCommand ("bind",Key_Bind_f);
1184 	Cmd_AddCommand ("unbind",Key_Unbind_f);
1185 	Cmd_AddCommand ("unbindall",Key_Unbindall_f);
1186 	Cmd_AddCommand ("bindlist",Key_Bindlist_f);
1187 
1188 	cl_cmdcomplete = Cvar_Get ("cl_cmdcomplete", "0", 0);
1189 }
1190 
Key_GenerateRepeats(void)1191 void Key_GenerateRepeats (void)
1192 {
1193 	int		i;
1194 
1195 	for (i = 0; i < 256; i++)
1196 	{
1197 		if (keydown[i])
1198 		{
1199 			if (curtime >= key_lastrepeat[i] + key_repeatrate)
1200 			{
1201 				Key_Event (i, true, curtime);
1202 				key_lastrepeat[i] = curtime;
1203 			}
1204 		}
1205 	}
1206 }
1207 
1208 /*
1209 ===================
1210 Key_Event
1211 
1212 Called by the system between frames for both key up and key down events
1213 Should NOT be called during an interrupt!
1214 ===================
1215 */
Key_Event(int key,qboolean down,uint32 time)1216 void Key_Event (int key, qboolean down, uint32 time)
1217 {
1218 	char		*kb;
1219 	char		cmd[1024];
1220 
1221 	// hack for modal presses
1222 	/*if (key_waiting == -1)
1223 	{
1224 		if (down)
1225 			key_waiting = key;
1226 		return;
1227 		}*/
1228 
1229 	//Com_Printf ("%d is %d for %u\n", LOG_GENERAL, key, down, time);
1230 
1231 	// update auto-repeat status
1232 	if (down)
1233 	{
1234 		key_repeats[key]++;
1235 		if (cls.key_dest != key_console && key != K_BACKSPACE && key != K_DEL && key != K_LEFTARROW && key != K_RIGHTARROW
1236 			&& key != K_PAUSE
1237 			&& key != K_PGUP
1238 			&& key != K_KP_PGUP
1239 			&& key != K_PGDN
1240 			&& key != K_KP_PGDN
1241 			&& key_repeats[key] > 1)
1242 			return;	// ignore most autorepeats
1243 
1244 		if (key >= 200 && !keybindings[key])
1245 			Com_Printf ("%s is unbound, hit F4 to set.\n", LOG_CLIENT, Key_KeynumToString (key) );
1246 	}
1247 	else
1248 	{
1249 		key_repeats[key] = 0;
1250 	}
1251 
1252 	//for dinput
1253 	if (down && keydown[K_ALT])
1254 	{
1255 		if (key == K_ENTER)
1256 		{
1257 			Com_Printf ("ALT+Enter, setting fullscreen %d.\n", LOG_CLIENT, !vid_fullscreen->intvalue);
1258 			Cvar_SetValue( "vid_fullscreen", (float)!vid_fullscreen->intvalue );
1259 			return;
1260 		}
1261 		else if (key == K_TAB)
1262 		{
1263 			//prevent executing action on alt+tab
1264 			return;
1265 		}
1266 	}
1267 
1268 	if (key == K_SHIFT)
1269 		shift_down = down;
1270 
1271 	// console key is hardcoded, so the user can never unbind it
1272 	if ((key == '`' || key == '~') && !shift_down)
1273 	{
1274 		if (!down)
1275 			return;
1276 		Con_ToggleConsole_f ();
1277 		return;
1278 	}
1279 
1280 	// any key during the attract mode will bring up the menu
1281 	/*if (cl.attractloop && cls.key_dest != key_menu &&
1282 		!(key >= K_F1 && key <= K_F12))
1283 		key = K_ESCAPE;*/
1284 
1285 	// menu key is hardcoded, so the user can never unbind it
1286 	if (key == K_ESCAPE)
1287 	{
1288 		if (!down)
1289 			return;
1290 
1291 		if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
1292 		{	// put away help computer / inventory
1293 			Cbuf_AddText ("cmd putaway\n");
1294 			return;
1295 		}
1296 		switch (cls.key_dest)
1297 		{
1298 		case key_message:
1299 			Key_Message (key);
1300 			break;
1301 		case key_menu:
1302 			M_Keydown (key);
1303 			break;
1304 		case key_game:
1305 		case key_console:
1306 			M_Menu_Main_f ();
1307 			break;
1308 		default:
1309 			Com_Error (ERR_FATAL, "Bad cls.key_dest");
1310 		}
1311 		return;
1312 	}
1313 
1314 	if (!keydown[key])
1315 		key_lastrepeat[key] = curtime + key_repeatdelay;
1316 
1317 	// track if any key is down for BUTTON_ANY
1318 	keydown[key] = down;
1319 	if (down)
1320 	{
1321 		if (key_repeats[key] == 1)
1322 			anykeydown++;
1323 	}
1324 	else
1325 	{
1326 		key_lastrepeat[key] = 0;
1327 
1328 		anykeydown--;
1329 		if (anykeydown < 0)
1330 			anykeydown = 0;
1331 	}
1332 
1333 //
1334 // key up events only generate commands if the game key binding is
1335 // a button command (leading + sign).  These will occur even in console mode,
1336 // to keep the character from continuing an action started before a console
1337 // switch.  Button commands include the kenum as a parameter, so multiple
1338 // downs can be matched with ups
1339 //
1340 	if (!down)
1341 	{
1342 		//r1ch: only generate -events if key was down (prevents -binds in menu / messagemode)
1343 		if (buttondown[key])
1344 		{
1345 			kb = keybindings[key];
1346 			if (kb && kb[0] == '+')
1347 			{
1348 				Com_sprintf (cmd, sizeof(cmd), "-%s %i %u\n", kb+1, key, time);
1349 				Cbuf_AddText (cmd);
1350 			}
1351 			if (keyshift[key] != key)
1352 			{
1353 				kb = keybindings[keyshift[key]];
1354 				if (kb && kb[0] == '+')
1355 				{
1356 					Com_sprintf (cmd, sizeof(cmd), "-%s %i %u\n", kb+1, key, time);
1357 					Cbuf_AddText (cmd);
1358 				}
1359 			}
1360 			buttondown[key] = false;
1361 		}
1362 		return;
1363 	}
1364 
1365 //
1366 // if not a consolekey, send to the interpreter no matter what mode is
1367 //
1368 	if ( (cls.key_dest == key_menu && menubound[key])
1369 	|| (cls.key_dest == key_console && !consolekeys[key])
1370 	|| (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
1371 	{
1372 		kb = keybindings[key];
1373 		if (kb && kb[0])
1374 		{
1375 			if (kb[0] == '+')
1376 			{
1377 				// button commands add keynum and time as a parm
1378 				if (cls.key_dest != key_game) //r1: don't run buttons in console
1379 					return;
1380 				Com_sprintf (cmd, sizeof(cmd), "%s %i %u\n", kb, key, time);
1381 				Cbuf_AddText (cmd);
1382 				buttondown[key] = true;
1383 			}
1384 			else
1385 			{
1386 				Cbuf_AddText (kb);
1387 				Cbuf_AddText ("\n");
1388 			}
1389 		}
1390 		return;
1391 	}
1392 
1393 	//if (!down)
1394 	//	return;		// other systems only care about key down events
1395 
1396 	if (shift_down)
1397 		key = keyshift[key];
1398 
1399 	switch (cls.key_dest)
1400 	{
1401 	case key_message:
1402 		Key_Message (key);
1403 		break;
1404 	case key_menu:
1405 		M_Keydown (key);
1406 		break;
1407 
1408 	case key_game:
1409 	case key_console:
1410 		Key_Console (key);
1411 		break;
1412 	default:
1413 		Com_Error (ERR_FATAL, "Bad cls.key_dest");
1414 	}
1415 }
1416 
1417 /*
1418 ===================
1419 Key_ClearStates
1420 ===================
1421 */
Key_ClearStates(void)1422 void Key_ClearStates (void)
1423 {
1424 	int		i;
1425 
1426 	anykeydown = false;
1427 
1428 	for (i=0 ; i<256 ; i++)
1429 	{
1430 		if ( keydown[i] || key_repeats[i] )
1431 			Key_Event( i, false, 0 );
1432 		keydown[i] = 0;
1433 		key_repeats[i] = 0;
1434 		key_lastrepeat[i] = 0;
1435 	}
1436 }
1437 
1438 
1439 /*
1440 ===================
1441 Key_GetKey
1442 ===================
1443 */
1444 /*int Key_GetKey (void)
1445 {
1446 	key_waiting = -1;
1447 
1448 	while (key_waiting == -1)
1449 		Sys_SendKeyEvents ();
1450 
1451 	return key_waiting;
1452 }*/
1453 
1454