367 lines
13 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2017—2019 Sam Hocevar <sam@hocevar.net>
  5. // © 2010—2015 Benjamin Litzelmann
  6. //
  7. // Lol Engine is free software. It comes without any warranty, to
  8. // the extent permitted by applicable law. You can redistribute it
  9. // and/or modify it under the terms of the Do What the Fuck You Want
  10. // to Public License, Version 2, as published by the WTFPL Task Force.
  11. // See http://www.wtfpl.net/ for more details.
  12. //
  13. #pragma once
  14. #include <string>
  15. #include <map>
  16. namespace lol
  17. {
  18. //-----------------------------------------------------------------------------
  19. class KeyBinding
  20. {
  21. friend class Controller;
  22. protected:
  23. //Status methods ----------------------------------------------------------
  24. /** Indicates wheither the key is currently down */
  25. bool IsPressed() const { return m_current; }
  26. /** Indicates wheither the key is currently up */
  27. bool IsReleased() const { return !m_current; }
  28. /** Indicates wheither the key has just been pressed */
  29. bool WasPressedThisFrame() const { return m_current && !m_previous; }
  30. /** Indicates wheither the key has just been released */
  31. bool WasReleasedThisFrame() const { return !m_current && m_previous; }
  32. public:
  33. //Binding methods ---------------------------------------------------------
  34. /** Bind a physical device and key */
  35. void Bind(const std::string& device_name, const std::string& key_name);
  36. /** Unbind a previously bound physical device and key. Returns true if the binding was existing. */
  37. bool Unbind(const std::string& device_name, const std::string& key_name);
  38. /* Small helpers */
  39. void BindMouse(const std::string& key_name) { Bind(g_name_mouse, key_name); }
  40. void BindKeyboard(const std::string& key_name) { Bind(g_name_keyboard, key_name); }
  41. void BindJoystick(const uint64_t num, const std::string& key_name) { Bind(g_name_joystick(num), key_name); }
  42. bool UnbindMouse(const std::string& key_name) { return Unbind(g_name_mouse, key_name); }
  43. bool UnbindKeyboard(const std::string& key_name) { return Unbind(g_name_keyboard, key_name); }
  44. bool UnbindJoystick(const uint64_t num, const std::string& key_name) { return Unbind(g_name_joystick(num), key_name); }
  45. protected:
  46. /** Update the binding value. Called internally by the controller, once per frame */
  47. void Update()
  48. {
  49. m_previous = m_current;
  50. m_current = false;
  51. for (int i = 0; i < m_keybindings.count(); ++i)
  52. m_current = m_current || m_keybindings[i].m1->key((input::key)m_keybindings[i].m2);
  53. }
  54. /** m1 is the InputDevice, m2 is the key index on the InputDevice */
  55. array<const InputDevice*, int> m_keybindings;
  56. /** Value at the previous frame */
  57. bool m_current = false;
  58. /** Value at the current frame */
  59. bool m_previous = false;
  60. };
  61. //-----------------------------------------------------------------------------
  62. class AxisBinding
  63. {
  64. friend class Controller;
  65. protected:
  66. //Status methods ----------------------------------------------------------
  67. /** Gets the current absolute value of this axis */
  68. float GetValue() const { return m_current; }
  69. /** Gets the current delta value of this axis */
  70. float GetDelta() const { return m_current - m_previous; }
  71. public:
  72. //Binding methods ---------------------------------------------------------
  73. /** Bind a physical device and axis */
  74. void Bind(const std::string& device_name, const std::string& axis_name);
  75. /** Bind a physical device and key over this axis. The axis value will be 0 if the key is up and 1 if it's down */
  76. void BindKey(const std::string& device_name, const std::string& key_name);
  77. /** Bind physical device and keys over this axis. The axis value will be 0 if both the key are up, -1 if minkey is down, and 1 if maxkey is down */
  78. void BindKeys(const std::string& device_name, const std::string& min_key_name, const std::string& max_key_name);
  79. /** Unbind a previously bound physical device and axis. Returns true if the binding was existing. */
  80. bool Unbind(const std::string& device_name, const std::string& axis_name);
  81. /** Unbind a previously bound physical device and axis. Returns true if the binding was existing. */
  82. bool UnbindKey(const std::string& device_name, const std::string& key_name);
  83. /** Unbind a previously bound physical device and axis. Returns true if the binding was existing. */
  84. bool UnbindKeys(const std::string& device_name, const std::string& min_key_name, const std::string& max_key_name);
  85. /* Small helpers */
  86. void BindMouse(const std::string& axis_name) { Bind(g_name_mouse, axis_name); }
  87. bool UnbindMouse(const std::string& axis_name) { return Unbind(g_name_mouse, axis_name); }
  88. /* */
  89. void BindJoystick(const uint64_t num, const std::string& axis_name) { Bind(g_name_joystick(num), axis_name); }
  90. bool UnbindJoystick(const uint64_t num, const std::string& axis_name) { return Unbind(g_name_joystick(num), axis_name); }
  91. protected:
  92. void Update()
  93. {
  94. m_previous = m_current;
  95. m_current = RetrieveCurrentValue();
  96. }
  97. float RetrieveCurrentValue();
  98. /** m1 is the InputDevice, m2 is the axis index on the InputDevice */
  99. array<const InputDevice*, int> m_axisbindings;
  100. /** m1 is the InputDevice, m2 is the key index on the InputDevice for the negative value, m3 is the key index on the InputDevice for the positive value. Only one key is required to bind key over axis. */
  101. array<const InputDevice*, int, int> m_keybindings;
  102. float m_current = 0.0f;
  103. float m_previous = 0.0f;
  104. };
  105. //-------------------------------------------------------------------------
  106. class InputProfile
  107. {
  108. friend class Controller;
  109. private:
  110. class Key
  111. {
  112. friend class Controller;
  113. friend class InputProfile;
  114. public:
  115. Key() { }
  116. Key(int idx, std::string const& name) : m_idx(idx), m_name(name) { }
  117. Key(const Key& other) : m_idx(other.m_idx), m_name(other.m_name) { }
  118. ~Key() { }
  119. bool operator==(const Key& other) { return m_name == other.m_name; }
  120. private:
  121. int m_idx = 0;
  122. std::string m_name;
  123. };
  124. class Joystick
  125. {
  126. friend class Controller;
  127. friend class InputProfile;
  128. public:
  129. Joystick() { }
  130. Joystick(uint64_t joy, int idx, std::string const& name) : m_joy(joy), m_idx(idx), m_name(name) { }
  131. Joystick(const Joystick& other) : m_joy(other.m_joy), m_idx(other.m_idx), m_name(other.m_name) { }
  132. ~Joystick() { }
  133. bool operator==(const Joystick& other) { return m_name == other.m_name; }
  134. private:
  135. uint64_t m_joy = 0;
  136. int m_idx = 0;
  137. std::string m_name;
  138. };
  139. public:
  140. class KeyboardKey : public Key
  141. {
  142. friend class Controller;
  143. friend class InputProfile;
  144. public:
  145. KeyboardKey(int idx, std::string const& name) : Key(idx, name) { }
  146. };
  147. class MouseKey : public Key
  148. {
  149. friend class Controller;
  150. friend class InputProfile;
  151. public:
  152. MouseKey(int idx, std::string const& name) : Key(idx, name) { }
  153. };
  154. class MouseAxis : public Key
  155. {
  156. friend class Controller;
  157. friend class InputProfile;
  158. public:
  159. MouseAxis(int idx, std::string const& name) : Key(idx, name) { }
  160. };
  161. class JoystickKey : public Joystick
  162. {
  163. friend class Controller;
  164. friend class InputProfile;
  165. public:
  166. JoystickKey(uint64_t joy, int idx, std::string const& name) : Joystick(joy, idx, name) { }
  167. };
  168. class JoystickAxis : public Joystick
  169. {
  170. friend class Controller;
  171. friend class InputProfile;
  172. public:
  173. JoystickAxis(uint64_t joy, int idx, std::string const& name) : Joystick(joy, idx, name) { }
  174. };
  175. public:
  176. InputProfile() = default;
  177. virtual ~InputProfile() = default;
  178. bool IsEmpty() const
  179. {
  180. return !GetKeyCount() && !GetAxisCount();
  181. }
  182. int GetKeyCount() const
  183. {
  184. return m_keys.count() + m_mouse_keys.count() + m_joystick_keys.count();
  185. }
  186. int GetAxisCount() const
  187. {
  188. return m_mouse_axis.count() + m_joystick_axis.count();
  189. }
  190. //Keys --------------------------------------------------------------------
  191. InputProfile& operator<<(InputProfile::KeyboardKey const& binding)
  192. {
  193. m_keys.push_unique(binding);
  194. return *this;
  195. }
  196. InputProfile& operator<<(array<InputProfile::KeyboardKey> const& bindings)
  197. {
  198. m_keys += bindings;
  199. return *this;
  200. }
  201. //------
  202. InputProfile& operator<<(InputProfile::MouseKey const& binding)
  203. {
  204. m_mouse_keys.push_unique(binding);
  205. return *this;
  206. }
  207. InputProfile& operator<<(array<InputProfile::MouseKey> const& bindings)
  208. {
  209. m_mouse_keys += bindings;
  210. return *this;
  211. }
  212. //------
  213. InputProfile& operator<<(InputProfile::JoystickKey const& binding)
  214. {
  215. m_joystick.push_unique(binding.m_joy);
  216. m_joystick_keys.push_unique(binding);
  217. return *this;
  218. }
  219. InputProfile& operator<<(array<InputProfile::JoystickKey> const& bindings)
  220. {
  221. for (InputProfile::JoystickKey const& binding : bindings)
  222. m_joystick.push_unique(binding.m_joy);
  223. m_joystick_keys += bindings;
  224. return *this;
  225. }
  226. //Axis --------------------------------------------------------------------
  227. InputProfile& operator<<(InputProfile::MouseAxis const& binding)
  228. {
  229. m_mouse_axis.push_unique(binding);
  230. return *this;
  231. }
  232. InputProfile& operator<<(array<InputProfile::MouseAxis> const& bindings)
  233. {
  234. m_mouse_axis += bindings;
  235. return *this;
  236. }
  237. //------
  238. InputProfile& operator<<(InputProfile::JoystickAxis const& binding)
  239. {
  240. m_joystick.push_unique(binding.m_joy);
  241. m_joystick_axis.push_unique(binding);
  242. return *this;
  243. }
  244. InputProfile& operator<<(array<InputProfile::JoystickAxis> const& bindings)
  245. {
  246. for (InputProfile::JoystickAxis const& binding : bindings)
  247. m_joystick.push_unique(binding.m_joy);
  248. m_joystick_axis += bindings;
  249. return *this;
  250. }
  251. void register_default_keys()
  252. {
  253. #define _SC(id, str, name) *this << InputProfile::KeyboardKey(id, #name);
  254. #include "ui/keys.inc"
  255. }
  256. private:
  257. array<KeyboardKey> m_keys;
  258. array<MouseKey> m_mouse_keys;
  259. array<MouseAxis> m_mouse_axis;
  260. array<uint64_t> m_joystick;
  261. array<JoystickKey> m_joystick_keys;
  262. array<JoystickAxis> m_joystick_axis;
  263. };
  264. //-----------------------------------------------------------------------------
  265. //TODO: Add mask|layer system to prevent several controllers from interfering with another. (input overlay in menus)
  266. class Controller : public Entity
  267. {
  268. public:
  269. Controller(std::string const &name);
  270. Controller(std::string const &name, InputProfile const& setup);
  271. virtual ~Controller();
  272. virtual void tick_game(float seconds);
  273. /** Activate the controller on next frame */
  274. void Activate();
  275. /** Deactivate the controller on next frame */
  276. void Deactivate();
  277. /** Deactivate every active controller on next frame and return an array of deactivated (previously active) controllers */
  278. static array<Controller*> DeactivateAll();
  279. /** Init mode 1: Input profile system */
  280. void Init(InputProfile const& profile);
  281. void ClearProfile();
  282. /** layer mask stuff */
  283. void SetLayerMask(uint32_t layer_mask);
  284. uint32_t GetLayerMask();
  285. protected:
  286. bool IsLayerActive();
  287. public:
  288. /** GetKeys/Axis stuff */
  289. KeyBinding& GetKey(int index);
  290. KeyBinding const& GetKey(int index) const;
  291. AxisBinding& GetAxis(int index);
  292. AxisBinding const& GetAxis(int index) const;
  293. /** Key methods: should not go directly to binding */
  294. /** Indicates wheither the key is currently down */
  295. bool IsKeyPressed(int index) const;
  296. /** Indicates wheither the key is currently up */
  297. bool IsKeyReleased(int index) const;
  298. /** Indicates wheither the key has just been pressed */
  299. bool WasKeyPressedThisFrame(int index) const;
  300. /** Indicates wheither the key has just been released */
  301. bool WasKeyReleasedThisFrame(int index) const;
  302. /** Axis methods: should not go directly to binding */
  303. /** Gets the current absolute value of this axis */
  304. float GetAxisValue(int index) const;
  305. /** Gets the current delta value of this axis */
  306. float GetAxisDelta(int index) const;
  307. protected:
  308. /** Input profile system */
  309. void UnbindProfile();
  310. void BindProfile(InputProfile const& setup);
  311. private:
  312. uint32_t m_layer_mask = 1; // plugged on the first by default
  313. std::map<int, KeyBinding> m_key_bindings;
  314. std::map<int, AxisBinding> m_axis_bindings;
  315. std::string m_name;
  316. bool m_activate_nextframe;
  317. bool m_deactivate_nextframe;
  318. bool m_active;
  319. //Input profile stuff
  320. mutex m_mutex;
  321. class InputProfile m_profile;
  322. std::shared_ptr<InputDevice> m_keyboard;
  323. std::shared_ptr<InputDevice> m_mouse;
  324. array<class InputDevice*> m_joysticks;
  325. array<uint64_t> m_joystick_idx;
  326. };
  327. } /* namespace lol */