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