inputhandler.h 10 KB

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