inputhandler.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #pragma once
  17. #include "irrlichttypes_extrabloated.h"
  18. #include "joystick_controller.h"
  19. #include <list>
  20. #include "keycode.h"
  21. #include "renderingengine.h"
  22. #ifdef HAVE_TOUCHSCREENGUI
  23. #include "gui/touchscreengui.h"
  24. #endif
  25. class InputHandler;
  26. /****************************************************************************
  27. Fast key cache for main game loop
  28. ****************************************************************************/
  29. /* This is faster than using getKeySetting with the tradeoff that functions
  30. * using it must make sure that it's initialised before using it and there is
  31. * no error handling (for example bounds checking). This is really intended for
  32. * use only in the main running loop of the client (the_game()) where the faster
  33. * (up to 10x faster) key lookup is an asset. Other parts of the codebase
  34. * (e.g. formspecs) should continue using getKeySetting().
  35. */
  36. struct KeyCache
  37. {
  38. KeyCache()
  39. {
  40. handler = NULL;
  41. populate();
  42. populate_nonchanging();
  43. }
  44. void populate();
  45. // Keys that are not settings dependent
  46. void populate_nonchanging();
  47. KeyPress key[KeyType::INTERNAL_ENUM_COUNT];
  48. InputHandler *handler;
  49. };
  50. class KeyList : private std::list<KeyPress>
  51. {
  52. typedef std::list<KeyPress> super;
  53. typedef super::iterator iterator;
  54. typedef super::const_iterator const_iterator;
  55. virtual const_iterator find(const KeyPress &key) const
  56. {
  57. const_iterator f(begin());
  58. const_iterator e(end());
  59. while (f != e) {
  60. if (*f == key)
  61. return f;
  62. ++f;
  63. }
  64. return e;
  65. }
  66. virtual iterator find(const KeyPress &key)
  67. {
  68. iterator f(begin());
  69. iterator e(end());
  70. while (f != e) {
  71. if (*f == key)
  72. return f;
  73. ++f;
  74. }
  75. return e;
  76. }
  77. public:
  78. void clear() { super::clear(); }
  79. void set(const KeyPress &key)
  80. {
  81. if (find(key) == end())
  82. push_back(key);
  83. }
  84. void unset(const KeyPress &key)
  85. {
  86. iterator p(find(key));
  87. if (p != end())
  88. erase(p);
  89. }
  90. void toggle(const KeyPress &key)
  91. {
  92. iterator p(this->find(key));
  93. if (p != end())
  94. erase(p);
  95. else
  96. push_back(key);
  97. }
  98. bool operator[](const KeyPress &key) const { return find(key) != end(); }
  99. };
  100. class MyEventReceiver : public IEventReceiver
  101. {
  102. public:
  103. // This is the one method that we have to implement
  104. virtual bool OnEvent(const SEvent &event);
  105. bool IsKeyDown(const KeyPress &keyCode) const { return keyIsDown[keyCode]; }
  106. // Checks whether a key was down and resets the state
  107. bool WasKeyDown(const KeyPress &keyCode)
  108. {
  109. bool b = keyWasDown[keyCode];
  110. if (b)
  111. keyWasDown.unset(keyCode);
  112. return b;
  113. }
  114. // Checks whether a key was just pressed. State will be cleared
  115. // in the subsequent iteration of Game::processPlayerInteraction
  116. bool WasKeyPressed(const KeyPress &keycode) const { return keyWasPressed[keycode]; }
  117. // Checks whether a key was just released. State will be cleared
  118. // in the subsequent iteration of Game::processPlayerInteraction
  119. bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; }
  120. void listenForKey(const KeyPress &keyCode)
  121. {
  122. keysListenedFor.set(keyCode);
  123. }
  124. void dontListenForKeys()
  125. {
  126. keysListenedFor.clear();
  127. }
  128. s32 getMouseWheel()
  129. {
  130. s32 a = mouse_wheel;
  131. mouse_wheel = 0;
  132. return a;
  133. }
  134. void clearInput()
  135. {
  136. keyIsDown.clear();
  137. keyWasDown.clear();
  138. keyWasPressed.clear();
  139. keyWasReleased.clear();
  140. mouse_wheel = 0;
  141. }
  142. void clearWasKeyPressed()
  143. {
  144. keyWasPressed.clear();
  145. }
  146. void clearWasKeyReleased()
  147. {
  148. keyWasReleased.clear();
  149. }
  150. MyEventReceiver()
  151. {
  152. #ifdef HAVE_TOUCHSCREENGUI
  153. m_touchscreengui = NULL;
  154. #endif
  155. }
  156. JoystickController *joystick = nullptr;
  157. #ifdef HAVE_TOUCHSCREENGUI
  158. TouchScreenGUI *m_touchscreengui;
  159. #endif
  160. private:
  161. s32 mouse_wheel = 0;
  162. // The current state of keys
  163. KeyList keyIsDown;
  164. // Like keyIsDown but only reset when that key is read
  165. KeyList keyWasDown;
  166. // Whether a key has just been pressed
  167. KeyList keyWasPressed;
  168. // Whether a key has just been released
  169. KeyList keyWasReleased;
  170. // List of keys we listen for
  171. // TODO perhaps the type of this is not really
  172. // performant as KeyList is designed for few but
  173. // often changing keys, and keysListenedFor is expected
  174. // to change seldomly but contain lots of keys.
  175. KeyList keysListenedFor;
  176. };
  177. class InputHandler
  178. {
  179. public:
  180. InputHandler()
  181. {
  182. keycache.handler = this;
  183. keycache.populate();
  184. }
  185. virtual ~InputHandler() = default;
  186. virtual bool isRandom() const
  187. {
  188. return false;
  189. }
  190. virtual bool isKeyDown(GameKeyType k) = 0;
  191. virtual bool wasKeyDown(GameKeyType k) = 0;
  192. virtual bool wasKeyPressed(GameKeyType k) = 0;
  193. virtual bool wasKeyReleased(GameKeyType k) = 0;
  194. virtual bool cancelPressed() = 0;
  195. virtual float getMovementSpeed() = 0;
  196. virtual float getMovementDirection() = 0;
  197. virtual void clearWasKeyPressed() {}
  198. virtual void clearWasKeyReleased() {}
  199. virtual void listenForKey(const KeyPress &keyCode) {}
  200. virtual void dontListenForKeys() {}
  201. virtual v2s32 getMousePos() = 0;
  202. virtual void setMousePos(s32 x, s32 y) = 0;
  203. virtual s32 getMouseWheel() = 0;
  204. virtual void step(float dtime) {}
  205. virtual void clear() {}
  206. JoystickController joystick;
  207. KeyCache keycache;
  208. };
  209. /*
  210. Separated input handler
  211. */
  212. class RealInputHandler : public InputHandler
  213. {
  214. public:
  215. RealInputHandler(MyEventReceiver *receiver) : m_receiver(receiver)
  216. {
  217. m_receiver->joystick = &joystick;
  218. }
  219. virtual ~RealInputHandler()
  220. {
  221. m_receiver->joystick = nullptr;
  222. }
  223. virtual bool isKeyDown(GameKeyType k)
  224. {
  225. return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
  226. }
  227. virtual bool wasKeyDown(GameKeyType k)
  228. {
  229. return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
  230. }
  231. virtual bool wasKeyPressed(GameKeyType k)
  232. {
  233. return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyPressed(k);
  234. }
  235. virtual bool wasKeyReleased(GameKeyType k)
  236. {
  237. return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
  238. }
  239. virtual float getMovementSpeed()
  240. {
  241. bool f = m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]),
  242. b = m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]),
  243. l = m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]),
  244. r = m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]);
  245. if (f || b || l || r)
  246. {
  247. // if contradictory keys pressed, stay still
  248. if (f && b && l && r)
  249. return 0.0f;
  250. else if (f && b && !l && !r)
  251. return 0.0f;
  252. else if (!f && !b && l && r)
  253. return 0.0f;
  254. return 1.0f; // If there is a keyboard event, assume maximum speed
  255. }
  256. return joystick.getMovementSpeed();
  257. }
  258. virtual float getMovementDirection()
  259. {
  260. float x = 0, z = 0;
  261. /* Check keyboard for input */
  262. if (m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]))
  263. z += 1;
  264. if (m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]))
  265. z -= 1;
  266. if (m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]))
  267. x += 1;
  268. if (m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]))
  269. x -= 1;
  270. if (x != 0 || z != 0) /* If there is a keyboard event, it takes priority */
  271. return atan2(x, z);
  272. else
  273. return joystick.getMovementDirection();
  274. }
  275. virtual bool cancelPressed()
  276. {
  277. return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
  278. }
  279. virtual void clearWasKeyPressed()
  280. {
  281. m_receiver->clearWasKeyPressed();
  282. }
  283. virtual void clearWasKeyReleased()
  284. {
  285. m_receiver->clearWasKeyReleased();
  286. }
  287. virtual void listenForKey(const KeyPress &keyCode)
  288. {
  289. m_receiver->listenForKey(keyCode);
  290. }
  291. virtual void dontListenForKeys()
  292. {
  293. m_receiver->dontListenForKeys();
  294. }
  295. virtual v2s32 getMousePos()
  296. {
  297. auto control = RenderingEngine::get_raw_device()->getCursorControl();
  298. if (control) {
  299. return control->getPosition();
  300. }
  301. return m_mousepos;
  302. }
  303. virtual void setMousePos(s32 x, s32 y)
  304. {
  305. auto control = RenderingEngine::get_raw_device()->getCursorControl();
  306. if (control) {
  307. control->setPosition(x, y);
  308. } else {
  309. m_mousepos = v2s32(x, y);
  310. }
  311. }
  312. virtual s32 getMouseWheel()
  313. {
  314. return m_receiver->getMouseWheel();
  315. }
  316. void clear()
  317. {
  318. joystick.clear();
  319. m_receiver->clearInput();
  320. }
  321. private:
  322. MyEventReceiver *m_receiver = nullptr;
  323. v2s32 m_mousepos;
  324. };
  325. class RandomInputHandler : public InputHandler
  326. {
  327. public:
  328. RandomInputHandler() = default;
  329. bool isRandom() const
  330. {
  331. return true;
  332. }
  333. virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
  334. virtual bool wasKeyDown(GameKeyType k) { return false; }
  335. virtual bool wasKeyPressed(GameKeyType k) { return false; }
  336. virtual bool wasKeyReleased(GameKeyType k) { return false; }
  337. virtual bool cancelPressed() { return false; }
  338. virtual float getMovementSpeed() { return movementSpeed; }
  339. virtual float getMovementDirection() { return movementDirection; }
  340. virtual v2s32 getMousePos() { return mousepos; }
  341. virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
  342. virtual s32 getMouseWheel() { return 0; }
  343. virtual void step(float dtime);
  344. s32 Rand(s32 min, s32 max);
  345. private:
  346. KeyList keydown;
  347. v2s32 mousepos;
  348. v2s32 mousespeed;
  349. float movementSpeed;
  350. float movementDirection;
  351. };