#pragma once #include #include "Time.hpp" #include "Common/Casts.hpp" #include "Common/Sizes.hpp" #include "Common/Pure.hpp" #include "GFX/Window.hpp" #include "Math/Vector.hpp" namespace MC { // TODO: Add some more keys. // TODO: I think some of these keys are "modifiers" under GLFW, and should be handled differently. enum class Key { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Escape, Enter, Tab, Backspace, Insert, Delete, Right, Left, Down, Up, LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, Space, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, }; constexpr USize KeyCount = 65; static_assert(KeyCount == TO(USize, Key::F12) + 1, "Key count mismatch."); enum class Mouse { Left, Right, Middle, }; constexpr USize MouseCount = 3; static_assert(MouseCount == TO(USize, Mouse::Middle) + 1, "Mouse count mismatch."); // The simple input system. // All methods are thread safe, except the initial registration of the input callbacks // and the state update. Both must be called from the main thread. class Input { public: explicit Input() = default; // Registers the input callbacks for the given window. // This function must be called from the main thread. static void register_callbacks(GFX::Window const& window); // Updates the input state from the callback buffers. // This function must be called from the main thread. void update(Time::Timestamp current_time); // Returns true if the key was pressed during the last frame. PURE Bool pressed(Key key) const; // Returns true if the mouse button was pressed during the last frame. PURE Bool pressed(Mouse button) const; // Returns true if the key is currently held down. PURE Bool held(Key key) const; // Returns true if the mouse button is currently held down. PURE Bool held(Mouse button) const; // Returns true if the key was released during the last frame. PURE Bool released(Key key) const; // Returns true if the mouse button was released during the last frame. PURE Bool released(Mouse button) const; // Returns true if the key was double pressed during the last frame. // A double press is defined as two presses within a certain time frame. PURE Bool double_pressed(Key key) const; // Returns true if the mouse button was double pressed during the last frame. // A double press is defined as two presses within a certain time frame. PURE Bool double_pressed(Mouse button) const; // Returns the position of the mouse cursor in the window. PURE Vector<2> mouse_position() const; // Returns the change in the position of the mouse cursor since the last frame. PURE Vector<2> mouse_movement() const; private: template struct ButtonMap { T keys[KeyCount] = { 0 }; T mouse_buttons[MouseCount] = { 0 }; }; struct FrameState { ButtonMap map; Vec2 mouse_position = { 0, 0 }; }; std::unique_ptr m_state = std::make_unique(); std::unique_ptr m_previous_state = std::make_unique(); std::unique_ptr> m_last_key_release = std::make_unique>(); std::unique_ptr> m_double_press = std::make_unique>(); static Bool key_pressed(std::unique_ptr const& current, std::unique_ptr const& previous, Key key); static Bool mouse_button_pressed(std::unique_ptr const& current, std::unique_ptr const& previous, Mouse mouse); static Bool key_released(std::unique_ptr const& current, std::unique_ptr const& previous, Key key); static Bool mouse_button_released(std::unique_ptr const& current, std::unique_ptr const& previous, Mouse mouse); static Bool s_key_buffer[KeyCount]; static Bool s_mouse_buffer[MouseCount]; static Vec2 s_mouse_position; enum class MouseEventType { None, First, Subsequent }; static MouseEventType s_mouse_event_type; static USize key_value(Key key); static USize mouse_button_value(Mouse button); static Key from_glfw_key(I32 key); static Mouse from_glfw_mouse(I32 button); static void key_callback(GLFWwindow* _window, I32 key, I32 _scancode, I32 action, I32 _mods); static void cursor_position_callback(GLFWwindow* _window, F64 x, F64 y); static void mouse_button_callback(GLFWwindow* _window, I32 button, I32 action, I32 _mods); }; }