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