#include "irrlichttypes_extrabloated.h"
#include "joystick_controller.h"
+#include <list>
#include "keycode.h"
#include "renderingengine.h"
-#include <unordered_set>
#ifdef HAVE_TOUCHSCREENGUI
#include "gui/touchscreengui.h"
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);
+ }
+
+ 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.count(keyCode); }
+ 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.count(keyCode);
+ bool b = keyWasDown[keyCode];
if (b)
- keyWasDown.erase(keyCode);
+ 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.count(keycode); }
+ 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.count(keycode); }
+ bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; }
- void listenForKey(const KeyPress &keyCode) { keysListenedFor.insert(keyCode); }
- void dontListenForKeys() { keysListenedFor.clear(); }
+ void listenForKey(const KeyPress &keyCode)
+ {
+ keysListenedFor.set(keyCode);
+ }
+ void dontListenForKeys()
+ {
+ keysListenedFor.clear();
+ }
s32 getMouseWheel()
{
#endif
}
- s32 mouse_wheel = 0;
-
JoystickController *joystick = nullptr;
#ifdef HAVE_TOUCHSCREENGUI
#endif
private:
- //! The current state of keys
- std::unordered_set<KeyPress> keyIsDown;
+ s32 mouse_wheel = 0;
- //! Whether a key was down
- std::unordered_set<KeyPress> keyWasDown;
+ // The current state of keys
+ KeyList keyIsDown;
- //! Whether a key has just been pressed
- std::unordered_set<KeyPress> keyWasPressed;
+ // Like keyIsDown but only reset when that key is read
+ KeyList keyWasDown;
- //! Whether a key has just been released
- std::unordered_set<KeyPress> keyWasReleased;
+ // Whether a key has just been pressed
+ KeyList keyWasPressed;
- //! List of keys we listen for
- std::unordered_set<KeyPress> keysListenedFor;
+ // 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
virtual bool wasKeyReleased(GameKeyType k) = 0;
virtual bool cancelPressed() = 0;
+ virtual float getMovementSpeed() = 0;
+ virtual float getMovementDirection() = 0;
+
virtual void clearWasKeyPressed() {}
virtual void clearWasKeyReleased() {}
{
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 wasKeyPressed(GameKeyType k)
{
- return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyReleased(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
+ }
+ 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
+ return joystick.getMovementDirection();
+ }
+
virtual bool cancelPressed()
{
return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
}
+
virtual void clearWasKeyPressed()
{
m_receiver->clearWasKeyPressed();
{
m_receiver->clearWasKeyReleased();
}
+
virtual void listenForKey(const KeyPress &keyCode)
{
m_receiver->listenForKey(keyCode);
}
- virtual void dontListenForKeys() { m_receiver->dontListenForKeys(); }
+ virtual void dontListenForKeys()
+ {
+ m_receiver->dontListenForKeys();
+ }
+
virtual v2s32 getMousePos()
{
- if (RenderingEngine::get_raw_device()->getCursorControl()) {
- return RenderingEngine::get_raw_device()
- ->getCursorControl()
- ->getPosition();
+ auto control = RenderingEngine::get_raw_device()->getCursorControl();
+ if (control) {
+ return control->getPosition();
}
return m_mousepos;
virtual void setMousePos(s32 x, s32 y)
{
- if (RenderingEngine::get_raw_device()->getCursorControl()) {
- RenderingEngine::get_raw_device()
- ->getCursorControl()
- ->setPosition(x, 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(); }
+ virtual s32 getMouseWheel()
+ {
+ return m_receiver->getMouseWheel();
+ }
void clear()
{
return true;
}
- virtual bool isKeyDown(GameKeyType k) { return keydown.count(keycache.key[k]); }
+ 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); }
s32 Rand(s32 min, s32 max);
private:
- std::unordered_set<KeyPress> keydown;
+ KeyList keydown;
v2s32 mousepos;
v2s32 mousespeed;
+ float movementSpeed;
+ float movementDirection;
};