OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4KeyboardInput.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // Keyboard input mapping to engine functions
17 
18 #include "C4Include.h"
19 #include "gui/C4KeyboardInput.h"
20 
21 #include "c4group/C4Components.h"
22 #include "game/C4Game.h"
23 #include "platform/C4Window.h"
24 
25 
26 #include <algorithm>
27 #include <regex>
28 #include <string>
29 #include <unordered_map>
30 
31 #ifdef HAVE_SDL
32 #include <SDL.h>
33 #endif
34 
35 #ifdef USE_SDL_MAINLOOP
36 // Required for KeycodeToString translation table.
37 #include "platform/C4App.h"
38 #endif
39 
40 /* ----------------- Key maps ------------------ */
41 
43 {
45  const char *szName;
46 };
47 
49 {
50  { KEYS_Alt, "Alt" },
51  { KEYS_Control, "Ctrl" },
52  { KEYS_Shift, "Shift" },
53  { KEYS_Undefined, nullptr }
54 };
55 
57 {
58  // query map
59  const C4KeyShiftMapEntry *pCheck = KeyShiftMap;
60  while (pCheck->szName)
61  if (SEqualNoCase(sName.getData(), pCheck->szName)) break; else ++pCheck;
62  return pCheck->eShift;
63 }
64 
66 {
67  // query map
68  const C4KeyShiftMapEntry *pCheck = KeyShiftMap;
69  while (pCheck->szName)
70  if (eShift == pCheck->eShift) break; else ++pCheck;
71  return StdStrBuf(pCheck->szName);
72 }
73 
75 {
77  const char *szName;
78  const char *szShortName;
79 };
80 
81 #if defined(USE_COCOA)
83 #else
85  {K_ESCAPE, "Escape", "Esc"},
86  {K_1, "1", nullptr},
87  {K_2, "2", nullptr},
88  {K_3, "3", nullptr},
89  {K_4, "4", nullptr},
90  {K_5, "5", nullptr},
91  {K_6, "6", nullptr},
92  {K_7, "7", nullptr},
93  {K_8, "8", nullptr},
94  {K_9, "9", nullptr},
95  {K_0, "0", nullptr},
96  {K_MINUS, "Minus", "-"},
97  {K_EQUAL, "Equal", "="},
98  {K_BACK, "BackSpace", nullptr},
99  {K_TAB, "Tab", nullptr},
100  {K_Q, "Q", nullptr},
101  {K_W, "W", nullptr},
102  {K_E, "E", nullptr},
103  {K_R, "R", nullptr},
104  {K_T, "T", nullptr},
105  {K_Y, "Y", nullptr},
106  {K_U, "U", nullptr},
107  {K_I, "I", nullptr},
108  {K_O, "O", nullptr},
109  {K_P, "P", nullptr},
110  {K_LEFT_BRACKET, "LeftBracket", "["},
111  {K_RIGHT_BRACKET, "RightBracket", "]"},
112  {K_RETURN, "Return", "Ret"},
113  {K_CONTROL_L, "LeftControl", "LCtrl"},
114  {K_A, "A", nullptr},
115  {K_S, "S", nullptr},
116  {K_D, "D", nullptr},
117  {K_F, "F", nullptr},
118  {K_G, "G", nullptr},
119  {K_H, "H", nullptr},
120  {K_J, "J", nullptr},
121  {K_K, "K", nullptr},
122  {K_L, "L", nullptr},
123  {K_SEMICOLON, "Semicolon", ";"},
124  {K_APOSTROPHE, "Apostrophe", "'"},
125  {K_GRAVE_ACCENT, "GraveAccent", "`"},
126  {K_SHIFT_L, "LeftShift", "LShift"},
127  {K_BACKSLASH, "Backslash", "\\"},
128  {K_Z, "Z", nullptr},
129  {K_X, "X", nullptr},
130  {K_C, "C", nullptr},
131  {K_V, "V", nullptr},
132  {K_B, "B", nullptr},
133  {K_N, "N", nullptr},
134  {K_M, "M", nullptr},
135  {K_COMMA, "Comma", ","},
136  {K_PERIOD, "Period", "."},
137  {K_SLASH, "Slash", "/"},
138  {K_SHIFT_R, "RightShift", "RShift"},
139  {K_MULTIPLY, "Multiply", "N*"},
140  {K_ALT_L, "LeftAlt", "LAlt"},
141  {K_SPACE, "Space", "Sp"},
142  {K_CAPS, "Capslock", nullptr},
143  {K_F1, "F1", nullptr},
144  {K_F2, "F2", nullptr},
145  {K_F3, "F3", nullptr},
146  {K_F4, "F4", nullptr},
147  {K_F5, "F5", nullptr},
148  {K_F6, "F6", nullptr},
149  {K_F7, "F7", nullptr},
150  {K_F8, "F8", nullptr},
151  {K_F9, "F9", nullptr},
152  {K_F10, "F10", nullptr},
153  {K_NUM, "NumLock", "NLock"},
154  {K_SCROLL, "ScrollLock", "SLock"},
155  {K_NUM7, "Num7", "N7"},
156  {K_NUM8, "Num8", "N8"},
157  {K_NUM9, "Num9", "N9"},
158  {K_SUBTRACT, "Subtract", "N-"},
159  {K_NUM4, "Num4", "N4"},
160  {K_NUM5, "Num5", "N5"},
161  {K_NUM6, "Num6", "N6"},
162  {K_ADD, "Add", "N+"},
163  {K_NUM1, "Num1", "N1"},
164  {K_NUM2, "Num2", "N2"},
165  {K_NUM3, "Num3", "N3"},
166  {K_NUM0, "Num0", "N0"},
167  {K_DECIMAL, "Decimal", "N,"},
168  {K_86, "|<>", nullptr},
169  {K_F11, "F11", nullptr},
170  {K_F12, "F12", nullptr},
171  {K_NUM_RETURN, "NumReturn", "NRet"},
172  {K_CONTROL_R, "RightControl", "RCtrl"},
173  {K_DIVIDE, "Divide", "N/"},
174  {K_ALT_R, "RightAlt", "RAlt"},
175  {K_HOME, "Home", nullptr},
176  {K_UP, "Up", nullptr},
177  {K_PAGEUP, "PageUp", nullptr},
178  {K_LEFT, "Left", nullptr},
179  {K_RIGHT, "Right", nullptr},
180  {K_END, "End", nullptr},
181  {K_DOWN, "Down", nullptr},
182  {K_PAGEDOWN, "PageDown", nullptr},
183  {K_INSERT, "Insert", "Ins"},
184  {K_DELETE, "Delete", "Del"},
185  {K_PAUSE, "Pause", nullptr},
186  {K_WIN_L, "LeftWin", "LWin"},
187  {K_WIN_R, "RightWin", "RWin"},
188  {K_MENU, "Menu", nullptr},
189  {K_PRINT, "Print", nullptr},
190  {0x00, nullptr, nullptr}
191 };
192 #endif
193 
194 C4KeyCodeEx::C4KeyCodeEx(C4KeyCode key, C4KeyShiftState Shift, bool fIsRepeated, int32_t deviceId)
195 : Key(key), dwShift(Shift), fRepeated(fIsRepeated), deviceId(deviceId)
196 {
197 }
198 
200 {
201  // reduce stuff like Ctrl+RightCtrl to simply RightCtrl
202  if ((dwShift & KEYS_Control) && (Key == K_CONTROL_L || Key == K_CONTROL_R)) dwShift &= ~KEYS_Control;
203  if ((dwShift & KEYS_Shift) && (Key == K_SHIFT_L || Key == K_SHIFT_R)) dwShift &= ~KEYS_Shift;
204 }
205 
206 C4KeyCode C4KeyCodeEx::GetKeyByScanCode(const char *scan_code)
207 {
208  // scan code is in hex format
209  unsigned int scan_code_int;
210  if (sscanf(scan_code, "$%x", &scan_code_int) != 1) return KEY_Undefined;
211  return scan_code_int;
212 }
213 
214 static const std::unordered_map<std::string, C4KeyCode> controllercodes =
215 {
216  { "ButtonA", KEY_CONTROLLER_ButtonA },
217  { "ButtonB", KEY_CONTROLLER_ButtonB },
218  { "ButtonX", KEY_CONTROLLER_ButtonX },
219  { "ButtonY", KEY_CONTROLLER_ButtonY },
220  { "ButtonBack", KEY_CONTROLLER_ButtonBack },
221  { "ButtonGuide", KEY_CONTROLLER_ButtonGuide },
222  { "ButtonStart", KEY_CONTROLLER_ButtonStart },
223  { "ButtonLeftStick", KEY_CONTROLLER_ButtonLeftStick },
224  { "ButtonRightStick", KEY_CONTROLLER_ButtonRightStick },
225  { "ButtonLeftShoulder", KEY_CONTROLLER_ButtonLeftShoulder },
226  { "ButtonRightShoulder", KEY_CONTROLLER_ButtonRightShoulder },
227  { "ButtonDpadUp", KEY_CONTROLLER_ButtonDpadUp },
228  { "ButtonDpadDown", KEY_CONTROLLER_ButtonDpadDown },
229  { "ButtonDpadLeft", KEY_CONTROLLER_ButtonDpadLeft },
230  { "ButtonDpadRight", KEY_CONTROLLER_ButtonDpadRight },
231  { "AnyButton", KEY_CONTROLLER_AnyButton },
232  { "LeftStickLeft", KEY_CONTROLLER_AxisLeftXLeft },
233  { "LeftStickRight", KEY_CONTROLLER_AxisLeftXRight },
234  { "LeftStickUp", KEY_CONTROLLER_AxisLeftYUp },
235  { "LeftStickDown", KEY_CONTROLLER_AxisLeftYDown },
236  { "RightStickLeft", KEY_CONTROLLER_AxisRightXLeft },
237  { "RightStickRight", KEY_CONTROLLER_AxisRightXRight },
238  { "RightStickUp", KEY_CONTROLLER_AxisRightYUp },
239  { "RightStickDown", KEY_CONTROLLER_AxisRightYDown },
240  { "LeftTrigger", KEY_CONTROLLER_AxisTriggerLeft },
241  { "RightTrigger", KEY_CONTROLLER_AxisTriggerRight },
242 };
243 
245 {
246  // direct key code?
247  if (sName.getLength() > 2)
248  {
249  unsigned int dwRVal;
250  if (sscanf(sName.getData(), "\\x%x", &dwRVal) == 1) return dwRVal;
251  // scan code
252  if (*sName.getData() == '$') return GetKeyByScanCode(sName.getData());
253  // direct gamepad code
254  std::regex controller_re(R"/(^Controller(\w+)$)/");
255  std::cmatch matches;
256  if (std::regex_match(sName.getData(), matches, controller_re))
257  {
258  auto keycode_it = controllercodes.find(matches[1].str());
259  if (keycode_it != controllercodes.end())
260  return KEY_Gamepad(keycode_it->second);
261  else
262  return KEY_Undefined;
263 
264  }
265  bool is_mouse_key;
266 #ifdef _WIN32
267  is_mouse_key = !strnicmp(sName.getData(), "Mouse", 5);
268 #else
269  is_mouse_key = !strncasecmp(sName.getData(), "Mouse", 5);
270 #endif
271  if (is_mouse_key)
272  {
273  // skip Mouse/GameMouse
274  const char *key_str = sName.getData()+5;
275  int mouse_id;
276  if (sscanf(key_str, "%d", &mouse_id) == 1)
277  {
278  // skip number
279  while (isdigit(*key_str)) ++key_str;
280  // check for known mouse events (e.g. Mouse1Move or GameMouse1Wheel)
281  if (!stricmp(key_str, "Move")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Move);
282  if (!stricmp(key_str, "Wheel1Up")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Wheel1Up);
283  if (!stricmp(key_str, "Wheel1Down")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Wheel1Down);
284  if (SEqualNoCase(key_str, "Button", 6)) // e.g. Mouse1ButtonLeft or GameMouse1ButtonRightDouble
285  {
286  // check for known mouse button events
287  uint8_t mouseevent_id = 0;
288  key_str += 6;
289  if (SEqualNoCase(key_str, "Left",4)) { mouseevent_id=KEY_MOUSE_ButtonLeft; key_str += 4; }
290  else if (SEqualNoCase(key_str, "Right",5)) { mouseevent_id=KEY_MOUSE_ButtonRight; key_str += 5; }
291  else if (SEqualNoCase(key_str, "Middle",6)) { mouseevent_id=KEY_MOUSE_ButtonMiddle; key_str += 6; }
292  else if (SEqualNoCase(key_str, "X1",2)) { mouseevent_id=KEY_MOUSE_ButtonX1; key_str += 2; }
293  else if (SEqualNoCase(key_str, "X2",2)) { mouseevent_id=KEY_MOUSE_ButtonX2; key_str += 2; }
294  else if (isdigit(*key_str))
295  {
296  // indexed mouse button (e.g. Mouse1Button4 or Mouse1Button4Double)
297  int button_index;
298  if (sscanf(key_str, "%d", &button_index) == 1)
299  {
300  mouseevent_id=static_cast<uint8_t>(KEY_MOUSE_Button1+button_index-1);
301  while (isdigit(*key_str)) ++key_str;
302  }
303  }
304  if (mouseevent_id)
305  {
306  // valid event if finished or followed by "Double"
307  if (!*key_str) return KEY_Mouse(mouse_id-1, mouseevent_id);
308  if (!stricmp(key_str, "Double")) return KEY_Mouse(mouse_id-1, mouseevent_id+(KEY_MOUSE_Button1Double-KEY_MOUSE_Button1));
309  // invalid mouse key...
310  }
311  }
312  }
313  }
314 
315  }
316  // query map
317  const C4KeyCodeMapEntry *pCheck = KeyCodeMap;
318  while (pCheck->szName) {
319  if (SEqualNoCase(sName.getData(), pCheck->szName)) {
320  return(pCheck->wCode);
321  }
322  ++pCheck;
323  }
324 #if defined(USE_SDL_MAINLOOP)
325  SDL_Scancode s = SDL_GetScancodeFromName(sName.getData());
326  if (s != SDL_SCANCODE_UNKNOWN) return s;
327 #endif
328  return KEY_Undefined;
329 }
330 
331 StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool fShort)
332 {
333  // Gamepad keys
334  if (Key_IsGamepad(wCode))
335  {
336  if (fHumanReadable)
337  {
338  switch (Key_GetGamepadEvent(wCode))
339  {
340  case KEY_CONTROLLER_ButtonA : return StdStrBuf("{{@Ico:A}}");
341  case KEY_CONTROLLER_ButtonB : return StdStrBuf("{{@Ico:B}}");
342  case KEY_CONTROLLER_ButtonX : return StdStrBuf("{{@Ico:X}}");
343  case KEY_CONTROLLER_ButtonY : return StdStrBuf("{{@Ico:Y}}");
344  case KEY_CONTROLLER_ButtonBack : return StdStrBuf("{{@Ico:Back}}");
345  case KEY_CONTROLLER_ButtonGuide : return StdStrBuf("Guide");
346  case KEY_CONTROLLER_ButtonStart : return StdStrBuf("{{@Ico:Start}}");
347  case KEY_CONTROLLER_ButtonLeftStick : return StdStrBuf("{{@Ico:LeftStick}}");
348  case KEY_CONTROLLER_ButtonRightStick : return StdStrBuf("{{@Ico:RightStick}}");
349  case KEY_CONTROLLER_ButtonLeftShoulder : return StdStrBuf("{{@Ico:LeftShoulder}}");
350  case KEY_CONTROLLER_ButtonRightShoulder : return StdStrBuf("{{@Ico:RightShoulder}}");
351  case KEY_CONTROLLER_ButtonDpadUp : return StdStrBuf("{{@Ico:DpadUp}}");
352  case KEY_CONTROLLER_ButtonDpadDown : return StdStrBuf("{{@Ico:DpadDown}}");
353  case KEY_CONTROLLER_ButtonDpadLeft : return StdStrBuf("{{@Ico:DpadLeft}}");
354  case KEY_CONTROLLER_ButtonDpadRight : return StdStrBuf("{{@Ico:DpadRight}}");
355  case KEY_CONTROLLER_AnyButton : return StdStrBuf("Any Button");
356  case KEY_CONTROLLER_AxisLeftXLeft : return StdStrBuf("{{@Ico:LeftStick}} Left");
357  case KEY_CONTROLLER_AxisLeftXRight : return StdStrBuf("{{@Ico:LeftStick}} Right");
358  case KEY_CONTROLLER_AxisLeftYUp : return StdStrBuf("{{@Ico:LeftStick}} Up");
359  case KEY_CONTROLLER_AxisLeftYDown : return StdStrBuf("{{@Ico:LeftStick}} Down");
360  case KEY_CONTROLLER_AxisRightXLeft : return StdStrBuf("{{@Ico:RightStick}} Left");
361  case KEY_CONTROLLER_AxisRightXRight : return StdStrBuf("{{@Ico:RightStick}} Right");
362  case KEY_CONTROLLER_AxisRightYUp : return StdStrBuf("{{@Ico:RightStick}} Up");
363  case KEY_CONTROLLER_AxisRightYDown : return StdStrBuf("{{@Ico:RightStick}} Down");
364  case KEY_CONTROLLER_AxisTriggerLeft : return StdStrBuf("{{@Ico:LeftTrigger}}");
365  case KEY_CONTROLLER_AxisTriggerRight : return StdStrBuf("{{@Ico:RightTrigger}}");
366  }
367  }
368  else
369  {
370  // A linear search in our small map is probably fast enough.
371  auto it = std::find_if(controllercodes.begin(), controllercodes.end(), [wCode](const auto &p)
372  {
373  return p.second == Key_GetGamepadEvent(wCode);
374  });
375  if (it != controllercodes.end())
376  return FormatString("Controller%s", it->first.c_str());
377  }
378  return StdStrBuf("Unknown");
379  }
380 
381  // Mouse keys
382  if (Key_IsMouse(wCode))
383  {
384  int mouse_id = Key_GetMouse(wCode);
385  int mouse_event = Key_GetMouseEvent(wCode);
386  const char *mouse_str = "Mouse";
387  switch (mouse_event)
388  {
389  case KEY_MOUSE_Move: return FormatString("%s%dMove", mouse_str, mouse_id);
390  case KEY_MOUSE_Wheel1Up: return FormatString("%s%dWheel1Up", mouse_str, mouse_id);
391  case KEY_MOUSE_Wheel1Down: return FormatString("%s%dWheel1Down", mouse_str, mouse_id);
392  case KEY_MOUSE_ButtonLeft: return FormatString("%s%dLeft", mouse_str, mouse_id);
393  case KEY_MOUSE_ButtonRight: return FormatString("%s%dRight", mouse_str, mouse_id);
394  case KEY_MOUSE_ButtonMiddle: return FormatString("%s%dMiddle", mouse_str, mouse_id);
395  case KEY_MOUSE_ButtonX1: return FormatString("%s%dX1", mouse_str, mouse_id);
396  case KEY_MOUSE_ButtonX2: return FormatString("%s%dX2", mouse_str, mouse_id);
397  case KEY_MOUSE_ButtonLeftDouble: return FormatString("%s%dLeftDouble", mouse_str, mouse_id);
398  case KEY_MOUSE_ButtonRightDouble: return FormatString("%s%dRightDouble", mouse_str, mouse_id);
399  case KEY_MOUSE_ButtonMiddleDouble:return FormatString("%s%dMiddleDouble", mouse_str, mouse_id);
400  case KEY_MOUSE_ButtonX1Double: return FormatString("%s%dX1Double", mouse_str, mouse_id);
401  case KEY_MOUSE_ButtonX2Double: return FormatString("%s%dX2Double", mouse_str, mouse_id);
402  default:
403  // extended mouse button
404  {
405  uint8_t btn = Key_GetMouseEvent(wCode);
406  if (btn >= KEY_MOUSE_Button1Double)
407  return FormatString("%s%dButton%dDouble", mouse_str, mouse_id, int(btn-KEY_MOUSE_Button1Double));
408  else
409  return FormatString("%s%dButton%d", mouse_str, mouse_id, int(btn-KEY_MOUSE_Button1));
410  }
411  }
412  }
413 
414  // it's a keyboard key
415  if (!fHumanReadable) {
416  // for config files and such: dump scancode
417  return FormatString("$%x", static_cast<unsigned int>(wCode));
418  }
419 #if defined(USE_WIN32_WINDOWS)
420 
421  // Query map
422  const C4KeyCodeMapEntry *pCheck = KeyCodeMap;
423  while (pCheck->szName)
424  if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName); else ++pCheck;
425 
426 // TODO: Works?
427 // StdStrBuf Name; Name.SetLength(1000);
428 // int res = GetKeyNameText(wCode, Name.getMData(), Name.getSize());
429 // if(!res)
430 // // not found: Compose as direct code
431 // return FormatString("\\x%x", (DWORD) wCode);
432 // // Set size
433 // Name.SetLength(res);
434 // return Name;
435 
436  wchar_t buf[100];
437  int len = GetKeyNameText(wCode<<16, buf, 100);
438  if (len > 0) {
439  // buf is nullterminated name
440  return StdStrBuf(buf);
441  }
442 #elif defined (USE_COCOA)
443  // query map
444  const C4KeyCodeMapEntry *pCheck = KeyCodeMap;
445  while (pCheck->szName)
446  if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName); else ++pCheck;
447  // not found: Compose as direct code
448  return FormatString("\\x%x", static_cast<unsigned int>(wCode));
449 #elif defined(USE_SDL_MAINLOOP)
450  StdStrBuf buf;
451  auto name = KeycodeToString(wCode);
452  if (name) buf.Copy(name);
453  if (!buf.getLength()) buf.Format("\\x%lx", wCode);
454  return buf;
455 #endif
456  return FormatString("$%x", static_cast<unsigned int>(wCode));
457 }
458 
459 StdStrBuf C4KeyCodeEx::ToString(bool fHumanReadable, bool fShort) const
460 {
461  static StdStrBuf sResult;
462  sResult.Clear();
463  // Add shift
464  for (DWORD dwShiftCheck = KEYS_First; dwShiftCheck <= KEYS_Max; dwShiftCheck <<= 1)
465  if (dwShiftCheck & dwShift)
466  {
467  sResult.Append(KeyShift2String((C4KeyShiftState) dwShiftCheck));
468  sResult.AppendChar('+');
469  }
470  // Add key
471  if (sResult.getLength())
472  {
473  sResult.Append(KeyCode2String(Key, fHumanReadable, fShort));
474  return sResult;
475  }
476  else
477  {
478  return KeyCode2String(Key, fHumanReadable, fShort);
479  }
480 }
481 
482 
483 
484 /* ----------------- C4KeyCodeEx ------------------ */
485 
487 {
488  if (pComp->isDeserializer())
489  {
490  // reading from file
491  StdStrBuf sCode;
492  bool is_scan_code;
493  // read shifts
494  DWORD dwSetShift = 0;
495  for (;;)
496  {
497  is_scan_code = pComp->Separator(StdCompiler::SEP_DOLLAR);
498  if (!is_scan_code) pComp->NoSeparator();
499  pComp->Value(mkParAdapt(sCode, StdCompiler::RCT_Idtf));
500  if (is_scan_code) // scan codes start with $. Reassamble the two tokens that were split by StdCompiler
501  {
502  sCode.Take(FormatString("$%s", sCode.getData()));
503  break;
504  }
505  if (!pComp->Separator(StdCompiler::SEP_PLUS)) break; // no more separator: Parse this as keyboard code
506  // try to convert to shift state
507  C4KeyShiftState eAddState = String2KeyShift(sCode);
508  if (eAddState == KEYS_Undefined)
509  pComp->excCorrupt("undefined key shift state: %s", sCode.getData());
510  dwSetShift |= eAddState;
511  }
512  // any code given? Otherwise, keep default
513  if (sCode.getLength())
514  {
515  // last section: convert to key code
516  C4KeyCode eCode = String2KeyCode(sCode);
517  if (eCode == KEY_Undefined)
518  {
519  if (pOutBuf)
520  {
521  // unknown key, but an output buffer for unknown keys was provided. No failure; caller might resolve key.
522  eCode = KEY_Default;
523  }
524  else
525  {
526  pComp->excCorrupt("undefined key code: %s", sCode.getData());
527  }
528  }
529  dwShift = dwSetShift;
530  Key = eCode;
531  if (pOutBuf) pOutBuf->Take(std::move(sCode));
532  }
533  }
534  else
535  {
536  // write shift states
537  for (DWORD dwShiftCheck = KEYS_First; dwShiftCheck <= KEYS_Max; dwShiftCheck <<= 1)
538  if (dwShiftCheck & dwShift)
539  {
540  pComp->Value(mkDecompileAdapt(KeyShift2String((C4KeyShiftState) dwShiftCheck)));
542  }
543  // write key
544  pComp->Value(mkDecompileAdapt(KeyCode2String(Key, false, false)));
545  }
546 }
547 
549 {
550  pComp->Value(iStrength);
551  pComp->Separator();
552  pComp->Value(game_x);
553  pComp->Separator();
554  pComp->Value(game_y);
555  pComp->Separator();
556  pComp->Value(vp_x);
557  pComp->Separator();
558  pComp->Value(vp_y);
559 }
560 
561 bool C4KeyEventData::operator ==(const struct C4KeyEventData &cmp) const
562 {
563  return iStrength == cmp.iStrength
564  && game_x == cmp.game_x && game_y == cmp.game_y
565  && vp_x == cmp.vp_x && vp_y == cmp.vp_y;
566 
567 }
568 
569 /* ----------------- C4CustomKey------------------ */
570 
571 C4CustomKey::C4CustomKey(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
572  : Scope(Scope), Name(), uiPriority(uiPriority), iRef(0), is_down(false)
573 {
574  // generate code
575  if (DefCode.Key != KEY_Default) DefaultCodes.push_back(DefCode);
576  // ctor for default key
577  Name.Copy(szName);
578  if (pCallback)
579  {
580  pCallback->Ref();
581  vecCallbacks.push_back(pCallback);
582  pCallback->pOriginalKey = this;
583  }
584 }
585 
586 C4CustomKey::C4CustomKey(const CodeList &rDefCodes, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
587  : DefaultCodes(rDefCodes), Scope(Scope), Name(), uiPriority(uiPriority), iRef(0), is_down(false)
588 {
589  // ctor for default key
590  Name.Copy(szName);
591  if (pCallback)
592  {
593  pCallback->Ref();
594  vecCallbacks.push_back(pCallback);
595  pCallback->pOriginalKey = this;
596  }
597 }
598 
599 C4CustomKey::C4CustomKey(const C4CustomKey &rCpy, bool fCopyCallbacks)
600  : Codes(rCpy.Codes), DefaultCodes(rCpy.DefaultCodes), Scope(rCpy.Scope), Name(), uiPriority(rCpy.uiPriority), iRef(0), is_down(false)
601 {
602  Name.Copy(rCpy.GetName());
603  if (fCopyCallbacks)
604  {
605  for (CBVec::const_iterator i = rCpy.vecCallbacks.begin(); i != rCpy.vecCallbacks.end(); ++i)
606  {
607  (*i)->Ref();
608  vecCallbacks.push_back(*i);
609  }
610  }
611 }
612 
614 {
615  // free callback handles
616  for (CBVec::const_iterator i = vecCallbacks.begin(); i != vecCallbacks.end(); ++i)
617  (*i)->Deref();
618 }
619 
621 {
622  const CodeList &codes = GetCodes();
623  for (const auto &code : codes)
624  if (code == key)
625  return true;
626  return false;
627 }
628 
629 void C4CustomKey::Update(const C4CustomKey *pByKey)
630 {
631  assert(pByKey);
632  assert(Name == pByKey->Name);
633  // transfer any assigned data, except name which should be equal anyway
634  if (pByKey->DefaultCodes.size()) DefaultCodes = pByKey->DefaultCodes;
635  if (pByKey->Codes.size()) Codes = pByKey->Codes;
636  if (pByKey->Scope != KEYSCOPE_None) Scope = pByKey->Scope;
637  if (pByKey->uiPriority != PRIO_None) uiPriority = pByKey->uiPriority;
638  for (CBVec::const_iterator i = pByKey->vecCallbacks.begin(); i != pByKey->vecCallbacks.end(); ++i)
639  {
640  (*i)->Ref();
641  vecCallbacks.push_back(*i);
642  }
643 }
644 
646 {
647  return pIntfc->IsOriginalKey(pCheckKey);
648 }
649 
651 {
652  // remove all instances from list
653  CBVec::iterator i;
654  while ((i = std::find_if(vecCallbacks.begin(), vecCallbacks.end(), std::bind2nd(std::ptr_fun(&C4KeyboardCallbackInterfaceHasOriginalKey), pOfKey))) != vecCallbacks.end())
655  {
656  C4KeyboardCallbackInterface *pItfc = *i;
657  vecCallbacks.erase(i);
658  pItfc->Deref();
659  }
660 }
661 
663 {
664  pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(Codes), Name.getData(), DefaultCodes));
665 }
666 
668 {
669  // remember down-state
670  is_down = (eEv == KEYEV_Down);
671  // execute all callbacks
672  for (CBVec::iterator i = vecCallbacks.begin(); i != vecCallbacks.end(); ++i)
673  if ((*i)->OnKeyEvent(key, eEv))
674  return true;
675  // no event processed it
676  return false;
677 }
678 
679 
680 
681 /* ----------------- C4KeyBinding ------------------ */
682 
683 C4KeyBinding::C4KeyBinding(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
684  : C4CustomKey(DefCode, szName, Scope, pCallback, uiPriority)
685 {
686  // self holds a ref
687  Ref();
688  // register into keyboard input class
690 }
691 
692 C4KeyBinding::C4KeyBinding(const CodeList &rDefCodes, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
693  : C4CustomKey(rDefCodes, szName, Scope, pCallback, uiPriority)
694 {
695  // self holds a ref
696  Ref();
697  // register into keyboard input class
699 }
700 
702 {
703  // deregister from keyboard input class, if that class still exists
706  // shouldn't be refed now
707  assert(iRef==1);
708  iRef = 0;
709 }
710 
711 
712 /* ----------------- C4KeyboardInput ------------------ */
713 
714 bool C4KeyboardInput::IsValid = false;
715 
717 {
718  LastKeyExtraData = C4KeyEventData();
719  // release all keys - name map is guarantueed to contain them all
720  for (KeyNameMap::const_iterator i = KeysByName.begin(); i != KeysByName.end(); ++i)
721  i->second->Deref();
722  // clear maps
723  KeysByCode.clear();
724  KeysByName.clear();
725 }
726 
727 void C4KeyboardInput::UpdateKeyCodes(C4CustomKey *pKey, const C4CustomKey::CodeList &rOldCodes, const C4CustomKey::CodeList &rNewCodes)
728 {
729  // new key codes must be the new current key codes
730  assert(pKey->GetCodes() == rNewCodes);
731  // kill from old list
732  C4CustomKey::CodeList::const_iterator iCode;
733  for (iCode = rOldCodes.begin(); iCode != rOldCodes.end(); ++iCode)
734  {
735  // no need to kill if code stayed
736  if (std::find(rNewCodes.begin(), rNewCodes.end(), *iCode) != rNewCodes.end()) continue;
737  std::pair<KeyCodeMap::iterator, KeyCodeMap::iterator> KeyRange = KeysByCode.equal_range((*iCode).Key);
738  for (KeyCodeMap::iterator i = KeyRange.first; i != KeyRange.second; ++i)
739  if (i->second == pKey)
740  {
741  KeysByCode.erase(i);
742  break;
743  }
744  }
745  // readd new codes
746  for (iCode = rNewCodes.begin(); iCode != rNewCodes.end(); ++iCode)
747  {
748  // no double-add if it was in old list already
749  if (std::find(rOldCodes.begin(), rOldCodes.end(), *iCode) != rOldCodes.end()) continue;
750  KeysByCode.insert(std::make_pair((*iCode).Key, pKey));
751  }
752 }
753 
755 {
756  assert(pRegKey); if (!pRegKey) return;
757  // key will be added: ref it
758  pRegKey->Ref();
759  // search key of same name first
760  C4CustomKey *pDupKey = KeysByName[pRegKey->GetName().getData()];
761  if (pDupKey)
762  {
763  // key of this name exists: Merge them (old codes copied cuz they'll be overwritten)
764  C4CustomKey::CodeList OldCodes = pDupKey->GetCodes();
765  const C4CustomKey::CodeList &rNewCodes = pRegKey->GetCodes();
766  pDupKey->Update(pRegKey);
767  // update access map if key changed
768  if (!(OldCodes == rNewCodes)) UpdateKeyCodes(pDupKey, OldCodes, rNewCodes);
769  // key to be registered no longer used
770  pRegKey->Deref();
771  }
772  else
773  {
774  // new unique key: Insert into map
775  KeysByName[pRegKey->GetName().getData()] = pRegKey;
776  for (C4CustomKey::CodeList::const_iterator i = pRegKey->GetCodes().begin(); i != pRegKey->GetCodes().end(); ++i)
777  {
778  KeysByCode.insert(std::make_pair((*i).Key, pRegKey));
779  }
780  }
781 }
782 
784 {
785  // kill from name map
786  KeyNameMap::iterator in = KeysByName.find(rsName.getData());
787  if (in == KeysByName.end()) return;
788  C4CustomKey *pKey = in->second;
789  KeysByName.erase(in);
790  // kill all key bindings from key map
791  for (C4CustomKey::CodeList::const_iterator iCode = pKey->GetCodes().begin(); iCode != pKey->GetCodes().end(); ++iCode)
792  {
793  std::pair<KeyCodeMap::iterator, KeyCodeMap::iterator> KeyRange = KeysByCode.equal_range((*iCode).Key);
794  for (KeyCodeMap::iterator i = KeyRange.first; i != KeyRange.second; ++i)
795  if (i->second == pKey)
796  {
797  KeysByCode.erase(i);
798  break;
799  }
800  }
801  // release reference to key
802  pKey->Deref();
803 }
804 
806 {
807  // find key in name map
808  KeyNameMap::iterator in = KeysByName.find(pUnregKey->GetName().getData());
809  if (in == KeysByName.end()) return;
810  C4CustomKey *pKey = in->second;
811  // is this key in the map?
812  if (pKey != pUnregKey)
813  {
814  // Other key is in the list: Just remove the callbacks
815  pKey->KillCallbacks(pUnregKey);
816  return;
817  }
818  // this key is in the list: Replace by a duplicate...
819  C4CustomKey *pNewKey = new C4CustomKey(*pUnregKey, true);
820  // ...without the own callbacks
821  pNewKey->KillCallbacks(pUnregKey);
822  // and replace current key by duplicate
823  UnregisterKey(pUnregKey->GetName());
824  RegisterKey(pNewKey);
825 }
826 
827 bool C4KeyboardInput::DoInput(const C4KeyCodeEx &InKey, C4KeyEventType InEvent, DWORD InScope, int32_t iStrength)
828 {
829  // store last-key-info
830  LastKeyExtraData.iStrength = (iStrength >= 0) ? iStrength : ((InEvent != KEYEV_Up) * 100);
831  LastKeyExtraData.game_x = LastKeyExtraData.game_y = LastKeyExtraData.vp_x = LastKeyExtraData.vp_y = C4KeyEventData::KeyPos_None;
832  // check all key events generated by this key: First the keycode itself, then any more generic key events like KEY_Any
833  const int32_t iKeyRangeMax = 5;
834  int32_t iKeyRangeCnt=0, j;
835  C4KeyCode FallbackKeys[iKeyRangeMax];
836  FallbackKeys[iKeyRangeCnt++] = InKey.Key;
837  if (Key_IsGamepadButton(InKey.Key))
838  {
839  // "any gamepad button"-event
840  FallbackKeys[iKeyRangeCnt++] = KEY_Gamepad(KEY_CONTROLLER_AnyButton);
841  }
842  else if (Key_IsGamepadAxis(InKey.Key))
843  {
844  // TODO: do we need "any axis" events?
845  }
846  if (InKey.Key != KEY_Any) FallbackKeys[iKeyRangeCnt++] = KEY_Any;
847  // now get key ranges for fallback chain
848  std::pair<KeyCodeMap::iterator, KeyCodeMap::iterator> KeyRanges[iKeyRangeMax];
849  assert(iKeyRangeCnt <= iKeyRangeMax);
850  for (int32_t i = 0; i<iKeyRangeCnt; ++i)
851  {
852  KeyRanges[i] = KeysByCode.equal_range(FallbackKeys[i]);
853  }
854  // check all assigned keys
855  // exec from highest to lowest priority
856  unsigned int uiLastPrio = C4CustomKey::PRIO_MoreThanMax;
857  for (;;)
858  {
859  KeyCodeMap::const_iterator i;
860  // get priority to exec
861  unsigned int uiExecPrio = C4CustomKey::PRIO_None, uiCurr;
862  for (j = 0; j < iKeyRangeCnt; ++j)
863  for (i = KeyRanges[j].first; i != KeyRanges[j].second; ++i)
864  {
865  uiCurr = i->second->GetPriority();
866  if (uiCurr > uiExecPrio && uiCurr < uiLastPrio) uiExecPrio = uiCurr;
867  }
868  // nothing with correct priority set left?
869  if (uiExecPrio == C4CustomKey::PRIO_None) break;
870  // exec all of this priority
871  for (j = 0; j < iKeyRangeCnt; ++j)
872  for (i = KeyRanges[j].first; i != KeyRanges[j].second; ++i)
873  {
874  C4CustomKey *pKey = i->second;
875  assert(pKey);
876  // check priority
877  if (pKey->GetPriority() == uiExecPrio)
878  // check scope and modifier
879  // (not on release of a key that has been down, because a key release might happen with a different modifier or in different scope than its pressing!)
880  if ((InEvent == KEYEV_Up && pKey->IsDown())
881  || ((pKey->GetScope() & InScope) && pKey->IsCodeMatched(C4KeyCodeEx(FallbackKeys[j], C4KeyShiftState(InKey.dwShift)))))
882  // exec it
883  if (pKey->Execute(InEvent, InKey))
884  return true;
885  }
886  // nothing found in this priority: exec next
887  uiLastPrio = uiExecPrio;
888  }
889  // no key matched or all returned false in Execute: Not processed
890  return false;
891 }
892 
894 {
895  // compile all keys that are already defined
896  // no definition of new keys with current compiler...
897  pComp->Name("Keys");
898  try
899  {
900  for (KeyNameMap::const_iterator i = KeysByName.begin(); i != KeysByName.end(); ++i)
901  {
902  // naming done in C4CustomKey, because default is determined by key only
903  C4CustomKey::CodeList OldCodes = i->second->GetCodes();
904  pComp->Value(*i->second);
905  // resort in secondary map if key changed
906  if (pComp->isDeserializer())
907  {
908  const C4CustomKey::CodeList &rNewCodes = i->second->GetCodes();
909  if (!(OldCodes == rNewCodes)) UpdateKeyCodes(i->second, OldCodes, rNewCodes);
910  }
911  }
912  }
913  catch (StdCompiler::Exception *pEx)
914  {
915  pComp->NameEnd(true);
916  throw pEx;
917  }
918  pComp->NameEnd();
919 }
920 
922 {
923  // load from INI file (2do: load from registry)
924  C4Group GrpExtra;
925  if (!GrpExtra.Open(C4CFN_Extra)) return false;
926  StdBuf sFileContents;
927  if (!GrpExtra.LoadEntry(C4CFN_KeyConfig, &sFileContents)) return false;
928  StdStrBuf sFileContentsString((const char *) sFileContents.getData());
929  if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(*this, sFileContentsString, "Custom keys from" C4CFN_Extra DirSep C4CFN_KeyConfig))
930  return false;
931  LogF(LoadResStr("IDS_PRC_LOADEDKEYCONF"), C4CFN_Extra DirSep C4CFN_KeyConfig);
932  return true;
933 }
934 
936 {
937  KeyNameMap::const_iterator i = KeysByName.find(szKeyName);
938  if (i == KeysByName.end()) return nullptr; else return (*i).second;
939 }
940 
941 StdStrBuf C4KeyboardInput::GetKeyCodeNameByKeyName(const char *szKeyName, bool fShort, int32_t iIndex)
942 {
943  C4CustomKey *pKey = GetKeyByName(szKeyName);
944  if (pKey)
945  {
946  const C4CustomKey::CodeList &codes = pKey->GetCodes();
947  if ((size_t)iIndex < codes.size())
948  {
949  C4KeyCodeEx code = codes[iIndex];
950  return code.ToString(true, fShort);
951  }
952  }
953  // Error
954  return StdStrBuf();
955 }
956 
958 {
959  static C4KeyboardInput keyinp;
960  return keyinp;
961 }
const char * getData() const
Definition: StdBuf.h:450
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:129
#define C4CFN_Extra
Definition: C4Components.h:31
C4KeyScope GetScope() const
const void * getData() const
Definition: StdBuf.h:107
Definition: StdBuf.h:37
C4KeyCodeEx(C4KeyCode Key=KEY_Default, C4KeyShiftState Shift=KEYS_None, bool fIsRepeated=false, int32_t deviceId=-1)
virtual void NoSeparator()
Definition: StdCompiler.h:130
static C4KeyShiftState String2KeyShift(const StdStrBuf &sName)
uint8_t Key_GetMouse(C4KeyCode key)
const C4KeyCode KEY_CONTROLLER_ButtonLeftShoulder
static C4KeyCode String2KeyCode(const StdStrBuf &sName)
C4Game Game
Definition: C4Globals.cpp:52
void excCorrupt(const char *szMessage,...)
Definition: StdCompiler.h:259
const C4KeyCode KEY_CONTROLLER_AxisTriggerLeft
void Clear()
Definition: StdBuf.h:474
const C4KeyCode KEY_MOUSE_ButtonX1
const C4KeyCode KEY_CONTROLLER_ButtonY
C4CustomKey(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority=PRIO_Base)
C4CustomKey * GetKeyByName(const char *szKeyName)
int stricmp(const char *s1, const char *s2)
const char * szShortName
const C4KeyCode KEY_CONTROLLER_ButtonRightStick
C4KeyShiftState
const C4KeyCode KEY_CONTROLLER_ButtonStart
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:184
const C4KeyCode KEY_CONTROLLER_ButtonB
void CompileFunc(StdCompiler *pComp)
void Update(const C4CustomKey *pByKey)
bool LoadEntry(const char *szEntryName, char **lpbpBuf, size_t *ipSize=nullptr, int iAppendZeros=0)
Definition: C4Group.cpp:1893
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:181
bool C4KeyboardCallbackInterfaceHasOriginalKey(C4KeyboardCallbackInterface *pIntfc, const C4CustomKey *pCheckKey)
virtual bool Name(const char *szName)
Definition: StdCompiler.h:87
const C4KeyCode KEY_MOUSE_Button1
const C4KeyCode KEY_MOUSE_Wheel1Up
const C4KeyCode KEY_CONTROLLER_ButtonDpadDown
const C4KeyCode KEY_CONTROLLER_AxisLeftXRight
const char * KeycodeToString(C4KeyCode code)
Definition: C4AppSDL.cpp:252
const C4KeyCodeMapEntry KeyCodeMap[]
C4KeyCode KEY_Mouse(uint8_t mouse_id, uint8_t mouseevent)
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:93
void AppendChar(char cChar)
Definition: StdBuf.h:596
static StdStrBuf KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool fShort)
bool operator==(const struct C4KeyEventData &cmp) const
std::vector< C4KeyCodeEx > CodeList
StdStrBuf GetKeyCodeNameByKeyName(const char *szKeyName, bool fShort=false, int32_t iIndex=0)
uint8_t Key_GetMouseEvent(C4KeyCode key)
const C4KeyCode KEY_CONTROLLER_ButtonBack
const C4KeyShiftMapEntry KeyShiftMap[]
const C4KeyCode KEY_CONTROLLER_ButtonA
const C4KeyCode KEY_CONTROLLER_ButtonRightShoulder
bool Key_IsGamepadButton(C4KeyCode key)
const StdStrBuf & GetName() const
C4KeyboardInput & KeyboardInput
Definition: C4Game.h:98
const C4KeyCode KEY_CONTROLLER_AxisRightXLeft
const C4KeyCode KEY_MOUSE_ButtonLeftDouble
const C4KeyCode KEY_Default
bool Open(const char *szGroupName, bool fCreate=false)
Definition: C4Group.cpp:514
StdDecompileAdapt< T > mkDecompileAdapt(const T &rValue)
Definition: StdAdaptors.h:154
const C4KeyCode KEY_MOUSE_ButtonX1Double
void Take(char *pnData)
Definition: StdBuf.h:465
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:527
bool Key_IsMouse(C4KeyCode key)
bool Key_IsGamepad(C4KeyCode key)
C4KeyCode KEY_Gamepad(uint8_t idButton)
const C4KeyCode KEY_CONTROLLER_AxisLeftXLeft
void Value(const T &rStruct)
Definition: StdCompiler.h:171
const C4KeyCode KEY_CONTROLLER_ButtonLeftStick
const C4KeyCode KEY_MOUSE_ButtonX2
C4KeyboardInput & C4KeyboardInput_Init()
C4KeyCode Key
const C4KeyCode KEY_MOUSE_ButtonX2Double
const C4KeyCode KEY_MOUSE_Move
virtual bool isDeserializer()
Definition: StdCompiler.h:63
const C4KeyCode KEY_Undefined
static bool IsValid
const C4KeyCode KEY_MOUSE_ButtonRightDouble
const C4KeyCode KEY_MOUSE_Button1Double
C4KeyEventType
C4KeyBinding(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority=PRIO_Base)
uint8_t Key_GetGamepadEvent(C4KeyCode key)
bool IsCodeMatched(const C4KeyCodeEx &key) const
StdSTLContainerAdapt< C > mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep=StdCompiler::SEP_SEP)
Definition: StdAdaptors.h:682
C4KeyShiftState eShift
C4KeyScope
bool IsOriginalKey(const class C4CustomKey *pCheckKey) const
bool DoInput(const C4KeyCodeEx &InKey, C4KeyEventType InEvent, DWORD InScope, int32_t iStrength)
const C4KeyCode KEY_CONTROLLER_AxisRightYDown
bool Key_IsGamepadAxis(C4KeyCode key)
const C4KeyCode KEY_CONTROLLER_AxisRightXRight
StdStrBuf ToString(bool fHumanReadable, bool fShort) const
void KillCallbacks(const C4CustomKey *pOfKey)
unsigned int GetPriority() const
const C4KeyCode KEY_Any
const C4KeyCode KEY_CONTROLLER_ButtonDpadLeft
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:459
const C4KeyCode KEY_CONTROLLER_ButtonGuide
size_t getLength() const
Definition: StdBuf.h:453
#define C4CFN_KeyConfig
Definition: C4Components.h:139
const C4KeyCode KEY_MOUSE_ButtonMiddleDouble
const CodeList & GetCodes() const
const C4KeyCode KEY_CONTROLLER_AxisRightYUp
virtual ~C4CustomKey()
const C4KeyCode KEY_MOUSE_ButtonRight
void UnregisterKey(const StdStrBuf &rsName)
#define DirSep
void RegisterKey(C4CustomKey *pRegKey)
void CompileFunc(StdCompiler *pComp)
const C4KeyCode KEY_CONTROLLER_AxisLeftYUp
const C4KeyCode KEY_CONTROLLER_ButtonDpadUp
uint32_t DWORD
const C4KeyCode KEY_MOUSE_ButtonLeft
void CompileFunc(StdCompiler *pComp, StdStrBuf *pOutBuf=nullptr)
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:253
void Copy()
Definition: StdBuf.h:475
const C4KeyCode KEY_CONTROLLER_ButtonX
const C4KeyCode KEY_CONTROLLER_AnyButton
const C4KeyCode KEY_CONTROLLER_ButtonDpadRight
#define s
bool Execute(C4KeyEventType eEv, C4KeyCodeEx key)
bool IsDown() const
unsigned long C4KeyCode
virtual void NameEnd(bool fBreak=false)
Definition: StdCompiler.h:88
const C4KeyCode KEY_CONTROLLER_AxisLeftYDown
void UnregisterKeyBinding(C4CustomKey *pKey)
class C4CustomKey * pOriginalKey
const C4KeyCode KEY_MOUSE_ButtonMiddle
const C4KeyCode KEY_MOUSE_Wheel1Down
const C4KeyCode KEY_CONTROLLER_AxisTriggerRight
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:277
static StdStrBuf KeyShift2String(C4KeyShiftState eShift)
void CompileFunc(StdCompiler *pComp)