123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- /*
- Minetest
- Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #pragma once
- #include "irrlichttypes_extrabloated.h"
- #include "joystick_controller.h"
- #include <list>
- #include "keycode.h"
- #include "renderingengine.h"
- #include "gui/touchscreengui.h"
- class InputHandler;
- /****************************************************************************
- Fast key cache for main game loop
- ****************************************************************************/
- /* This is faster than using getKeySetting with the tradeoff that functions
- * using it must make sure that it's initialised before using it and there is
- * no error handling (for example bounds checking). This is really intended for
- * use only in the main running loop of the client (the_game()) where the faster
- * (up to 10x faster) key lookup is an asset. Other parts of the codebase
- * (e.g. formspecs) should continue using getKeySetting().
- */
- struct KeyCache
- {
- KeyCache()
- {
- handler = NULL;
- populate();
- populate_nonchanging();
- }
- void populate();
- // Keys that are not settings dependent
- void populate_nonchanging();
- KeyPress key[KeyType::INTERNAL_ENUM_COUNT];
- InputHandler *handler;
- };
- class KeyList : private std::list<KeyPress>
- {
- typedef std::list<KeyPress> super;
- typedef super::iterator iterator;
- typedef super::const_iterator const_iterator;
- virtual const_iterator find(const KeyPress &key) const
- {
- const_iterator f(begin());
- const_iterator e(end());
- while (f != e) {
- if (*f == key)
- return f;
- ++f;
- }
- return e;
- }
- virtual iterator find(const KeyPress &key)
- {
- iterator f(begin());
- iterator e(end());
- while (f != e) {
- if (*f == key)
- return f;
- ++f;
- }
- return e;
- }
- public:
- void clear() { super::clear(); }
- void set(const KeyPress &key)
- {
- if (find(key) == end())
- push_back(key);
- }
- void unset(const KeyPress &key)
- {
- iterator p(find(key));
- if (p != end())
- erase(p);
- }
- void toggle(const KeyPress &key)
- {
- iterator p(this->find(key));
- if (p != end())
- erase(p);
- else
- push_back(key);
- }
- void append(const KeyList &other)
- {
- for (const KeyPress &key : other) {
- set(key);
- }
- }
- bool operator[](const KeyPress &key) const { return find(key) != end(); }
- };
- class MyEventReceiver : public IEventReceiver
- {
- public:
- // This is the one method that we have to implement
- virtual bool OnEvent(const SEvent &event);
- bool IsKeyDown(const KeyPress &keyCode) const { return keyIsDown[keyCode]; }
- // Checks whether a key was down and resets the state
- bool WasKeyDown(const KeyPress &keyCode)
- {
- bool b = keyWasDown[keyCode];
- if (b)
- keyWasDown.unset(keyCode);
- return b;
- }
- // Checks whether a key was just pressed. State will be cleared
- // in the subsequent iteration of Game::processPlayerInteraction
- bool WasKeyPressed(const KeyPress &keycode) const { return keyWasPressed[keycode]; }
- // Checks whether a key was just released. State will be cleared
- // in the subsequent iteration of Game::processPlayerInteraction
- bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; }
- void listenForKey(const KeyPress &keyCode)
- {
- keysListenedFor.set(keyCode);
- }
- void dontListenForKeys()
- {
- keysListenedFor.clear();
- }
- s32 getMouseWheel()
- {
- s32 a = mouse_wheel;
- mouse_wheel = 0;
- return a;
- }
- void clearInput()
- {
- keyIsDown.clear();
- keyWasDown.clear();
- keyWasPressed.clear();
- keyWasReleased.clear();
- mouse_wheel = 0;
- }
- void releaseAllKeys()
- {
- keyWasReleased.append(keyIsDown);
- keyIsDown.clear();
- }
- void clearWasKeyPressed()
- {
- keyWasPressed.clear();
- }
- void clearWasKeyReleased()
- {
- keyWasReleased.clear();
- }
- MyEventReceiver()
- {
- m_touchscreengui = NULL;
- }
- JoystickController *joystick = nullptr;
- TouchScreenGUI *m_touchscreengui;
- private:
- s32 mouse_wheel = 0;
- // The current state of keys
- KeyList keyIsDown;
- // Like keyIsDown but only reset when that key is read
- KeyList keyWasDown;
- // Whether a key has just been pressed
- KeyList keyWasPressed;
- // Whether a key has just been released
- KeyList keyWasReleased;
- // List of keys we listen for
- // TODO perhaps the type of this is not really
- // performant as KeyList is designed for few but
- // often changing keys, and keysListenedFor is expected
- // to change seldomly but contain lots of keys.
- KeyList keysListenedFor;
- };
- class InputHandler
- {
- public:
- InputHandler()
- {
- keycache.handler = this;
- keycache.populate();
- }
- virtual ~InputHandler() = default;
- virtual bool isRandom() const
- {
- return false;
- }
- virtual bool isKeyDown(GameKeyType k) = 0;
- virtual bool wasKeyDown(GameKeyType k) = 0;
- virtual bool wasKeyPressed(GameKeyType k) = 0;
- virtual bool wasKeyReleased(GameKeyType k) = 0;
- virtual bool cancelPressed() = 0;
- virtual float getMovementSpeed() = 0;
- virtual float getMovementDirection() = 0;
- virtual void clearWasKeyPressed() {}
- virtual void clearWasKeyReleased() {}
- virtual void listenForKey(const KeyPress &keyCode) {}
- virtual void dontListenForKeys() {}
- virtual v2s32 getMousePos() = 0;
- virtual void setMousePos(s32 x, s32 y) = 0;
- virtual s32 getMouseWheel() = 0;
- virtual void step(float dtime) {}
- virtual void clear() {}
- virtual void releaseAllKeys() {}
- JoystickController joystick;
- KeyCache keycache;
- };
- /*
- Separated input handler
- */
- class RealInputHandler : public InputHandler
- {
- public:
- RealInputHandler(MyEventReceiver *receiver) : m_receiver(receiver)
- {
- m_receiver->joystick = &joystick;
- }
- virtual ~RealInputHandler()
- {
- m_receiver->joystick = nullptr;
- }
- virtual bool isKeyDown(GameKeyType k)
- {
- return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
- }
- virtual bool wasKeyDown(GameKeyType k)
- {
- return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
- }
- virtual bool wasKeyPressed(GameKeyType k)
- {
- return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyPressed(k);
- }
- virtual bool wasKeyReleased(GameKeyType k)
- {
- return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
- }
- virtual float getMovementSpeed()
- {
- bool f = m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]),
- b = m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]),
- l = m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]),
- r = m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]);
- if (f || b || l || r)
- {
- // if contradictory keys pressed, stay still
- if (f && b && l && r)
- return 0.0f;
- else if (f && b && !l && !r)
- return 0.0f;
- else if (!f && !b && l && r)
- return 0.0f;
- return 1.0f; // If there is a keyboard event, assume maximum speed
- }
- if (m_receiver->m_touchscreengui && m_receiver->m_touchscreengui->getMovementSpeed())
- return m_receiver->m_touchscreengui->getMovementSpeed();
- return joystick.getMovementSpeed();
- }
- virtual float getMovementDirection()
- {
- float x = 0, z = 0;
- /* Check keyboard for input */
- if (m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]))
- z += 1;
- if (m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]))
- z -= 1;
- if (m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]))
- x += 1;
- if (m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]))
- x -= 1;
- if (x != 0 || z != 0) /* If there is a keyboard event, it takes priority */
- return atan2(x, z);
- else if (m_receiver->m_touchscreengui && m_receiver->m_touchscreengui->getMovementDirection())
- return m_receiver->m_touchscreengui->getMovementDirection();
- return joystick.getMovementDirection();
- }
- virtual bool cancelPressed()
- {
- return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
- }
- virtual void clearWasKeyPressed()
- {
- m_receiver->clearWasKeyPressed();
- }
- virtual void clearWasKeyReleased()
- {
- m_receiver->clearWasKeyReleased();
- }
- virtual void listenForKey(const KeyPress &keyCode)
- {
- m_receiver->listenForKey(keyCode);
- }
- virtual void dontListenForKeys()
- {
- m_receiver->dontListenForKeys();
- }
- virtual v2s32 getMousePos()
- {
- auto control = RenderingEngine::get_raw_device()->getCursorControl();
- if (control) {
- return control->getPosition();
- }
- return m_mousepos;
- }
- virtual void setMousePos(s32 x, s32 y)
- {
- auto control = RenderingEngine::get_raw_device()->getCursorControl();
- if (control) {
- control->setPosition(x, y);
- } else {
- m_mousepos = v2s32(x, y);
- }
- }
- virtual s32 getMouseWheel()
- {
- return m_receiver->getMouseWheel();
- }
- void clear()
- {
- joystick.clear();
- m_receiver->clearInput();
- }
- void releaseAllKeys()
- {
- joystick.releaseAllKeys();
- m_receiver->releaseAllKeys();
- }
- private:
- MyEventReceiver *m_receiver = nullptr;
- v2s32 m_mousepos;
- };
- class RandomInputHandler : public InputHandler
- {
- public:
- RandomInputHandler() = default;
- bool isRandom() const
- {
- return true;
- }
- virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
- virtual bool wasKeyDown(GameKeyType k) { return false; }
- virtual bool wasKeyPressed(GameKeyType k) { return false; }
- virtual bool wasKeyReleased(GameKeyType k) { return false; }
- virtual bool cancelPressed() { return false; }
- virtual float getMovementSpeed() { return movementSpeed; }
- virtual float getMovementDirection() { return movementDirection; }
- virtual v2s32 getMousePos() { return mousepos; }
- virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
- virtual s32 getMouseWheel() { return 0; }
- virtual void step(float dtime);
- s32 Rand(s32 min, s32 max);
- private:
- KeyList keydown;
- v2s32 mousepos;
- v2s32 mousespeed;
- float movementSpeed;
- float movementDirection;
- };
|