UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_keys.cpp
Go to the documentation of this file.
1 
8 /*
9 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
10 
11 Original file from Quake 2 v3.21: quake2-2.31/client/keys.c
12 Copyright (C) 1997-2001 Id Software, Inc.
13 
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 as published by the Free Software Foundation; either version 2
17 of the License, or (at your option) any later version.
18 
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 
23 See the GNU General Public License for more details.
24 
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 
29 */
30 
31 #include "../client.h"
32 #include "../cl_console.h"
33 #include "../ui/ui_input.h"
34 #include "../ui/ui_nodes.h"
35 #include "../../shared/utf8.h"
36 
38 uint32_t keyLinePos;
39 
40 static int keyInsert = 1;
41 
42 int editLine = 0;
43 int historyLine = 0;
44 
45 int msgMode;
47 size_t msgBufferLen = 0;
48 
66 
67 static bool keyDown[K_KEY_SIZE];
68 
69 typedef struct {
70  const char* name;
71  int keynum;
72 } keyName_t;
73 
74 #define M(x) {#x, K_##x}
75 static const keyName_t keyNames[] = {
76  M(TAB),
77  M(ENTER),
78  M(ESCAPE),
79  M(SPACE),
80  M(BACKSPACE),
81  M(UPARROW),
82  M(DOWNARROW),
83  M(LEFTARROW),
84  M(RIGHTARROW),
85 
86  M(ALT),
87  M(CTRL),
88  M(SHIFT),
89 
90  M(F1),
91  M(F2),
92  M(F3),
93  M(F4),
94  M(F5),
95  M(F6),
96  M(F7),
97  M(F8),
98  M(F9),
99  M(F10),
100  M(F11),
101  M(F12),
102 
103  M(INS),
104  M(DEL),
105  M(PGDN),
106  M(PGUP),
107  M(HOME),
108  M(END),
109 
110  M(MOUSE1),
111  M(MOUSE2),
112  M(MOUSE3),
113  M(MOUSE4),
114  M(MOUSE5),
115 
116  M(AUX1),
117  M(AUX2),
118  M(AUX3),
119  M(AUX4),
120  M(AUX5),
121  M(AUX6),
122  M(AUX7),
123  M(AUX8),
124  M(AUX9),
125  M(AUX10),
126  M(AUX11),
127  M(AUX12),
128  M(AUX13),
129  M(AUX14),
130  M(AUX15),
131  M(AUX16),
132 
133  M(APPS),
134 
135  M(KP_HOME),
136  M(KP_UPARROW),
137  M(KP_PGUP),
138  M(KP_LEFTARROW),
139  M(KP_5),
140  M(KP_RIGHTARROW),
141  M(KP_END),
142  M(KP_DOWNARROW),
143  M(KP_PGDN),
144  M(KP_ENTER),
145  M(KP_INS),
146  M(KP_DEL),
147  M(KP_SLASH),
148  M(KP_MULTIPLY),
149  M(KP_MINUS),
150  M(KP_PLUS),
151 
152  M(MWHEELUP),
153  M(MWHEELDOWN),
154 
155  M(JOY1),
156  M(JOY2),
157  M(JOY3),
158  M(JOY4),
159  M(JOY5),
160  M(JOY6),
161  M(JOY7),
162  M(JOY8),
163  M(JOY9),
164  M(JOY10),
165  M(JOY11),
166  M(JOY12),
167  M(JOY13),
168  M(JOY14),
169  M(JOY15),
170  M(JOY16),
171  M(JOY17),
172  M(JOY18),
173  M(JOY19),
174  M(JOY20),
175  M(JOY21),
176  M(JOY22),
177  M(JOY23),
178  M(JOY24),
179  M(JOY25),
180  M(JOY26),
181  M(JOY27),
182  M(JOY28),
183  M(JOY29),
184  M(JOY30),
185  M(JOY31),
186  M(JOY32),
187 
188  M(PAUSE),
189 
190  {"SEMICOLON", ';'}, /* because a raw semicolon seperates commands */
191 
192  M(SUPER),
193  M(COMPOSE),
194  M(MODE),
195  M(HELP),
196  M(PRINT),
197  M(SYSREQ),
198  M(SCROLLOCK),
199  M(BREAK),
200  M(MENU),
201  M(POWER),
202  M(EURO),
203  M(UNDO),
204 
205  {nullptr, 0}
206 };
207 #undef M
208 
214 bool Key_IsDown (unsigned int key)
215 {
216  if (key >= K_KEY_SIZE)
217  return false;
218  return keyDown[key];
219 }
220 
221 bool Key_IsNumlock (void)
222 {
223  return (SDL_GetModState() & KMOD_NUM) == KMOD_NUM;
224 }
225 /*
226 ==============================================================================
227 LINE TYPING INTO THE CONSOLE
228 ==============================================================================
229 */
230 
236 static void Key_Console (int key, int unicode)
237 {
238  if (keyDown[K_CTRL]) {
239  switch (toupper(key)) {
240  /* ctrl-L clears screen */
241  case 'L':
242  Cbuf_AddText("clear\n");
243  return;
244  /* jump to beginning of line */
245  case 'A':
246  keyLinePos = 1;
247  return;
248  /* end of line */
249  case 'E':
250  keyLinePos = strlen(keyLines[editLine]);
251  return;
252  }
253  }
254 
255  if (key == K_ENTER || key == K_KP_ENTER) { /* backslash text are commands, else chat */
256  if (keyLines[editLine][1] == '\\' || keyLines[editLine][1] == '/')
257  Cbuf_AddText("%s\n", keyLines[editLine] + 2); /* skip the > */
258  /* no command - just enter */
259  else if (!keyLines[editLine][1])
260  return;
261  else
262  Cbuf_AddText("%s\n", keyLines[editLine] + 1); /* valid command */
263 
264  Com_Printf("%s\n", keyLines[editLine] + 1);
265  editLine = (editLine + 1) & (MAXKEYLINES - 1);
268  /* maybe MAXKEYLINES was reached - we don't want to spawn 'random' strings
269  * from history buffer in our console */
270  keyLines[editLine][1] = '\0';
271  keyLinePos = 1;
272 
273  return;
274  }
275 
276  /* command completion */
277  if (key == K_TAB) {
279  return;
280  }
281 
282  if (key == K_BACKSPACE || (key == 'h' && keyDown[K_CTRL])) {
283  if (keyLinePos > 1) {
285  keyLinePos--;
286  }
287  return;
288  }
289  /* delete char on cursor */
290  if (key == K_DEL || key == K_KP_DEL) {
291  if (keyLinePos < strlen(keyLines[editLine]))
292  strcpy(keyLines[editLine] + keyLinePos, keyLines[editLine] + keyLinePos + 1);
293  return;
294  }
295 
296  if (key == K_UPARROW || key == K_KP_UPARROW || (tolower(key) == 'p' && keyDown[K_CTRL])) {
297  do {
298  historyLine = (historyLine - 1) & (MAXKEYLINES - 1);
299  } while (historyLine != editLine && !keyLines[historyLine][1]);
300 
301  if (historyLine == editLine)
302  historyLine = (editLine + 1) & (MAXKEYLINES - 1);
303 
305  keyLinePos = strlen(keyLines[editLine]);
306  return;
307  } else if (key == K_DOWNARROW || key == K_KP_DOWNARROW || (tolower(key) == 'n' && keyDown[K_CTRL])) {
308  if (historyLine == editLine)
309  return;
310  do {
311  historyLine = (historyLine + 1) & (MAXKEYLINES - 1);
312  } while (historyLine != editLine && !keyLines[historyLine][1]);
313 
314  if (historyLine == editLine) {
316  /* fresh edit line */
317  keyLines[editLine][1] = '\0';
318  keyLinePos = 1;
319  } else {
321  keyLinePos = strlen(keyLines[editLine]);
322  }
323  return;
324  }
325 
326  if (key == K_LEFTARROW || key == K_KP_LEFTARROW) { /* move cursor left */
327  if (keyDown[K_CTRL]) { /* by a whole word */
328  while (keyLinePos > 1 && keyLines[editLine][keyLinePos - 1] == ' ')
329  keyLinePos--; /* get off current word */
330  while (keyLinePos > 1 && keyLines[editLine][keyLinePos - 1] != ' ')
331  keyLinePos--; /* and behind previous word */
332  return;
333  }
334 
335  if (keyLinePos > 1) /* or just a char. */
336  keyLinePos--;
337  return;
338  } else if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW) { /* move cursor right */
339  int i;
340  if ((i = strlen(keyLines[editLine])) == keyLinePos)
341  return; /* no character to get */
342  if (keyDown[K_CTRL]) { /* by a whole word */
343  while (keyLinePos < i && keyLines[editLine][keyLinePos + 1] == ' ')
344  keyLinePos++; /* get off current word */
345  while (keyLinePos < i && keyLines[editLine][keyLinePos + 1] != ' ')
346  keyLinePos++; /* and in front of next word */
347  if (keyLinePos < i) /* all the way in front */
348  keyLinePos++;
349  return;
350  }
351  keyLinePos++; /* or just a char. */
352  return;
353  }
354 
355  /* toggle insert mode */
356  if (key == K_INS || key == K_KP_INS) {
357  keyInsert ^= 1;
358  return;
359  }
360 
361  if (key == K_PGUP || key == K_KP_PGUP || key == K_MWHEELUP) {
362  Con_Scroll(-2);
363  return;
364  }
365 
366  if (key == K_PGDN || key == K_KP_PGDN || key == K_MWHEELDOWN) {
367  Con_Scroll(2);
368  return;
369  }
370 
371  if (key == K_HOME || key == K_KP_HOME) {
372  keyLinePos = 1;
373  return;
374  }
375 
376  if (key == K_END || key == K_KP_END) {
377  keyLinePos = strlen(keyLines[editLine]);
378  return;
379  }
380 
381  switch (key) {
382  case K_KP_MULTIPLY:
383  key = '*';
384  break;
385  case K_KP_SLASH:
386  key = '/';
387  break;
388  case K_KP_MINUS:
389  key = '-';
390  break;
391  case K_KP_PLUS:
392  key = '+';
393  break;
394  case K_KP_HOME:
395  key = '7';
396  break;
397  case K_KP_UPARROW:
398  key = '8';
399  break;
400  case K_KP_PGUP:
401  key = '9';
402  break;
403  case K_KP_LEFTARROW:
404  key = '4';
405  break;
406  case K_KP_5:
407  key = '5';
408  break;
409  case K_KP_RIGHTARROW:
410  key = '6';
411  break;
412  case K_KP_END:
413  key = '1';
414  break;
415  case K_KP_DOWNARROW:
416  key = '2';
417  break;
418  case K_KP_PGDN:
419  key = '3';
420  break;
421  case K_KP_INS:
422  key = '0';
423  break;
424  case K_KP_DEL:
425  key = '.';
426  break;
427  default:
428  key = unicode;
429  break;
430  }
431 
433  if (key < 32 || key > 127)
434  return; /* non printable */
435 
436  if (keyLinePos < MAXCMDLINE - 1) {
437  int i;
438  if (keyInsert) { /* can't do strcpy to move string to right */
439  i = strlen(keyLines[editLine]) - 1;
440 
441  if (i == MAXCMDLINE - 2)
442  i--;
443  for (; i >= keyLinePos; i--)
444  keyLines[editLine][i + 1] = keyLines[editLine][i];
445  }
448  keyLinePos++;
449  if (!i) /* only null terminate if at the end */
451  }
452 }
453 
462 int Key_StringToKeynum (const char* str)
463 {
464  if (Q_strnull(str))
465  return -1;
466 
467  /* single char? */
468  if (str[1] == '\0')
469  return str[0];
470 
471  for (const keyName_t* kn = keyNames; kn->name; kn++) {
472  if (!Q_strcasecmp(str, kn->name))
473  return kn->keynum;
474  }
475  return -1;
476 }
477 
485 const char* Key_KeynumToString (int keynum)
486 {
487  if (keynum == -1)
488  return "<KEY NOT FOUND>";
490  if (keynum > 32 && keynum < 127) { /* printable ascii */
491  static char tinystr[2];
492  tinystr[0] = keynum;
493  tinystr[1] = 0;
494  return tinystr;
495  }
496 
497  for (const keyName_t* kn = keyNames; kn->name; kn++)
498  if (keynum == kn->keynum)
499  return kn->name;
500 
501  return "<UNKNOWN KEYNUM>";
502 }
503 
511 const char* Key_GetBinding (const char* binding, keyBindSpace_t space)
512 {
513  char** keySpace = nullptr;
514 
515  switch (space) {
516  case KEYSPACE_UI:
517  keySpace = menuKeyBindings;
518  break;
519  case KEYSPACE_GAME:
520  keySpace = keyBindings;
521  break;
522  case KEYSPACE_BATTLE:
523  keySpace = battleKeyBindings;
524  break;
525  default:
526  Sys_Error("Unknown key space (%i) given", space);
527  }
528 
529  for (int i = K_FIRST_KEY; i < K_LAST_KEY; i++)
530  if (keySpace[i] && *keySpace[i] && Q_streq(keySpace[i], binding)) {
531  return Key_KeynumToString(i);
532  }
533 
534  /* not found */
535  return "";
536 }
537 
547 void Key_SetBinding (int keynum, const char* binding, keyBindSpace_t space)
548 {
549  char** keySpace = nullptr;
550 
551  if (keynum == -1 || keynum >= K_KEY_SIZE)
552  return;
553 
554  Com_DPrintf(DEBUG_CLIENT, "Binding for '%s' for space ", binding);
555  switch (space) {
556  case KEYSPACE_UI:
557  keySpace = &menuKeyBindings[keynum];
558  Com_DPrintf(DEBUG_CLIENT, "menu\n");
559  break;
560  case KEYSPACE_GAME:
561  keySpace = &keyBindings[keynum];
562  Com_DPrintf(DEBUG_CLIENT, "game\n");
563  break;
564  case KEYSPACE_BATTLE:
565  keySpace = &battleKeyBindings[keynum];
566  Com_DPrintf(DEBUG_CLIENT, "battle\n");
567  break;
568  default:
569  Com_DPrintf(DEBUG_CLIENT, "failure\n");
570  return;
571  }
572 
573  /* free old bindings */
574  Mem_Free(*keySpace);
575  *keySpace = nullptr;
576 
577  /* allocate memory for new binding, but don't set empty commands*/
578  if (binding)
579  *keySpace = Mem_PoolStrDup(binding, com_genericPool, 0);
580 }
581 
586 static void Key_Unbind_f (void)
587 {
588  if (Cmd_Argc() != 2) {
589  Com_Printf("Usage: %s <key> : remove commands from a key\n", Cmd_Argv(0));
590  return;
591  }
592 
593  const int b = Key_StringToKeynum(Cmd_Argv(1));
594  if (b == -1) {
595  Com_Printf("\"%s\" isn't a valid key\n", Cmd_Argv(1));
596  return;
597  }
598 
599  if (Q_streq(Cmd_Argv(0), "unbindmenu"))
600  Key_SetBinding(b, "", KEYSPACE_UI);
601  else if (Q_streq(Cmd_Argv(0), "unbindbattle"))
603  else
605 }
606 
611 static void Key_Unbindall_f (void)
612 {
613  for (int i = K_FIRST_KEY; i < K_LAST_KEY; i++)
614  if (keyBindings[i]) {
615  if (Q_streq(Cmd_Argv(0), "unbindallmenu"))
616  Key_SetBinding(i, "", KEYSPACE_UI);
617  else
619  }
620 }
621 
626 static void Key_Bind_f (void)
627 {
628  const int c = Cmd_Argc();
629 
630  if (c < 2) {
631  Com_Printf("Usage: %s <key> [command] : attach a command to a key\n", Cmd_Argv(0));
632  return;
633  }
634  const int b = Key_StringToKeynum(Cmd_Argv(1));
635  if (b == -1) {
636  Com_Printf("\"%s\" isn't a valid key\n", Cmd_Argv(1));
637  return;
638  }
639 
640  if (c == 2) {
641  if (keyBindings[b])
642  Com_Printf("\"%s\" = \"%s\"\n", Cmd_Argv(1), keyBindings[b]);
643  else
644  Com_Printf("\"%s\" is not bound\n", Cmd_Argv(1));
645  return;
646  }
647 
648 
649  if (Q_streq(Cmd_Argv(0), "bindui"))
651  else if (Q_streq(Cmd_Argv(0), "bindmenu"))
653  else if (Q_streq(Cmd_Argv(0), "bindbattle"))
655  else
657 }
658 
664 void Key_WriteBindings (const char* filename)
665 {
666  bool writeError = false;
667  int cnt = 0;
668 
669  ScopedFile f;
670  FS_OpenFile(filename, &f, FILE_WRITE);
671  if (!f) {
672  Com_Printf("Couldn't write %s.\n", filename);
673  return;
674  }
675 
676  FS_Printf(&f, "// generated by ufo, do not modify\n");
677  FS_Printf(&f, "// If you want to know the keyname of a specific key - set in_debug cvar to 1 and press the key\n");
678  FS_Printf(&f, "unbindallmenu\n");
679  FS_Printf(&f, "unbindall\n");
680  FS_Printf(&f, "unbindallbattle\n");
681  /* failfast, stops loop for first occurred error in fprintf */
682  for (int i = 0; i < K_LAST_KEY && !writeError; i++)
683  if (menuKeyBindings[i] && menuKeyBindings[i][0]) {
684  if (FS_Printf(&f, "bindmenu %s \"%s\"\n", Key_KeynumToString(i), menuKeyBindings[i]) < 0)
685  writeError = true;
686  cnt++;
687  }
688  for (int i = 0; i < K_LAST_KEY && !writeError; i++)
689  if (keyBindings[i] && keyBindings[i][0]) {
690  if (FS_Printf(&f, "bind %s \"%s\"\n", Key_KeynumToString(i), keyBindings[i]) < 0)
691  writeError = true;
692  cnt++;
693  }
694  for (int i = 0; i < K_LAST_KEY && !writeError; i++)
695  if (battleKeyBindings[i] && battleKeyBindings[i][0]) {
696  if (FS_Printf(&f, "bindbattle %s \"%s\"\n", Key_KeynumToString(i), battleKeyBindings[i]) < 0)
697  writeError = true;
698  cnt++;
699  }
700 
701  for (int i = 0; i < UI_GetKeyBindingCount(); i++) {
702  const char* path;
704 
705  if (binding->node == nullptr)
706  continue;
707  if (binding->inherited)
708  continue;
709  if (binding->property == nullptr)
710  path = va("%s", UI_GetPath(binding->node));
711  else
712  path = va("%s@%s", UI_GetPath(binding->node), binding->property->string);
713 
714  if (FS_Printf(&f, "bindui %s \"%s\" \"%s\"\n", Key_KeynumToString(binding->key), path, binding->description ? binding->description : "") < 0)
715  writeError = true;
716  }
717 
718  FS_CloseFile(&f);
719  if (!writeError && cnt > 0) {
720  Com_Printf("Wrote %s\n", filename);
721  } else {
722  /* error in writing the keys.cfg - remove the file again */
723  FS_RemoveFile(va("%s/%s", FS_Gamedir(), filename));
724  }
725 }
726 
730 static void Key_WriteBindings_f (void)
731 {
732  char filename[MAX_QPATH];
733 
734  if (Cmd_Argc() != 2) {
735  Com_Printf("Usage: %s <filename>\n", Cmd_Argv(0));
736  return;
737  }
738 
739  Q_strncpyz(filename, Cmd_Argv(1), sizeof(filename));
740  Com_DefaultExtension(filename, sizeof(filename), ".cfg");
741  Key_WriteBindings(filename);
742 }
743 
747 static void Key_Bindlist_f (void)
748 {
749  Com_Printf("key space: game\n");
750  for (int i = K_FIRST_KEY; i < K_LAST_KEY; i++)
751  if (keyBindings[i] && keyBindings[i][0])
752  Com_Printf("- %s \"%s\"\n", Key_KeynumToString(i), keyBindings[i]);
753  Com_Printf("key space: menu\n");
754  for (int i = K_FIRST_KEY; i < K_LAST_KEY; i++)
755  if (menuKeyBindings[i] && menuKeyBindings[i][0])
756  Com_Printf("- %s \"%s\"\n", Key_KeynumToString(i), menuKeyBindings[i]);
757  Com_Printf("key space: battle\n");
758  for (int i = 0; i < K_LAST_KEY; i++)
759  if (battleKeyBindings[i] && battleKeyBindings[i][0])
760  Com_Printf("- %s \"%s\"\n", Key_KeynumToString(i), battleKeyBindings[i]);
761 
762 }
763 
764 static int Key_CompleteKeyName (const char* partial, const char** match)
765 {
766  int n = 0;
767  for (keyName_t const* kn = keyNames; kn->name; ++kn) {
768  if (Cmd_GenericCompleteFunction(kn->name, partial, match)) {
769  Com_Printf("%s\n", kn->name);
770  ++n;
771  }
772  }
773  return n;
774 }
775 
776 void Key_Init (void)
777 {
781 
782  OBJZERO(keyDown);
783 
784  for (int i = 0; i < MAXKEYLINES; i++) {
786  keyLines[i][1] = 0;
787  }
788  keyLinePos = 1;
789 
790  /* register our functions */
791  Cmd_AddCommand("bindui", Key_Bind_f, "Bind a key to a ui node");
792  Cmd_AddCommand("bindmenu", Key_Bind_f, "Bind a key to a console command - only executed when hovering a menu");
793  Cmd_AddCommand("bind", Key_Bind_f, "Bind a key to a console command");
794  Cmd_AddCommand("bindbattle", Key_Bind_f, "Bind a key to a console command - only executed when in battlescape");
795  Cmd_AddCommand("unbindmenu", Key_Unbind_f, "Unbind a key");
796  Cmd_AddCommand("unbind", Key_Unbind_f, "Unbind a key");
797  Cmd_AddCommand("unbindbattle", Key_Unbind_f, "Unbind a key");
804  Cmd_AddCommand("unbindallmenu", Key_Unbindall_f, "Delete all key bindings for the menu");
805  Cmd_AddCommand("unbindall", Key_Unbindall_f, "Delete all key bindings");
806  Cmd_AddCommand("unbindallbattle", Key_Unbindall_f, "Delete all key bindings for battlescape");
807  Cmd_AddCommand("bindlist", Key_Bindlist_f, "Show all bindings on the game console");
808  Cmd_AddCommand("savebind", Key_WriteBindings_f, "Saves key bindings to keys.cfg");
809 }
810 
815 void Key_SetDest (keydest_t keyDest)
816 {
817  cls.keyDest = keyDest;
818  if (cls.keyDest == key_console) {
819  /* make sure the menu no more capture inputs */
820  UI_ReleaseInput();
821 #if SDL_VERSION_ATLEAST(2,0,0)
822  SDL_StartTextInput();
823 #endif
824  } else {
825 #if SDL_VERSION_ATLEAST(2,0,0)
826  SDL_StopTextInput();
827 #endif
828  }
829 }
830 
835 static bool Key_IsMouseButton (unsigned int key)
836 {
837  return key >= K_MOUSE1 && key <= K_MOUSE5;
838 }
839 
845 void Key_Event (unsigned int key, unsigned short unicode, bool down, unsigned time)
846 {
847  /* unbindable key */
848  if (key >= K_KEY_SIZE)
849  return;
850 
851  if (cls.keyDest == key_game && !Key_IsMouseButton(key)) {
852  if (down && UI_KeyPressed(key, unicode))
853  return;
854  else if (!down && UI_KeyRelease(key, unicode))
855  return;
856  }
857 
858  /* menu key is hardcoded, so the user can never unbind it */
859  if (key == K_ESCAPE) {
860  if (!down)
861  return;
862 
863  switch (cls.keyDest) {
864  case key_console:
866  break;
867  default:
868  Com_Error(ERR_FATAL, "Bad cls.key_dest");
869  }
870  return;
871  }
872 
873  /* track if any key is down for BUTTON_ANY */
874  keyDown[key] = down;
875  if (!down) {
876  /* key up events only generate commands if the game key binding is
877  * a button command (leading + sign). These will occur even in console mode,
878  * to keep the character from continuing an action started before a console
879  * switch. Button commands include the kenum as a parameter, so multiple
880  * downs can be matched with ups */
881  const char* kb = menuKeyBindings[key];
882  /* this loop ensures, that every down event reaches it's proper kbutton_t */
883  for (int i = 0; i < 3; i++) {
884  if (kb && kb[0] == '+') {
885  /* '-' means we have released the key
886  * the key number is used to determine whether the kbutton_t is really
887  * released or whether any other bound key will still ensure that the
888  * kbutton_t is pressed
889  * the time is the msec value when the key was released */
890  Cbuf_AddText("-%s %i %i\n", kb + 1, key, time);
891  }
892  if (i == 0)
893  kb = keyBindings[key];
894  else
895  kb = battleKeyBindings[key];
896  }
897  return;
898  }
899 
900  /* if not a consolekey, send to the interpreter no matter what mode is */
901  if (cls.keyDest == key_game || (key >= K_MOUSE1 && key <= K_MWHEELUP)) {
902  /* Some keyboards need modifiers to access key values that are
903  * present as bare keys on other keyboards. Smooth over the difference
904  * here by using the translated value if there is a binding for it. */
905  const char* kb = nullptr;
906  if (IN_GetMouseSpace() == MS_UI && unicode >= 32 && unicode < 127)
907  kb = menuKeyBindings[unicode];
908  if (!kb && IN_GetMouseSpace() == MS_UI)
909  kb = menuKeyBindings[key];
910  if (!kb && unicode >= 32 && unicode < 127)
911  kb = keyBindings[unicode];
912  if (!kb)
913  kb = keyBindings[key];
914  if (!kb && CL_OnBattlescape())
915  kb = battleKeyBindings[key];
916  if (kb) {
917  if (kb[0] == '+') { /* button commands add keynum and time as a parm */
918  /* '+' means we have pressed the key
919  * the key number is used because the kbutton_t can be 'pressed' by several keys
920  * the time is the msec value when the key was pressed */
921  Cbuf_AddText("%s %i %i\n", kb, key, time);
922  } else {
923  Cbuf_AddText("%s\n", kb);
924  }
925  if (cls.keyDest == key_game)
926  return;
927  }
928  }
929 
930  if (!down)
931  return; /* other systems only care about key down events */
932 
933  switch (cls.keyDest) {
934  case key_game:
935  case key_console:
936  Key_Console(key, unicode);
937  break;
938  default:
939  Com_Error(ERR_FATAL, "Bad cls.key_dest");
940  }
941 }
bool Q_strnull(const char *string)
Definition: shared.h:138
keydest_t
Definition: cl_keys.h:181
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
Definition: cl_keys.h:79
static void Key_Bindlist_f(void)
List all binded keys with its function.
Definition: cl_keys.cpp:747
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
const char * name
Definition: cl_keys.cpp:70
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
static void Key_Bind_f(void)
Binds a key to a given script command.
Definition: cl_keys.cpp:626
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
bool CL_OnBattlescape(void)
Check whether we are in a tactical mission as server or as client. But this only means that we are ab...
char * menuKeyBindings[K_KEY_SIZE]
Definition: cl_keys.cpp:64
#define F3(x, y, z)
Definition: md5.cpp:67
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
static void Key_Unbindall_f(void)
Unbind all key bindings.
Definition: cl_keys.cpp:611
const char * filename
Definition: ioapi.h:41
void Cbuf_AddText(const char *format,...)
Adds command text at the end of the buffer.
Definition: cmd.cpp:126
keyBindSpace_t
Definition: cl_keys.h:173
const struct value_s * property
Definition: ui_input.h:34
static int keyInsert
Definition: cl_keys.cpp:40
Definition: cl_keys.h:39
const char * description
Definition: ui_input.h:36
void FS_RemoveFile(const char *osPath)
Definition: files.cpp:1690
void Key_Event(unsigned int key, unsigned short unicode, bool down, unsigned time)
Called by the system between frames for both key up and key down events.
Definition: cl_keys.cpp:845
Definition: cl_keys.h:98
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
bool Cmd_GenericCompleteFunction(char const *candidate, char const *partial, char const **match)
Definition: cmd.cpp:648
#define M(x)
Definition: cl_keys.cpp:74
bool Key_IsNumlock(void)
Definition: cl_keys.cpp:221
void Key_Init(void)
Definition: cl_keys.cpp:776
unsigned short unicode
Definition: cl_input.cpp:69
static void Key_WriteBindings_f(void)
Definition: cl_keys.cpp:730
#define ERR_FATAL
Definition: common.h:210
const char * Key_GetBinding(const char *binding, keyBindSpace_t space)
Return the key binding for a given script command.
Definition: cl_keys.cpp:511
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
void Key_SetDest(keydest_t keyDest)
Sets the keyDest in cls.
Definition: cl_keys.cpp:815
client_static_t cls
Definition: cl_main.cpp:83
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc)
Definition: files.cpp:68
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define CONSOLE_PROMPT_CHAR
Definition: cl_console.h:43
unsigned int key
Definition: cl_input.cpp:68
bool UI_KeyPressed(unsigned int key, unsigned short unicode)
Called by the client when the user type a key.
Definition: ui_input.cpp:430
#define DEBUG_CLIENT
Definition: defines.h:59
void UI_SetKeyBinding(const char *path, int key, const char *description)
Set a binding from a key to a node to active.
Definition: ui_input.cpp:362
#define OBJZERO(obj)
Definition: shared.h:178
int msgMode
Definition: cl_keys.cpp:45
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
#define F2(x, y, z)
Definition: md5.cpp:66
void Con_Scroll(int scroll)
Scrolls the console.
Definition: cl_console.cpp:172
memPool_t * com_genericPool
Definition: common.cpp:73
const char * UI_GetPath(const uiNode_t *node)
Return a path from a window to a node.
Definition: ui_nodes.cpp:174
static bool keyDown[K_KEY_SIZE]
Definition: cl_keys.cpp:67
Definition: cl_keys.h:96
int editLine
Definition: cl_keys.cpp:42
int FS_Printf(qFILE *f, const char *msg,...)
Can print chunks for 1024 chars into a file.
Definition: files.cpp:1495
void FS_CloseFile(qFILE *f)
char keyLines[MAXKEYLINES][MAXCMDLINE]
Definition: cl_keys.cpp:37
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
#define Q_strcasecmp(a, b)
Definition: shared.h:131
int keynum
Definition: cl_keys.cpp:71
uiNode_t * node
Definition: ui_input.h:33
const char * string
Definition: scripts.h:169
#define MAXKEYLINES
Definition: cl_keys.h:186
Definition: cl_keys.h:80
static void Key_Unbind_f(void)
Unbind a given key binding.
Definition: cl_keys.cpp:586
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define F4(x, y, z)
Definition: md5.cpp:68
static int Key_CompleteKeyName(const char *partial, const char **match)
Definition: cl_keys.cpp:764
static const keyName_t keyNames[]
Definition: cl_keys.cpp:75
int UI_GetKeyBindingCount(void)
Definition: ui_input.cpp:272
#define MAXCMDLINE
Definition: common.h:307
bool Key_IsDown(unsigned int key)
Checks whether a given key is currently pressed.
Definition: cl_keys.cpp:214
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition: shared.cpp:297
Definition: cl_keys.h:77
bool Com_ConsoleCompleteCommand(const char *s, char *target, size_t bufSize, uint32_t *pos, uint32_t offset)
Console completion for command and variables.
Definition: common.cpp:717
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
Definition: cl_keys.h:78
uint32_t keyLinePos
Definition: cl_keys.cpp:38
void UI_ReleaseInput(void)
Release all captured input (keyboard or mouse)
Definition: ui_input.cpp:496
static bool Key_IsMouseButton(unsigned int key)
Returns true if the Key is a mouse event.
Definition: cl_keys.cpp:835
uiKeyBinding_t * UI_GetKeyBindingByIndex(int index)
Definition: ui_input.cpp:277
#define Mem_Free(ptr)
Definition: mem.h:35
char msgBuffer[MAXCMDLINE]
Definition: cl_keys.cpp:46
#define F1(x, y, z)
Definition: md5.cpp:65
void Cmd_AddParamCompleteFunction(const char *cmdName, int(*function)(const char *partial, const char **match))
Definition: cmd.cpp:679
bool inherited
Definition: ui_input.h:37
Definition: cl_keys.h:44
char * keyBindings[K_KEY_SIZE]
Definition: cl_keys.cpp:63
const uiKeyBinding_t * binding
Definition: cl_keys.h:59
#define Q_streq(a, b)
Definition: shared.h:136
#define Mem_PoolStrDup(in, pool, tagNum)
Definition: mem.h:50
const char * Key_KeynumToString(int keynum)
Convert a given keynum to string.
Definition: cl_keys.cpp:485
void Con_ToggleConsole_f(void)
Definition: cl_console.cpp:138
#define IN_GetMouseSpace()
Definition: cl_input.h:48
void Key_SetBinding(int keynum, const char *binding, keyBindSpace_t space)
Bind a keynum to script command.
Definition: cl_keys.cpp:547
int historyLine
Definition: cl_keys.cpp:43
int Key_StringToKeynum(const char *str)
Convert to given string to keynum.
Definition: cl_keys.cpp:462
char * battleKeyBindings[K_KEY_SIZE]
Definition: cl_keys.cpp:65
int down
Definition: cl_input.cpp:70
size_t msgBufferLen
Definition: cl_keys.cpp:47
bool UI_KeyRelease(unsigned int key, unsigned short unicode)
Called by the client when the user released a key.
Definition: ui_input.cpp:413
Definition: cl_input.h:33
static void Key_Console(int key, int unicode)
Interactive line editing and console scrollback.
Definition: cl_keys.cpp:236
keydest_t keyDest
Definition: client.h:56
void Key_WriteBindings(const char *filename)
Writes lines containing "bind key value".
Definition: cl_keys.cpp:664