452 lines
18 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2015 Benjamin Litzelmann
  5. // © 2017—2018 Sam Hocevar <sam@hocevar.net>
  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. public:
  23. KeyBinding()
  24. : m_current(false),
  25. m_previous(false)
  26. {}
  27. protected:
  28. //Status methods ----------------------------------------------------------
  29. /** Indicates wheither the key is currently down */
  30. bool IsPressed() const { return m_current; }
  31. /** Indicates wheither the key is currently up */
  32. bool IsReleased() const { return !m_current; }
  33. /** Indicates wheither the key has just been pressed */
  34. bool WasPressedThisFrame() const { return m_current && !m_previous; }
  35. /** Indicates wheither the key has just been released */
  36. bool WasReleasedThisFrame() const { return !m_current && m_previous; }
  37. public:
  38. //Binding methods ---------------------------------------------------------
  39. /** Bind a physical device and key */
  40. void Bind(const std::string& device_name, const std::string& key_name);
  41. /** Unbind a previously bound physical device and key. Returns true if the binding was existing. */
  42. bool Unbind(const std::string& device_name, const std::string& key_name);
  43. /* Small helpers */
  44. void BindMouse(const std::string& key_name) { Bind(g_name_mouse, key_name); }
  45. void BindKeyboard(const std::string& key_name) { Bind(g_name_keyboard, key_name); }
  46. void BindJoystick(const uint64_t num, const std::string& key_name) { Bind(g_name_joystick(num), key_name); }
  47. bool UnbindMouse(const std::string& key_name) { return Unbind(g_name_mouse, key_name); }
  48. bool UnbindKeyboard(const std::string& key_name) { return Unbind(g_name_keyboard, key_name); }
  49. bool UnbindJoystick(const uint64_t num, const std::string& key_name) { return Unbind(g_name_joystick(num), key_name); }
  50. /** Clear current binding */
  51. void ClearBindings();
  52. /** Indicate wheither a physical device and key has been bound. Returns the number of bindings set. */
  53. int IsBound() const { return m_keybindings.count(); }
  54. protected:
  55. /** Update the binding value. Called internally by the controller, once per frame */
  56. void Update()
  57. {
  58. m_previous = m_current;
  59. m_current = false;
  60. for (int i = 0; i < m_keybindings.count(); ++i)
  61. {
  62. m_current = m_current || m_keybindings[i].m1->GetKey(m_keybindings[i].m2);
  63. }
  64. }
  65. /** m1 is the InputDevice, m2 is the key index on the InputDevice */
  66. array<const InputDevice*, int> m_keybindings;
  67. /** Value at the previous frame */
  68. bool m_current;
  69. /** Value at the current frame */
  70. bool m_previous;
  71. };
  72. //-----------------------------------------------------------------------------
  73. class AxisBinding
  74. {
  75. friend class Controller;
  76. public:
  77. AxisBinding()
  78. : m_current(0.0f),
  79. m_previous(0.0f)
  80. {}
  81. protected:
  82. //Status methods ----------------------------------------------------------
  83. /** Gets the current absolute value of this axis */
  84. float GetValue() const { return m_current; }
  85. /** Gets the current delta value of this axis */
  86. float GetDelta() const { return m_current - m_previous; }
  87. public:
  88. //Binding methods ---------------------------------------------------------
  89. /** Bind a physical device and axis */
  90. void Bind(const std::string& device_name, const std::string& axis_name);
  91. /** 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 */
  92. void BindKey(const std::string& device_name, const std::string& key_name);
  93. /** 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 */
  94. void BindKeys(const std::string& device_name, const std::string& min_key_name, const std::string& max_key_name);
  95. /** Unbind a previously bound physical device and axis. Returns true if the binding was existing. */
  96. bool Unbind(const std::string& device_name, const std::string& axis_name);
  97. /** Unbind a previously bound physical device and axis. Returns true if the binding was existing. */
  98. bool UnbindKey(const std::string& device_name, const std::string& key_name);
  99. /** Unbind a previously bound physical device and axis. Returns true if the binding was existing. */
  100. bool UnbindKeys(const std::string& device_name, const std::string& min_key_name, const std::string& max_key_name);
  101. /* Small helpers */
  102. void BindMouse(const std::string& axis_name) { Bind(g_name_mouse, axis_name); }
  103. void BindMouseKey(const std::string& key_name) { BindKey(g_name_mouse, key_name); }
  104. void BindMouseKeys(const std::string& min_key_name, const std::string& max_key_name) { BindKeys(g_name_mouse, min_key_name, max_key_name); }
  105. bool UnbindMouse(const std::string& axis_name) { return Unbind(g_name_mouse, axis_name); }
  106. bool UnbindMouseKey(const std::string& key_name) { return UnbindKey(g_name_mouse, key_name); }
  107. bool UnbindMouseKeys(const std::string& min_key_name, const std::string& max_key_name){ return UnbindKeys(g_name_mouse, min_key_name, max_key_name); }
  108. /* */
  109. void BindJoystick(const uint64_t num, const std::string& axis_name) { Bind(g_name_joystick(num), axis_name); }
  110. void BindJoystickKey(const uint64_t num, const std::string& key_name) { BindKey(g_name_joystick(num), key_name); }
  111. void BindJoystickKeys(const uint64_t num, const std::string& min_key_name, const std::string& max_key_name) { BindKeys(g_name_joystick(num), min_key_name, max_key_name); }
  112. bool UnbindJoystick(const uint64_t num, const std::string& axis_name) { return Unbind(g_name_joystick(num), axis_name); }
  113. bool UnbindJoystickKey(const uint64_t num, const std::string& key_name) { return UnbindKey(g_name_joystick(num), key_name); }
  114. bool UnbindJoystickKeys(const uint64_t num, const std::string& min_key_name, const std::string& max_key_name){ return UnbindKeys(g_name_joystick(num), min_key_name, max_key_name); }
  115. /** Clear current binding */
  116. void ClearBindings();
  117. /** Indicate wheither a physical device and axis has been bound. Returns the number of bindings set. */
  118. int IsBound() const { return m_axisbindings.count() + m_keybindings.count(); }
  119. protected:
  120. void Update()
  121. {
  122. m_previous = m_current;
  123. m_current = IsBound() ? RetrieveCurrentValue() : 0.0f;
  124. }
  125. float RetrieveCurrentValue();
  126. /** m1 is the InputDevice, m2 is the axis index on the InputDevice, m3 and m4 are an optional key indices to bind one or two keys over the axis */
  127. array<const InputDevice*, int> m_axisbindings;
  128. /** 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. */
  129. array<const InputDevice*, int, int> m_keybindings;
  130. float m_current;
  131. float m_previous;
  132. };
  133. //-------------------------------------------------------------------------
  134. class InputProfile
  135. {
  136. friend class Controller;
  137. private:
  138. //---------------------------------------------------------------------
  139. class Key
  140. {
  141. friend class Controller;
  142. friend class InputProfile;
  143. public:
  144. Key() { }
  145. Key(int idx, std::string const& name) : m_idx(idx), m_name(name) { }
  146. Key(const Key& other) : m_idx(other.m_idx), m_name(other.m_name) { }
  147. ~Key() { }
  148. bool operator==(const Key& other) { return m_name == other.m_name; }
  149. private:
  150. int m_idx = 0;
  151. std::string m_name;
  152. };
  153. //---------------------------------------------------------------------
  154. class Joystick
  155. {
  156. friend class Controller;
  157. friend class InputProfile;
  158. public:
  159. Joystick() { }
  160. Joystick(uint64_t joy, int idx, std::string const& name) : m_joy(joy), m_idx(idx), m_name(name) { }
  161. Joystick(const Joystick& other) : m_joy(other.m_joy), m_idx(other.m_idx), m_name(other.m_name) { }
  162. ~Joystick() { }
  163. bool operator==(const Joystick& other) { return m_name == other.m_name; }
  164. private:
  165. uint64_t m_joy = 0;
  166. int m_idx = 0;
  167. std::string m_name;
  168. };
  169. public:
  170. //---------------------------------------------------------------------
  171. class Keyboard : public Key
  172. {
  173. friend class Controller;
  174. friend class InputProfile;
  175. public:
  176. Keyboard() : Key() { }
  177. Keyboard(int idx, std::string const& name) : Key(idx, name) { }
  178. Keyboard(const Keyboard& other) : Key(other.m_idx, other.m_name) { }
  179. };
  180. //---------------------------------------------------------------------
  181. class MouseKey : public Key
  182. {
  183. friend class Controller;
  184. friend class InputProfile;
  185. public:
  186. MouseKey() : Key() { }
  187. MouseKey(int idx, std::string const& name) : Key(idx, name) { }
  188. MouseKey(const Keyboard& other) : Key(other.m_idx, other.m_name) { }
  189. };
  190. //---------------------------------------------------------------------
  191. class MouseAxis : public Key
  192. {
  193. friend class Controller;
  194. friend class InputProfile;
  195. public:
  196. MouseAxis() : Key() { }
  197. MouseAxis(int idx, std::string const& name) : Key(idx, name) { }
  198. MouseAxis(const Keyboard& other) : Key(other.m_idx, other.m_name) { }
  199. };
  200. //---------------------------------------------------------------------
  201. class JoystickKey : public Joystick
  202. {
  203. friend class Controller;
  204. friend class InputProfile;
  205. public:
  206. JoystickKey() : Joystick() { }
  207. JoystickKey(uint64_t joy, int idx, std::string const& name) : Joystick(joy, idx, name) { }
  208. JoystickKey(const JoystickKey& other) : Joystick(other.m_joy, other.m_idx, other.m_name) { }
  209. };
  210. //---------------------------------------------------------------------
  211. class JoystickAxis : public Joystick
  212. {
  213. friend class Controller;
  214. friend class InputProfile;
  215. public:
  216. JoystickAxis() : Joystick() { }
  217. JoystickAxis(uint64_t joy, int idx, std::string const& name) : Joystick(joy, idx, name) { }
  218. JoystickAxis(const JoystickAxis& other) : Joystick(other.m_joy, other.m_idx, other.m_name) { }
  219. };
  220. public:
  221. InputProfile() { }
  222. InputProfile(const InputProfile& other)
  223. {
  224. m_keys = other.m_keys;
  225. m_mouse_keys = other.m_mouse_keys;
  226. m_mouse_axis = other.m_mouse_axis;
  227. m_joystick = other.m_joystick;
  228. m_joystick_keys = other.m_joystick_keys;
  229. m_joystick_axis = other.m_joystick_axis;
  230. }
  231. virtual ~InputProfile() { }
  232. bool IsEmpty() const
  233. {
  234. return !GetKeyCount() && !GetAxisCount();
  235. }
  236. int GetKeyCount() const
  237. {
  238. return m_keys.count() + m_mouse_keys.count() + m_joystick_keys.count();
  239. }
  240. int GetAxisCount() const
  241. {
  242. return m_mouse_axis.count() + m_joystick_axis.count();
  243. }
  244. //Keys --------------------------------------------------------------------
  245. InputProfile& operator<<(InputProfile::Keyboard const& binding)
  246. {
  247. m_keys.push_unique(binding);
  248. return *this;
  249. }
  250. InputProfile& operator<<(array<InputProfile::Keyboard> const& bindings)
  251. {
  252. m_keys += bindings;
  253. return *this;
  254. }
  255. //------
  256. InputProfile& operator<<(InputProfile::MouseKey const& binding)
  257. {
  258. m_mouse_keys.push_unique(binding);
  259. return *this;
  260. }
  261. InputProfile& operator<<(array<InputProfile::MouseKey> const& bindings)
  262. {
  263. m_mouse_keys += bindings;
  264. return *this;
  265. }
  266. //------
  267. InputProfile& operator<<(InputProfile::JoystickKey const& binding)
  268. {
  269. m_joystick.push_unique(binding.m_joy);
  270. m_joystick_keys.push_unique(binding);
  271. return *this;
  272. }
  273. InputProfile& operator<<(array<InputProfile::JoystickKey> const& bindings)
  274. {
  275. for (InputProfile::JoystickKey const& binding : bindings)
  276. m_joystick.push_unique(binding.m_joy);
  277. m_joystick_keys += bindings;
  278. return *this;
  279. }
  280. //Axis --------------------------------------------------------------------
  281. InputProfile& operator<<(InputProfile::MouseAxis const& binding)
  282. {
  283. m_mouse_axis.push_unique(binding);
  284. return *this;
  285. }
  286. InputProfile& operator<<(array<InputProfile::MouseAxis> const& bindings)
  287. {
  288. m_mouse_axis += bindings;
  289. return *this;
  290. }
  291. //------
  292. InputProfile& operator<<(InputProfile::JoystickAxis const& binding)
  293. {
  294. m_joystick.push_unique(binding.m_joy);
  295. m_joystick_axis.push_unique(binding);
  296. return *this;
  297. }
  298. InputProfile& operator<<(array<InputProfile::JoystickAxis> const& bindings)
  299. {
  300. for (InputProfile::JoystickAxis const& binding : bindings)
  301. m_joystick.push_unique(binding.m_joy);
  302. m_joystick_axis += bindings;
  303. return *this;
  304. }
  305. //BindingType -------------------------------------------------------------
  306. struct InputTypeBase : public StructSafeEnum
  307. {
  308. enum Type
  309. {
  310. Keyboard = 0,
  311. MouseKey,
  312. JoystickKey,
  313. MouseAxis,
  314. JoystickAxis,
  315. MAX,
  316. };
  317. protected:
  318. virtual bool BuildEnumMap(std::map<int64_t, std::string>& enum_map) { UNUSED(enum_map); return true; }
  319. };
  320. typedef SafeEnum<InputTypeBase> InputType;
  321. //Template helper ---------------------------------------------------------
  322. template <typename T, int N_BEGIN, int N_END>
  323. void AddBindings(InputType const& type, uint64_t joy = 0)
  324. {
  325. for (int i = N_BEGIN; i < N_END; ++i)
  326. {
  327. switch (type.ToScalar())
  328. {
  329. case InputType::Keyboard:/******/*this << InputProfile::Keyboard/******/(/***/i, T(i).tostring()); break;
  330. case InputType::MouseKey:/******/*this << InputProfile::MouseKey/******/(/***/i, T(i).tostring()); break;
  331. case InputType::JoystickKey:/***/*this << InputProfile::JoystickKey/***/(joy, i, T(i).tostring()); break;
  332. case InputType::MouseAxis:/*****/*this << InputProfile::MouseAxis/*****/(/***/i, T(i).tostring()); break;
  333. case InputType::JoystickAxis:/**/*this << InputProfile::JoystickAxis/**/(joy, i, T(i).tostring()); break;
  334. default: break;
  335. }
  336. }
  337. }
  338. private:
  339. array<Keyboard> m_keys;
  340. array<MouseKey> m_mouse_keys;
  341. array<MouseAxis> m_mouse_axis;
  342. array<uint64_t> m_joystick;
  343. array<JoystickKey> m_joystick_keys;
  344. array<JoystickAxis> m_joystick_axis;
  345. };
  346. typedef InputProfile::InputType InputProfileType;
  347. //-----------------------------------------------------------------------------
  348. //TODO: Add mask|layer system to prevent several controllers from interfering with another. (input overlay in menus)
  349. class Controller : public Entity
  350. {
  351. public:
  352. Controller(std::string const &name);
  353. Controller(std::string const &name, InputProfile const& setup);
  354. virtual ~Controller();
  355. virtual void TickGame(float seconds);
  356. /** Activate the controller on next frame */
  357. void Activate();
  358. /** Deactivate the controller on next frame */
  359. void Deactivate();
  360. /** Deactivate every active controller on next frame and return an array of deactivated (previously active) controllers */
  361. static array<Controller*> DeactivateAll();
  362. /** Init mode 1: Input profile system */
  363. void Init(InputProfile const& profile);
  364. void ClearProfile();
  365. /** Init mode 2: By hand, key/axis by key/axis */
  366. void SetInputCount(int nb_keys, int nb_axis);
  367. /** layer mask stuff */
  368. void SetLayerMask(uint32_t layer_mask);
  369. uint32_t GetLayerMask();
  370. protected:
  371. bool IsLayerActive();
  372. public:
  373. /** GetKeys/Axis stuff */
  374. KeyBinding& GetKey(int index);
  375. KeyBinding const& GetKey(int index) const;
  376. AxisBinding& GetAxis(int index);
  377. AxisBinding const& GetAxis(int index) const;
  378. /** Key methods: should not go directly to binding */
  379. /** Indicates wheither the key is currently down */
  380. bool IsKeyPressed(int index) const;
  381. /** Indicates wheither the key is currently up */
  382. bool IsKeyReleased(int index) const;
  383. /** Indicates wheither the key has just been pressed */
  384. bool WasKeyPressedThisFrame(int index) const;
  385. /** Indicates wheither the key has just been released */
  386. bool WasKeyReleasedThisFrame(int index) const;
  387. /** Axis methods: should not go directly to binding */
  388. /** Gets the current absolute value of this axis */
  389. float GetAxisValue(int index) const;
  390. /** Gets the current delta value of this axis */
  391. float GetAxisDelta(int index) const;
  392. /** Get named controller */
  393. static Controller* Get(std::string const &name);
  394. protected:
  395. /** Input profile system */
  396. void UnbindProfile();
  397. void BindProfile(InputProfile const& setup);
  398. private:
  399. uint32_t m_layer_mask = 1; //plugged on the first by default
  400. array<KeyBinding> m_keys;
  401. array<AxisBinding> m_axis;
  402. static uint32_t m_active_layer; //All active by default
  403. static array<Controller*> controllers;
  404. std::string m_name;
  405. bool m_activate_nextframe;
  406. bool m_deactivate_nextframe;
  407. bool m_active;
  408. //Input profile stuff
  409. mutex m_mutex;
  410. class InputProfile m_profile;
  411. class InputDevice* m_keyboard = nullptr;
  412. class InputDevice* m_mouse = nullptr;
  413. array<class InputDevice*> m_joystick;
  414. array<uint64_t> m_joystick_idx;
  415. };
  416. } /* namespace lol */