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