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 #ifndef INC_C4KeyboardInput
19 #define INC_C4KeyboardInput
20
21 // key context classifications
22 enum C4KeyScope
23 {
24 KEYSCOPE_None = 0,
25 KEYSCOPE_Control = 1, // player control (e.g. NUM1 to move left on keypad control)
26 KEYSCOPE_Gui = 2, // keys used to manipulate GUI elements (e.g. Tab to cycle through controls)
27 KEYSCOPE_Fullscreen = 4, // generic fullscreen-only keys (e.g. F9 for screenshot)
28 KEYSCOPE_Console = 8, // generic console-mode only keys (e.g. Space to switch edit cursor)
29 KEYSCOPE_Generic = 16, // generic keys available in fullscreen and console mode outside GUI (e.g. F1 for music on/off)
30 KEYSCOPE_FullSMenu = 32, // fullscreen menu control. If fullscreen menu is active, this disables viewport controls (e.g. Return to close player join menu)
31 KEYSCOPE_FilmView = 64, // ownerless viewport scrolling in film mode, player switching, etc. (e.g. Enter to switch to next player)
32 KEYSCOPE_FreeView = 128, // ownerless viewport scrolling, player switching, etc. (e.g. arrow left to scroll left in view)
33 KEYSCOPE_FullSView = 256 // player fullscreen viewport
34 };
35
36 // what can happen to keys
37 enum C4KeyEventType
38 {
39 KEYEV_None = 0, // no event
40 KEYEV_Down = 1, // in response to WM_KEYDOWN or joypad button pressed
41 KEYEV_Up = 2, // in response to WM_KEYUP or joypad button released
42 KEYEV_Pressed = 3, // in response to WM_KEYPRESSED
43 KEYEV_Moved = 4, // when moving a gamepad stick
44 };
45
46 // keyboard code
47 typedef unsigned long C4KeyCode;
48
49 // Gamepad codes (KEY_CONTROLLER_*): Masked as 0x420000; bit 8-15 used for gamepad index
50 const C4KeyCode KEY_CONTROLLER_Mask = 0x420000;
51
52 // Mouse codes (KEY_MOUSE_*): Masked as 0x430000; bit 8-15 used for mouse index
53 const C4KeyCode KEY_MOUSE_Mask = 0x430000;
54
55 const C4KeyCode
56 KEY_Default = 0, // no key
57 KEY_Any = ~0, // used for default key processing
58 KEY_Undefined = (~0)^1, // used to indicate an unknown key
59 KEY_CONTROLLER_ButtonMin = 0x10, // first button
60 KEY_CONTROLLER_ButtonA = 0x10,
61 KEY_CONTROLLER_ButtonB = 0x11,
62 KEY_CONTROLLER_ButtonX = 0x12,
63 KEY_CONTROLLER_ButtonY = 0x13,
64 KEY_CONTROLLER_ButtonBack = 0x14,
65 KEY_CONTROLLER_ButtonGuide = 0x15,
66 KEY_CONTROLLER_ButtonStart = 0x16,
67 KEY_CONTROLLER_ButtonLeftStick = 0x17,
68 KEY_CONTROLLER_ButtonRightStick = 0x18,
69 KEY_CONTROLLER_ButtonLeftShoulder = 0x19,
70 KEY_CONTROLLER_ButtonRightShoulder = 0x1a,
71 KEY_CONTROLLER_ButtonDpadUp = 0x1b,
72 KEY_CONTROLLER_ButtonDpadDown = 0x1c,
73 KEY_CONTROLLER_ButtonDpadLeft = 0x1d,
74 KEY_CONTROLLER_ButtonDpadRight = 0x1e,
75 KEY_CONTROLLER_ButtonMax = 0x1e, // last button
76 KEY_CONTROLLER_AnyButton = 0xff, // any of the buttons above
77 KEY_CONTROLLER_AxisMin = 0x30, // first axis
78 KEY_CONTROLLER_AxisLeftXLeft = 0x30,
79 KEY_CONTROLLER_AxisLeftXRight = 0x31,
80 KEY_CONTROLLER_AxisLeftYUp = 0x32,
81 KEY_CONTROLLER_AxisLeftYDown = 0x33,
82 KEY_CONTROLLER_AxisRightXLeft = 0x34,
83 KEY_CONTROLLER_AxisRightXRight = 0x35,
84 KEY_CONTROLLER_AxisRightYUp = 0x36,
85 KEY_CONTROLLER_AxisRightYDown = 0x37,
86 KEY_CONTROLLER_AxisTriggerLeft = 0x39, // triggers are only positive
87 KEY_CONTROLLER_AxisTriggerRight = 0x3b,
88 KEY_CONTROLLER_AxisMax = 0x3b, // last axis
89 KEY_MOUSE_Move = 1, // mouse control: mouse movement
90 KEY_MOUSE_Button1 = 0x10, // key index of mouse buttons + button index for more buttons
91 KEY_MOUSE_ButtonLeft = KEY_MOUSE_Button1 + 0,
92 KEY_MOUSE_ButtonRight = KEY_MOUSE_Button1 + 1,
93 KEY_MOUSE_ButtonMiddle = KEY_MOUSE_Button1 + 2,
94 KEY_MOUSE_ButtonX1 = KEY_MOUSE_Button1 + 3,
95 KEY_MOUSE_ButtonX2 = KEY_MOUSE_Button1 + 4,
96 KEY_MOUSE_ButtonMax = KEY_MOUSE_Button1 + 0x1f, // max number of supported mouse buttons
97 KEY_MOUSE_Button1Double = 0x30, // double clicks have special events because double click speed is issued by OS
98 KEY_MOUSE_ButtonLeftDouble = KEY_MOUSE_Button1Double + 0,
99 KEY_MOUSE_ButtonRightDouble = KEY_MOUSE_Button1Double + 1,
100 KEY_MOUSE_ButtonMiddleDouble = KEY_MOUSE_Button1Double + 2,
101 KEY_MOUSE_ButtonX1Double = KEY_MOUSE_Button1Double + 3,
102 KEY_MOUSE_ButtonX2Double = KEY_MOUSE_Button1Double + 4,
103 KEY_MOUSE_ButtonMaxDouble = KEY_MOUSE_Button1Double + 0x1f, // max number of supported mouse buttons
104 KEY_MOUSE_Wheel1Up = 0x40, // mouse control: wheel up
105 KEY_MOUSE_Wheel1Down = 0x41; // mouse control: wheel down
106
KEY_CONTROLLER_Button(uint8_t idx)107 inline uint8_t KEY_CONTROLLER_Button(uint8_t idx) { return KEY_CONTROLLER_ButtonMin+idx; }
KEY_CONTROLLER_Axis(uint8_t idx,bool fMax)108 inline uint8_t KEY_CONTROLLER_Axis(uint8_t idx, bool fMax) { return KEY_CONTROLLER_AxisMin+2*idx+fMax; }
109
KEY_Gamepad(uint8_t idButton)110 inline C4KeyCode KEY_Gamepad(uint8_t idButton) // convert gamepad key to Clonk-gamepad-keycode
111 {
112 // mask key as 0x004200bb, where 00 used to be the gamepad ID and bb is button ID.
113 return KEY_CONTROLLER_Mask + idButton;
114 }
115
Key_IsGamepad(C4KeyCode key)116 inline bool Key_IsGamepad(C4KeyCode key)
117 {
118 return (0xff0000 & key) == KEY_CONTROLLER_Mask;
119 }
120
Key_GetGamepad(C4KeyCode key)121 inline uint8_t Key_GetGamepad(C4KeyCode key)
122 {
123 return ((uint32_t)key >> 8) & 0xff;
124 }
125
Key_GetGamepadEvent(C4KeyCode key)126 inline uint8_t Key_GetGamepadEvent(C4KeyCode key)
127 {
128 return ((uint32_t)key) & 0xff;
129 }
130
Key_IsGamepadButton(C4KeyCode key)131 inline bool Key_IsGamepadButton(C4KeyCode key)
132 {
133 // whether this is a unique button event (AnyButton not included)
134 return Key_IsGamepad(key) && Inside<uint8_t>(Key_GetGamepadEvent(key), KEY_CONTROLLER_ButtonMin, KEY_CONTROLLER_ButtonMax);
135 }
136
Key_IsGamepadAxis(C4KeyCode key)137 inline bool Key_IsGamepadAxis(C4KeyCode key)
138 {
139 // whether this is a unique button event (AnyButton not included)
140 return Key_IsGamepad(key) && Inside<uint8_t>(Key_GetGamepadEvent(key), KEY_CONTROLLER_AxisMin, KEY_CONTROLLER_AxisMax);
141 }
142
Key_GetGamepadButtonIndex(C4KeyCode key)143 inline uint8_t Key_GetGamepadButtonIndex(C4KeyCode key)
144 {
145 // get zero-based button index
146 return Key_GetGamepadEvent(key) - KEY_CONTROLLER_ButtonMin;
147 }
148
Key_GetGamepadAxisIndex(C4KeyCode key)149 inline uint8_t Key_GetGamepadAxisIndex(C4KeyCode key)
150 {
151 // get zero-based axis index
152 return (Key_GetGamepadEvent(key) - KEY_CONTROLLER_AxisMin) / 2;
153 }
154
Key_IsGamepadAxisHigh(C4KeyCode key)155 inline bool Key_IsGamepadAxisHigh(C4KeyCode key)
156 {
157 return !!(key & 1);
158 }
159
KEY_Mouse(uint8_t mouse_id,uint8_t mouseevent)160 inline C4KeyCode KEY_Mouse(uint8_t mouse_id, uint8_t mouseevent)
161 {
162 // mask key as 0x0043ggbb, where mm is mouse ID and bb is mouse event ID.
163 return KEY_MOUSE_Mask + (mouse_id<<8) + mouseevent;
164 }
165
Key_IsMouse(C4KeyCode key)166 inline bool Key_IsMouse(C4KeyCode key)
167 {
168 return (0xff0000 & key) == KEY_MOUSE_Mask;
169 }
170
Key_GetMouse(C4KeyCode key)171 inline uint8_t Key_GetMouse(C4KeyCode key)
172 {
173 return ((uint32_t)key >> 8) & 0xff;
174 }
175
Key_GetMouseEvent(C4KeyCode key)176 inline uint8_t Key_GetMouseEvent(C4KeyCode key)
177 {
178 return ((uint32_t)key) & uint8_t(0xff);
179 }
180
181 bool KEY_IsModifier(C4KeyCode k);
182
183 #ifdef _WIN32
184 #define TOUPPERIFX11(key) (key)
185 #else
186 #define TOUPPERIFX11(key) toupper(key)
187 #endif
188
189 enum C4KeyShiftState
190 {
191 KEYS_None = 0,
192 KEYS_First = 1,
193 KEYS_Alt = 1,
194 KEYS_Control = 2,
195 KEYS_Shift = 4,
196 KEYS_Max = KEYS_Shift,
197 KEYS_Undefined = 0xffff
198 };
199
200 // extended key information containing shift state
201 struct C4KeyCodeEx
202 {
203 C4KeyCode Key; // the key
204 DWORD dwShift; // the status of Alt, Shift, Control
205
206 int32_t deviceId;
207
208 // if set, the keycode was generated by a key that has been held down
209 // this flag is ignored in comparison operations
210 bool fRepeated;
211
212 // helpers
213 static C4KeyShiftState String2KeyShift(const StdStrBuf &sName);
214 static C4KeyCode String2KeyCode(const StdStrBuf &sName);
215 static StdStrBuf KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool fShort);
216 StdStrBuf ToString(bool fHumanReadable, bool fShort) const;
217 static StdStrBuf KeyShift2String(C4KeyShiftState eShift);
218
219 // comparison operator for map access
220 inline bool operator <(const C4KeyCodeEx &v2) const
221 {
222 return Key < v2.Key || (Key == v2.Key && dwShift < v2.dwShift);
223 }
224
225 inline bool operator ==(const C4KeyCodeEx &v2) const
226 {
227 return Key == v2.Key && dwShift == v2.dwShift;
228 }
229
230 void CompileFunc(StdCompiler *pComp, StdStrBuf *pOutBuf=nullptr);
231
232 C4KeyCodeEx(C4KeyCode Key = KEY_Default, DWORD Shift = KEYS_None, bool fIsRepeated = false, int32_t deviceId = -1);
233 static C4KeyCodeEx FromC4MC(int8_t mouse_id, int32_t button, DWORD param, bool * is_down = nullptr);
234
IsRepeatedC4KeyCodeEx235 bool IsRepeated() const { return fRepeated; }
236
237 void FixShiftKeys(); // reduce stuff like Ctrl+RightCtrl to simply RightCtrl
238 private:
239 static C4KeyCode GetKeyByScanCode(const char *scan_code);
240 };
241
242 // extra data associated with a key event
243 struct C4KeyEventData
244 {
245 enum { KeyPos_None = 0x7fffff }; // value used to denote invalid/none key positions
246 int32_t iStrength{0}; // pressure between 0 and 100 (100 for nomal keypress)
247 int32_t game_x{KeyPos_None},game_y{KeyPos_None}, vp_x{KeyPos_None},vp_y{KeyPos_None}; // position for mouse event, landscape+viewport coordinates
248 C4KeyEventData() = default;
C4KeyEventDataC4KeyEventData249 C4KeyEventData(int32_t iStrength, int32_t game_x, int32_t game_y, int32_t vp_x, int32_t vp_y) : iStrength(iStrength), game_x(game_x), game_y(game_y),vp_x(vp_x),vp_y(vp_y) {}
250 void CompileFunc(StdCompiler *pComp);
251 bool operator ==(const struct C4KeyEventData &cmp) const;
252 };
253
254 // Helper functions for high-level GUI control mappings.
255 namespace ControllerKeys {
Any(T & keys)256 template<class T> void Any(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_AnyButton))); }
Cancel(T & keys)257 template<class T> void Cancel(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_ButtonB))); }
Ok(T & keys)258 template<class T> void Ok(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_ButtonA))); }
Left(T & keys)259 template<class T> void Left(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_AxisLeftXLeft)));
260 keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_ButtonDpadLeft))); }
Right(T & keys)261 template<class T> void Right(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_AxisLeftXRight)));
262 keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_ButtonDpadRight))); }
Up(T & keys)263 template<class T> void Up(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_AxisLeftYUp)));
264 keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_ButtonDpadUp))); }
Down(T & keys)265 template<class T> void Down(T &keys) { keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_AxisLeftYDown)));
266 keys.push_back(C4KeyCodeEx(KEY_Gamepad(KEY_CONTROLLER_ButtonDpadDown))); }
267 }
268
269 // callback interface
270 class C4KeyboardCallbackInterface
271 {
272 private:
273 int iRef{0};
274 public:
275 class C4CustomKey *pOriginalKey{nullptr};
276
277 public:
278 virtual bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv) = 0; // return true if processed
279
280 friend class C4KeyboardMapping;
281
282 // reference counter
Ref()283 inline void Ref() { ++iRef; }
Deref()284 inline void Deref() { if (!--iRef) delete this; }
285
286 C4KeyboardCallbackInterface() = default;
287 virtual ~C4KeyboardCallbackInterface() = default;
288
IsOriginalKey(const class C4CustomKey * pCheckKey)289 bool IsOriginalKey(const class C4CustomKey *pCheckKey) const { return pCheckKey == pOriginalKey; }
290 };
291
292 // callback interface
293 template <class TargetClass> class C4KeyCB : public C4KeyboardCallbackInterface
294 {
295 public:
296 typedef bool(TargetClass::*CallbackFunc)();
297
298 protected:
299 TargetClass &rTarget;
300 CallbackFunc pFuncDown, pFuncUp, pFuncPressed, pFuncMoved;
301
302 protected:
OnKeyEvent(const C4KeyCodeEx & key,C4KeyEventType eEv)303 bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv) override
304 {
305 if (!CheckCondition()) return false;
306 switch (eEv)
307 {
308 case KEYEV_Down: return pFuncDown ? (rTarget.*pFuncDown)() : false;
309 case KEYEV_Up: return pFuncUp ? (rTarget.*pFuncUp)() : false;
310 case KEYEV_Pressed: return pFuncPressed ? (rTarget.*pFuncPressed)() : false;
311 case KEYEV_Moved: return pFuncMoved ? (rTarget.*pFuncMoved)() : false;
312 default: return false;
313 }
314 }
315
CheckCondition()316 virtual bool CheckCondition() { return true; }
317
318 public:
319 C4KeyCB(TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr, CallbackFunc pFuncMoved=nullptr)
rTarget(rTarget)320 : rTarget(rTarget), pFuncDown(pFuncDown), pFuncUp(pFuncUp), pFuncPressed(pFuncPressed), pFuncMoved(pFuncMoved) {}
321 };
322
323 // callback interface that passes the pressed key as a parameter
324 template <class TargetClass> class C4KeyCBPassKey : public C4KeyboardCallbackInterface
325 {
326 public:
327 typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key);
328
329 protected:
330 TargetClass &rTarget;
331 CallbackFunc pFuncDown, pFuncUp, pFuncPressed, pFuncMoved;
332
333 protected:
OnKeyEvent(const C4KeyCodeEx & key,C4KeyEventType eEv)334 bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv) override
335 {
336 if (!CheckCondition()) return false;
337 switch (eEv)
338 {
339 case KEYEV_Down: return pFuncDown ? (rTarget.*pFuncDown)(key) : false;
340 case KEYEV_Up: return pFuncUp ? (rTarget.*pFuncUp)(key) : false;
341 case KEYEV_Pressed: return pFuncPressed ? (rTarget.*pFuncPressed)(key) : false;
342 case KEYEV_Moved: return pFuncMoved ? (rTarget.*pFuncMoved)(key) : false;
343 default: return false;
344 }
345 }
346
CheckCondition()347 virtual bool CheckCondition() { return true; }
348
349 public:
350 C4KeyCBPassKey(TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr, CallbackFunc pFuncMoved=nullptr)
rTarget(rTarget)351 : rTarget(rTarget), pFuncDown(pFuncDown), pFuncUp(pFuncUp), pFuncPressed(pFuncPressed), pFuncMoved(pFuncMoved) {}
352 };
353
354 // parameterized callback interface
355 template <class TargetClass, class ParameterType> class C4KeyCBEx : public C4KeyboardCallbackInterface
356 {
357 public:
358 typedef bool(TargetClass::*CallbackFunc)(ParameterType par);
359
360 protected:
361 TargetClass &rTarget;
362 CallbackFunc pFuncDown, pFuncUp, pFuncPressed, pFuncMoved;
363 ParameterType par;
364
365 protected:
OnKeyEvent(const C4KeyCodeEx & key,C4KeyEventType eEv)366 bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv) override
367 {
368 if (!CheckCondition()) return false;
369 switch (eEv)
370 {
371 case KEYEV_Down: return pFuncDown ? (rTarget.*pFuncDown)(par) : false;
372 case KEYEV_Up: return pFuncUp ? (rTarget.*pFuncUp)(par) : false;
373 case KEYEV_Pressed: return pFuncPressed ? (rTarget.*pFuncPressed)(par) : false;
374 case KEYEV_Moved: return pFuncMoved ? (rTarget.*pFuncMoved)(par) : false;
375 default: return false;
376 }
377 }
378
CheckCondition()379 virtual bool CheckCondition() { return true; }
380
381 public:
382 C4KeyCBEx(TargetClass &rTarget, const ParameterType &par, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr, CallbackFunc pFuncMoved=nullptr)
rTarget(rTarget)383 : rTarget(rTarget), pFuncDown(pFuncDown), pFuncUp(pFuncUp), pFuncPressed(pFuncPressed), pFuncMoved(pFuncMoved), par(par) {}
384 };
385
386 template <class TargetClass, class ParameterType> class C4KeyCBExPassKey : public C4KeyboardCallbackInterface
387 {
388 public:
389 typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key, const ParameterType &par);
390
391 protected:
392 TargetClass &rTarget;
393 CallbackFunc pFuncDown, pFuncUp, pFuncPressed, pFuncMoved;
394 ParameterType par;
395
396 protected:
OnKeyEvent(const C4KeyCodeEx & key,C4KeyEventType eEv)397 bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv) override
398 {
399 if (!CheckCondition()) return false;
400 switch (eEv)
401 {
402 case KEYEV_Down: return pFuncDown ? (rTarget.*pFuncDown)(key, par) : false;
403 case KEYEV_Up: return pFuncUp ? (rTarget.*pFuncUp)(key, par) : false;
404 case KEYEV_Pressed: return pFuncPressed ? (rTarget.*pFuncPressed)(key, par) : false;
405 case KEYEV_Moved: return pFuncMoved ? (rTarget.*pFuncMoved)(key, par) : false;
406 default: return false;
407 }
408 }
409
CheckCondition()410 virtual bool CheckCondition() { return true; }
411
412 public:
413 C4KeyCBExPassKey(TargetClass &rTarget, const ParameterType &par, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr, CallbackFunc pFuncMoved=nullptr)
rTarget(rTarget)414 : rTarget(rTarget), pFuncDown(pFuncDown), pFuncUp(pFuncUp), pFuncPressed(pFuncPressed), pFuncMoved(pFuncMoved), par(par) {}
415 };
416
417 // one mapped keyboard entry
418 class C4CustomKey
419 {
420 public:
421 typedef std::vector<C4KeyCodeEx> CodeList;
422 private:
423 CodeList Codes, DefaultCodes; // keyboard scancodes of OS plus shift state
424 C4KeyScope Scope; // scope in which key is processed
425 StdStrBuf Name; // custom key name; used for association in config files
426 typedef std::vector<C4KeyboardCallbackInterface *> CBVec;
427 unsigned int uiPriority; // key priority: If multiple keys of same code are defined, high prio overwrites low prio keys
428 bool is_down; // down-callbacks have been executed but up-callbacks have not (not compiled)
429
430 public:
431 CBVec vecCallbacks; // a list of all callbacks assigned to that key
432
433 enum Priority
434 {
435 PRIO_None = 0u,
436 PRIO_Base = 1u,
437 PRIO_Dlg = 2u,
438 PRIO_Ctrl = 3u, // controls have higher priority than dialogs in GUI
439 PRIO_CtrlOverride = 4u, // dialog handlings of keys that overwrite regular control handlings
440 PRIO_FocusCtrl = 5u, // controls override special dialog handling keys (e.g., RenameEdit)
441 PRIO_Context = 6u, // context menus above controls
442 PRIO_PlrControl = 7u, // player controls overwrite any other controls
443 PRIO_MoreThanMax = 100u // must be larger than otherwise largest used priority
444 };
445
446 protected:
447 int iRef;
448 C4CustomKey(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
449 C4CustomKey(CodeList rDefCodes, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key with multiple possible keys assigned
450 friend class C4Game;
451
452 public:
453 C4CustomKey(const C4CustomKey &rCpy, bool fCopyCallbacks);
454 virtual ~C4CustomKey(); // dtor
455
Ref()456 inline void Ref() { ++iRef; }
Deref()457 inline void Deref() { if (!--iRef) delete this; }
458
GetCodes()459 const CodeList &GetCodes() const { return Codes.size() ? Codes : DefaultCodes; } // return assigned codes; default if no custom has been assigned
GetName()460 const StdStrBuf &GetName() const { return Name; }
GetScope()461 C4KeyScope GetScope() const { return Scope; }
GetPriority()462 unsigned int GetPriority() const { return uiPriority; }
463 bool IsCodeMatched(const C4KeyCodeEx &key) const;
464
465 void Update(const C4CustomKey *pByKey); // merge given key into this
466 bool Execute(C4KeyEventType eEv, C4KeyCodeEx key);
467
IsDown()468 bool IsDown() const { return is_down; }
469
470 void KillCallbacks(const C4CustomKey *pOfKey); // remove any callbacks that were created by given key
471
472 void CompileFunc(StdCompiler *pComp);
473 };
474
475 // a key that auto-registers itself into main game keyboard input class and does dereg when deleted
476 class C4KeyBinding : protected C4CustomKey
477 {
478 // Stuffing these into an std::vector ends badly, so I've marked them non-copyable.
479 C4KeyBinding(const C4KeyBinding&) = delete;
480 C4KeyBinding& operator=(const C4KeyBinding&) = delete;
481 public:
482 C4KeyBinding(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
483 C4KeyBinding(const CodeList &rDefCodes, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
484 ~C4KeyBinding() override;
485 };
486
487 // main keyboard mapping class
488 class C4KeyboardInput
489 {
490 private:
491 // comparison fn for map
492 struct szLess
493 {
operatorszLess494 bool operator()(const char *p, const char *q) const { return p && q && (strcmp(p,q)<0); }
495 };
496
497 typedef std::multimap<C4KeyCode, C4CustomKey *> KeyCodeMap;
498 typedef std::map<const char *, C4CustomKey *, szLess> KeyNameMap;
499 // mapping of all keys by code and name
500 KeyCodeMap KeysByCode;
501 KeyNameMap KeysByName;
502 C4KeyEventData LastKeyExtraData;
503
504 public:
505 static bool IsValid; // global var to fix any deinitialization orders of key map and static keys
506
C4KeyboardInput()507 C4KeyboardInput() { IsValid = true; }
~C4KeyboardInput()508 ~C4KeyboardInput() { Clear(); IsValid = false; }
509
510 void Clear(); // empty keyboard maps
511
512 private:
513 // assign keycodes changed for a key: Update codemap
514 void UpdateKeyCodes(C4CustomKey *pKey, const C4CustomKey::CodeList &rOldCodes, const C4CustomKey::CodeList &rNewCodes);
515
516 public:
517 void RegisterKey(C4CustomKey *pRegKey); // register key into code and name maps, or update specific key
518 void UnregisterKey(const StdStrBuf &rsName); // remove key from all maps
519 void UnregisterKeyBinding(C4CustomKey *pKey); // just remove callbacks from a key
520
521 bool DoInput(const C4KeyCodeEx &InKey, C4KeyEventType InEvent, DWORD InScope, int32_t iStrength);
522
523 void CompileFunc(StdCompiler *pComp);
524 bool LoadCustomConfig(); // load keyboard customization file
525
526 C4CustomKey *GetKeyByName(const char *szKeyName);
527 StdStrBuf GetKeyCodeNameByKeyName(const char *szKeyName, bool fShort = false, int32_t iIndex = 0);
GetLastKeyExtraData()528 const C4KeyEventData &GetLastKeyExtraData() const { return LastKeyExtraData; }
SetLastKeyExtraData(const C4KeyEventData & data)529 void SetLastKeyExtraData(const C4KeyEventData &data) { LastKeyExtraData=data; }
530 };
531
532 // keyboardinput-initializer-helper
533 C4KeyboardInput &C4KeyboardInput_Init();
534
535 #endif // INC_C4KeyboardInput
536
537