1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20#include "quakedef.h"
21
22/*
23
24key up events are sent even if in console mode
25
26*/
27
28
29#define		MAXCMDLINE	256
30char	key_lines[32][MAXCMDLINE];
31int		key_linepos;
32int		shift_down=false;
33int		key_lastpress;
34
35int		edit_line=0;
36int		history_line=0;
37
38keydest_t	key_dest;
39
40int		key_count;			// incremented every key event
41
42char	*keybindings[256];
43qboolean	consolekeys[256];	// if true, can't be rebound while in console
44qboolean	menubound[256];	// if true, can't be rebound while in menu
45int		keyshift[256];		// key to map to if shift held down in console
46int		key_repeats[256];	// if > 1, it is autorepeating
47qboolean	keydown[256];
48
49typedef struct
50{
51	const char	*name;
52	int		keynum;
53} keyname_t;
54
55keyname_t keynames[] =
56{
57	{"TAB", K_TAB},
58	{"ENTER", K_ENTER},
59	{"ESCAPE", K_ESCAPE},
60	{"SPACE", K_SPACE},
61	{"BACKSPACE", K_BACKSPACE},
62	{"UPARROW", K_UPARROW},
63	{"DOWNARROW", K_DOWNARROW},
64	{"LEFTARROW", K_LEFTARROW},
65	{"RIGHTARROW", K_RIGHTARROW},
66
67	{"ALT", K_ALT},
68	{"CTRL", K_CTRL},
69	{"SHIFT", K_SHIFT},
70
71	{"F1", K_F1},
72	{"F2", K_F2},
73	{"F3", K_F3},
74	{"F4", K_F4},
75	{"F5", K_F5},
76	{"F6", K_F6},
77	{"F7", K_F7},
78	{"F8", K_F8},
79	{"F9", K_F9},
80	{"F10", K_F10},
81	{"F11", K_F11},
82	{"F12", K_F12},
83
84	{"INS", K_INS},
85	{"DEL", K_DEL},
86	{"PGDN", K_PGDN},
87	{"PGUP", K_PGUP},
88	{"HOME", K_HOME},
89	{"END", K_END},
90
91	{"MOUSE1", K_MOUSE1},
92	{"MOUSE2", K_MOUSE2},
93	{"MOUSE3", K_MOUSE3},
94
95	{"JOY1", K_JOY1},
96	{"JOY2", K_JOY2},
97	{"JOY3", K_JOY3},
98	{"JOY4", K_JOY4},
99
100	{"AUX1", K_AUX1},
101	{"AUX2", K_AUX2},
102	{"AUX3", K_AUX3},
103	{"AUX4", K_AUX4},
104	{"AUX5", K_AUX5},
105	{"AUX6", K_AUX6},
106	{"AUX7", K_AUX7},
107	{"AUX8", K_AUX8},
108	{"AUX9", K_AUX9},
109	{"AUX10", K_AUX10},
110	{"AUX11", K_AUX11},
111	{"AUX12", K_AUX12},
112	{"AUX13", K_AUX13},
113	{"AUX14", K_AUX14},
114	{"AUX15", K_AUX15},
115	{"AUX16", K_AUX16},
116	{"AUX17", K_AUX17},
117	{"AUX18", K_AUX18},
118	{"AUX19", K_AUX19},
119	{"AUX20", K_AUX20},
120	{"AUX21", K_AUX21},
121	{"AUX22", K_AUX22},
122	{"AUX23", K_AUX23},
123	{"AUX24", K_AUX24},
124	{"AUX25", K_AUX25},
125	{"AUX26", K_AUX26},
126	{"AUX27", K_AUX27},
127	{"AUX28", K_AUX28},
128	{"AUX29", K_AUX29},
129	{"AUX30", K_AUX30},
130	{"AUX31", K_AUX31},
131	{"AUX32", K_AUX32},
132
133	{"PAUSE", K_PAUSE},
134
135	{"MWHEELUP", K_MWHEELUP},
136	{"MWHEELDOWN", K_MWHEELDOWN},
137
138	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands
139
140	{NULL,0}
141};
142
143/*
144==============================================================================
145
146			LINE TYPING INTO THE CONSOLE
147
148==============================================================================
149*/
150
151
152/*
153====================
154Key_Console
155
156Interactive line editing and console scrollback
157====================
158*/
159void Key_Console (int key)
160{
161	const char	*cmd;
162
163	if (key == K_ENTER)
164	{
165		Cbuf_AddText (key_lines[edit_line]+1);	// skip the >
166		Cbuf_AddText ("\n");
167		Con_Printf ("%s\n",key_lines[edit_line]);
168		edit_line = (edit_line + 1) & 31;
169		history_line = edit_line;
170		key_lines[edit_line][0] = ']';
171		key_linepos = 1;
172		if (cls.state == ca_disconnected)
173			SCR_UpdateScreen ();	// force an update, because the command
174									// may take some time
175		return;
176	}
177
178	if (key == K_TAB)
179	{	// command completion
180		cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);
181		if (!cmd)
182			cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);
183		if (cmd)
184		{
185			Q_strcpy (key_lines[edit_line]+1, cmd);
186			key_linepos = Q_strlen(cmd)+1;
187			key_lines[edit_line][key_linepos] = ' ';
188			key_linepos++;
189			key_lines[edit_line][key_linepos] = 0;
190			return;
191		}
192	}
193
194	if (key == K_BACKSPACE || key == K_LEFTARROW)
195	{
196		if (key_linepos > 1)
197			key_linepos--;
198		return;
199	}
200
201	if (key == K_UPARROW)
202	{
203		do
204		{
205			history_line = (history_line - 1) & 31;
206		} while (history_line != edit_line
207				&& !key_lines[history_line][1]);
208		if (history_line == edit_line)
209			history_line = (edit_line+1)&31;
210		Q_strcpy(key_lines[edit_line], key_lines[history_line]);
211		key_linepos = Q_strlen(key_lines[edit_line]);
212		return;
213	}
214
215	if (key == K_DOWNARROW)
216	{
217		if (history_line == edit_line) return;
218		do
219		{
220			history_line = (history_line + 1) & 31;
221		}
222		while (history_line != edit_line
223			&& !key_lines[history_line][1]);
224		if (history_line == edit_line)
225		{
226			key_lines[edit_line][0] = ']';
227			key_linepos = 1;
228		}
229		else
230		{
231			Q_strcpy(key_lines[edit_line], key_lines[history_line]);
232			key_linepos = Q_strlen(key_lines[edit_line]);
233		}
234		return;
235	}
236
237	if (key == K_PGUP || key==K_MWHEELUP)
238	{
239		con_backscroll += 2;
240		if (con_backscroll > (int)(con_totallines - (vid.height>>3) - 1))
241			con_backscroll = (int)(con_totallines - (vid.height>>3) - 1);
242		return;
243	}
244
245	if (key == K_PGDN || key==K_MWHEELDOWN)
246	{
247		con_backscroll -= 2;
248		if (con_backscroll < 0)
249			con_backscroll = 0;
250		return;
251	}
252
253	if (key == K_HOME)
254	{
255		con_backscroll = con_totallines - (vid.height>>3) - 1;
256		return;
257	}
258
259	if (key == K_END)
260	{
261		con_backscroll = 0;
262		return;
263	}
264
265	if (key < 32 || key > 127)
266		return;	// non printable
267
268	if (key_linepos < MAXCMDLINE-1)
269	{
270		key_lines[edit_line][key_linepos] = key;
271		key_linepos++;
272		key_lines[edit_line][key_linepos] = 0;
273	}
274
275}
276
277//============================================================================
278
279char chat_buffer[32];
280qboolean team_message = false;
281
282void Key_Message (int key)
283{
284	static int chat_bufferlen = 0;
285
286	if (key == K_ENTER)
287	{
288		if (team_message)
289			Cbuf_AddText ("say_team \"");
290		else
291			Cbuf_AddText ("say \"");
292		Cbuf_AddText(chat_buffer);
293		Cbuf_AddText("\"\n");
294
295		key_dest = key_game;
296		chat_bufferlen = 0;
297		chat_buffer[0] = 0;
298		return;
299	}
300
301	if (key == K_ESCAPE)
302	{
303		key_dest = key_game;
304		chat_bufferlen = 0;
305		chat_buffer[0] = 0;
306		return;
307	}
308
309	if (key < 32 || key > 127)
310		return;	// non printable
311
312	if (key == K_BACKSPACE)
313	{
314		if (chat_bufferlen)
315		{
316			chat_bufferlen--;
317			chat_buffer[chat_bufferlen] = 0;
318		}
319		return;
320	}
321
322	if (chat_bufferlen == 31)
323		return; // all full
324
325	chat_buffer[chat_bufferlen++] = key;
326	chat_buffer[chat_bufferlen] = 0;
327}
328
329//============================================================================
330
331
332/*
333===================
334Key_StringToKeynum
335
336Returns a key number to be used to index keybindings[] by looking at
337the given string.  Single ascii characters return themselves, while
338the K_* names are matched up.
339===================
340*/
341int Key_StringToKeynum (char *str)
342{
343	keyname_t	*kn;
344
345	if (!str || !str[0])
346		return -1;
347	if (!str[1])
348		return str[0];
349
350	for (kn=keynames ; kn->name ; kn++)
351	{
352		if (!Q_strcasecmp(str,kn->name))
353			return kn->keynum;
354	}
355	return -1;
356}
357
358/*
359===================
360Key_KeynumToString
361
362Returns a string (either a single ascii char, or a K_* name) for the
363given keynum.
364FIXME: handle quote special (general escape sequence?)
365===================
366*/
367const char *Key_KeynumToString (int keynum)
368{
369	keyname_t	*kn;
370	static	char	tinystr[2];
371
372	if (keynum == -1)
373		return "<KEY NOT FOUND>";
374	if (keynum > 32 && keynum < 127)
375	{	// printable ascii
376		tinystr[0] = keynum;
377		tinystr[1] = 0;
378		return tinystr;
379	}
380
381	for (kn=keynames ; kn->name ; kn++)
382		if (keynum == kn->keynum)
383			return kn->name;
384
385	return "<UNKNOWN KEYNUM>";
386}
387
388
389/*
390===================
391Key_SetBinding
392===================
393*/
394void Key_SetBinding (int keynum, const char *binding)
395{
396	char	*newKey;
397	int		l;
398
399	if (keynum == -1)
400		return;
401
402// free old bindings
403	if (keybindings[keynum])
404	{
405		Z_Free (keybindings[keynum]);
406		keybindings[keynum] = NULL;
407	}
408
409// allocate memory for new binding
410	l = Q_strlen (binding);
411	newKey = (char*) Z_Malloc (l+1);
412	Q_strcpy (newKey, binding);
413	newKey[l] = 0;
414	keybindings[keynum] = newKey;
415}
416
417/*
418===================
419Key_Unbind_f
420===================
421*/
422void Key_Unbind_f (void)
423{
424	int		b;
425
426	if (Cmd_Argc() != 2)
427	{
428		Con_Printf ("unbind <key> : remove commands from a key\n");
429		return;
430	}
431
432	b = Key_StringToKeynum (Cmd_Argv(1));
433	if (b==-1)
434	{
435		Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
436		return;
437	}
438
439	Key_SetBinding (b, "");
440}
441
442void Key_Unbindall_f (void)
443{
444	int		i;
445
446	for (i=0 ; i<256 ; i++)
447		if (keybindings[i])
448			Key_SetBinding (i, "");
449}
450
451
452/*
453===================
454Key_Bind_f
455===================
456*/
457void Key_Bind_f (void)
458{
459	int			i, c, b;
460	char		cmd[1024];
461
462	c = Cmd_Argc();
463
464	if (c != 2 && c != 3)
465	{
466		Con_Printf ("bind <key> [command] : attach a command to a key\n");
467		return;
468	}
469	b = Key_StringToKeynum (Cmd_Argv(1));
470	if (b==-1)
471	{
472		Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
473		return;
474	}
475
476	if (c == 2)
477	{
478		if (keybindings[b])
479			Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
480		else
481			Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
482		return;
483	}
484
485// copy the rest of the command line
486	cmd[0] = 0;		// start out with a null string
487	for (i=2 ; i< c ; i++)
488	{
489		if (i > 2)
490			strcat (cmd, " ");
491		strcat (cmd, Cmd_Argv(i));
492	}
493
494	Key_SetBinding (b, cmd);
495}
496
497/*
498============
499Key_WriteBindings
500
501Writes lines containing "bind key value"
502============
503*/
504void Key_WriteBindings (FILE *f)
505{
506	int		i;
507
508	for (i=0 ; i<256 ; i++)
509		if (keybindings[i])
510			if (*keybindings[i])
511				fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
512}
513
514
515/*
516===================
517Key_Init
518===================
519*/
520void Key_Init (void)
521{
522	int		i;
523
524	for (i=0 ; i<32 ; i++)
525	{
526		key_lines[i][0] = ']';
527		key_lines[i][1] = 0;
528	}
529	key_linepos = 1;
530
531//
532// init ascii characters in console mode
533//
534	for (i=32 ; i<128 ; i++)
535		consolekeys[i] = true;
536	consolekeys[K_ENTER] = true;
537	consolekeys[K_TAB] = true;
538	consolekeys[K_LEFTARROW] = true;
539	consolekeys[K_RIGHTARROW] = true;
540	consolekeys[K_UPARROW] = true;
541	consolekeys[K_DOWNARROW] = true;
542	consolekeys[K_BACKSPACE] = true;
543	consolekeys[K_PGUP] = true;
544	consolekeys[K_PGDN] = true;
545	consolekeys[K_SHIFT] = true;
546	consolekeys[K_MWHEELUP] = true;
547	consolekeys[K_MWHEELDOWN] = true;
548	consolekeys[(unsigned int) '`'] = false;
549	consolekeys[(unsigned int) '~'] = false;
550
551	for (i=0 ; i<256 ; i++)
552		keyshift[i] = i;
553	for (i='a' ; i<='z' ; i++)
554		keyshift[i] = i - 'a' + 'A';
555	keyshift[(unsigned int) '1'] = '!';
556	keyshift[(unsigned int) '2'] = '@';
557	keyshift[(unsigned int) '3'] = '#';
558	keyshift[(unsigned int) '4'] = '$';
559	keyshift[(unsigned int) '5'] = '%';
560	keyshift[(unsigned int) '6'] = '^';
561	keyshift[(unsigned int) '7'] = '&';
562	keyshift[(unsigned int) '8'] = '*';
563	keyshift[(unsigned int) '9'] = '(';
564	keyshift[(unsigned int) '0'] = ')';
565	keyshift[(unsigned int) '-'] = '_';
566	keyshift[(unsigned int) '='] = '+';
567	keyshift[(unsigned int) ','] = '<';
568	keyshift[(unsigned int) '.'] = '>';
569	keyshift[(unsigned int) '/'] = '?';
570	keyshift[(unsigned int) ';'] = ':';
571	keyshift[(unsigned int) '\''] = '"';
572	keyshift[(unsigned int) '['] = '{';
573	keyshift[(unsigned int) ']'] = '}';
574	keyshift[(unsigned int) '`'] = '~';
575	keyshift[(unsigned int) '\\'] = '|';
576
577	menubound[K_ESCAPE] = true;
578	for (i=0 ; i<12 ; i++)
579		menubound[K_F1+i] = true;
580
581//
582// register our functions
583//
584	Cmd_AddCommand ("bind",Key_Bind_f);
585	Cmd_AddCommand ("unbind",Key_Unbind_f);
586	Cmd_AddCommand ("unbindall",Key_Unbindall_f);
587
588
589}
590
591/*
592===================
593Key_Event
594
595Called by the system between frames for both key up and key down events
596Should NOT be called during an interrupt!
597===================
598*/
599void Key_Event (int key, qboolean down)
600{
601	char	*kb;
602	char	cmd[1024];
603
604	keydown[key] = down;
605
606	if (!down)
607		key_repeats[key] = 0;
608
609	key_lastpress = key;
610	key_count++;
611	if (key_count <= 0)
612	{
613		return;		// just catching keys for Con_NotifyBox
614	}
615
616// update auto-repeat status
617	if (down)
618	{
619		key_repeats[key]++;
620		if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)
621		{
622			return;	// ignore most autorepeats
623		}
624
625		if (key >= 200 && !keybindings[key])
626			Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
627	}
628
629	if (key == K_SHIFT)
630		shift_down = down;
631
632//
633// handle escape specialy, so the user can never unbind it
634//
635	if (key == K_ESCAPE)
636	{
637		if (!down)
638			return;
639		switch (key_dest)
640		{
641		case key_message:
642			Key_Message (key);
643			break;
644		case key_menu:
645			M_Keydown (key);
646			break;
647		case key_game:
648		case key_console:
649			M_ToggleMenu_f ();
650			break;
651		default:
652			Sys_Error ("Bad key_dest");
653		}
654		return;
655	}
656
657//
658// key up events only generate commands if the game key binding is
659// a button command (leading + sign).  These will occur even in console mode,
660// to keep the character from continuing an action started before a console
661// switch.  Button commands include the kenum as a parameter, so multiple
662// downs can be matched with ups
663//
664	if (!down)
665	{
666		kb = keybindings[key];
667		if (kb && kb[0] == '+')
668		{
669			sprintf (cmd, "-%s %i\n", kb+1, key);
670			Cbuf_AddText (cmd);
671		}
672		if (keyshift[key] != key)
673		{
674			kb = keybindings[keyshift[key]];
675			if (kb && kb[0] == '+')
676			{
677				sprintf (cmd, "-%s %i\n", kb+1, key);
678				Cbuf_AddText (cmd);
679			}
680		}
681		return;
682	}
683
684//
685// during demo playback, most keys bring up the main menu
686//
687	if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
688	{
689		M_ToggleMenu_f ();
690		return;
691	}
692
693//
694// if not a consolekey, send to the interpreter no matter what mode is
695//
696	if ( (key_dest == key_menu && menubound[key])
697	|| (key_dest == key_console && !consolekeys[key])
698	|| (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )
699	{
700		kb = keybindings[key];
701		if (kb)
702		{
703			if (kb[0] == '+')
704			{	// button commands add keynum as a parm
705				sprintf (cmd, "%s %i\n", kb, key);
706				Cbuf_AddText (cmd);
707			}
708			else
709			{
710				Cbuf_AddText (kb);
711				Cbuf_AddText ("\n");
712			}
713		}
714		return;
715	}
716
717	if (!down)
718		return;		// other systems only care about key down events
719
720	if (shift_down)
721	{
722		key = keyshift[key];
723	}
724
725	switch (key_dest)
726	{
727	case key_message:
728		Key_Message (key);
729		break;
730	case key_menu:
731		M_Keydown (key);
732		break;
733
734	case key_game:
735	case key_console:
736		Key_Console (key);
737		break;
738	default:
739		Sys_Error ("Bad key_dest");
740	}
741}
742
743
744/*
745===================
746Key_ClearStates
747===================
748*/
749void Key_ClearStates (void)
750{
751	int		i;
752
753	for (i=0 ; i<256 ; i++)
754	{
755		keydown[i] = false;
756		key_repeats[i] = 0;
757	}
758}
759
760