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