#pragma once #include "InputCodes.hpp" #include "Vec.hpp" #include "List.hpp" #include "Map.hpp" #include "Timing.hpp" #include namespace tp { struct InputEvent { enum class Type { NONE = 0, BUTTON_ACTION, MOUSE_DELTA, MOUSE_POS, SCROLL, } type = Type::NONE; enum class ButtonAction { NONE = 0, PRESS, HOLD, RELEASE, REPEAT, } buttonAction = ButtonAction::NONE; Vec2F mouseEvent = { 0, 0 }; Vec2F scrollDelta = { 0, 0 }; }; class InputState { public: InputState() = default; void handleEvent(const InputEvent& event); bool isStateChanged(); // true if event is no longer needed and false if we need to emulate some transitions further bool isHandled(); public: // Transitions from state to state is strict and defined by state order in the enum // If posted event conflicts with that automata, we need to emulate intermediate states enum State { NONE = 0, // Button is inactive PRESSED, // Button is pressed HOLD, // Button is still pressed RELEASED, // Button is released }; State mCurrentState; State mPreviousState; }; // Assumes that user and event poster use different threads // User can add own states for each input and decide how this state changes on specific events // Event posters has no access to any custom state and only report any changes in any way class EventHandler { public: EventHandler(); ~EventHandler(); public: // Event Poster Interface // Record event void postEvent(InputID inputID, InputEvent inputEvent); public: // User interface bool isEvents(); void processEvent(); [[nodiscard]] const Vec2F& getPointer() const; [[nodiscard]] const Vec2F& getPointerPrev() const; [[nodiscard]] Vec2F getPointerDelta() const; [[nodiscard]] bool isPressed(InputID id) const; [[nodiscard]] bool isReleased(InputID id) const; [[nodiscard]] bool isDown(InputID id) const; [[nodiscard]] halnf getScrollY() const; [[nodiscard]] halnf getPointerPressure() const; private: std::mutex mMutex = {}; // Store thread protected queue of posted events List> mEventQueue; // input states Vec2F mPointer; Vec2F mPointerPrev; Vec2F mScrollDelta; halnf mPointerPressure = 0; InputState mInputStates[(int) InputID::LAST_KEY_CODE]{}; Timer mTimerEvent = Timer(1000); }; }