summary refs log tree commit diff
path: root/src/Input.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Input.cpp')
-rw-r--r--src/Input.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/Input.cpp b/src/Input.cpp
new file mode 100644
index 0000000..2362794
--- /dev/null
+++ b/src/Input.cpp
@@ -0,0 +1,221 @@
+#include "Input.hpp"
+#include "ThreadRole.hpp"
+
+namespace MC {
+
+Bool Input::s_key_buffer[KeyCount] = { false };
+Bool Input::s_mouse_buffer[MouseCount] = { false };
+Vec2 Input::s_mouse_position = { 0, 0 };
+Input::MouseEventType Input::s_mouse_event_type = MouseEventType::None;
+
+void Input::register_callbacks(GFX::Window const& window) {
+    ASSERT_MAIN_THREAD();
+
+    glfwSetKeyCallback(window.get(), key_callback);
+    glfwSetCursorPosCallback(window.get(), cursor_position_callback);
+    glfwSetMouseButtonCallback(window.get(), mouse_button_callback);
+}
+
+// I think this is the Windows default for double click...
+#define DOUBLE_PRESS_DELTA_MS 500
+
+void Input::update(Time::Timestamp const current_time) {
+    ASSERT_MAIN_THREAD();
+
+    std::swap(m_state, m_previous_state);
+
+    for (auto& key : m_double_press->keys) key = false;
+    for (auto& mouse_button : m_double_press->mouse_buttons) mouse_button = false;
+
+    for (USize i = 0; i < KeyCount; ++i) {
+        m_state->map.keys[i] = s_key_buffer[i];
+        if (key_pressed(m_state, m_previous_state, TO(Key, i))) {
+            auto previous_release_time = m_last_key_release->keys[i];
+            m_double_press->keys[i] = current_time - previous_release_time < DOUBLE_PRESS_DELTA_MS;
+            m_last_key_release->keys[i] = current_time;
+        }
+    }
+
+    for (USize i = 0; i < MouseCount; ++i) {
+        m_state->map.mouse_buttons[i] = s_mouse_buffer[i];
+        if (mouse_button_pressed(m_state, m_previous_state, TO(Mouse, i))) {
+            auto previous_release_time = m_last_key_release->keys[i];
+            m_double_press->keys[i] = current_time - previous_release_time < DOUBLE_PRESS_DELTA_MS;
+            m_last_key_release->keys[i] = current_time;
+        }
+    }
+
+    if (s_mouse_event_type == MouseEventType::First)
+        m_previous_state->mouse_position = s_mouse_position;
+    m_state->mouse_position = s_mouse_position;
+}
+
+Bool Input::pressed(Key const key) const {
+    return key_pressed(m_state, m_previous_state, key);
+}
+
+Bool Input::pressed(Mouse const button) const {
+    return mouse_button_pressed(m_state, m_previous_state, button);
+}
+
+Bool Input::held(Key const key) const {
+    return m_state->map.keys[key_value(key)];
+}
+
+Bool Input::held(Mouse const button) const {
+    return m_state->map.mouse_buttons[mouse_button_value(button)];
+}
+
+Bool Input::released(Key const key) const {
+    return key_released(m_state, m_previous_state, key);
+}
+
+Bool Input::released(Mouse const button) const {
+    return mouse_button_released(m_state, m_previous_state, button);
+}
+
+Bool Input::double_pressed(Key const key) const {
+    return m_double_press->keys[key_value(key)];
+}
+
+Bool Input::double_pressed(Mouse const button) const {
+    return m_double_press->mouse_buttons[mouse_button_value(button)];
+}
+
+Vector<2> Input::mouse_position() const {
+    return m_state->mouse_position;
+}
+
+Vector<2> Input::mouse_movement() const {
+    return m_state->mouse_position - m_previous_state->mouse_position;
+}
+
+Bool Input::key_pressed(
+    std::unique_ptr<FrameState> const& current, std::unique_ptr<FrameState> const& previous, Key key
+) {
+    return current->map.keys[key_value(key)] && !previous->map.keys[key_value(key)];
+}
+
+Bool Input::mouse_button_pressed(
+    std::unique_ptr<FrameState> const& current, std::unique_ptr<FrameState> const& previous, Mouse mouse
+) {
+    return current->map.mouse_buttons[mouse_button_value(mouse)] && !previous->map.mouse_buttons[mouse_button_value(mouse)];
+}
+
+Bool Input::key_released(
+    std::unique_ptr<FrameState> const& current, std::unique_ptr<FrameState> const& previous, Key key
+) {
+    return !current->map.keys[key_value(key)] && previous->map.keys[key_value(key)];
+}
+
+Bool Input::mouse_button_released(
+    std::unique_ptr<FrameState> const& current, std::unique_ptr<FrameState> const& previous, Mouse mouse
+) {
+    return !current->map.mouse_buttons[mouse_button_value(mouse)] && previous->map.mouse_buttons[mouse_button_value(mouse)];
+}
+
+USize Input::key_value(Key key) {
+    return TO(USize, key);
+}
+
+USize Input::mouse_button_value(Mouse button) {
+    return TO(USize, button);
+}
+
+Key Input::from_glfw_key(I32 const key) {
+    switch (key) {
+        case GLFW_KEY_A: return Key::A;
+        case GLFW_KEY_B: return Key::B;
+        case GLFW_KEY_C: return Key::C;
+        case GLFW_KEY_D: return Key::D;
+        case GLFW_KEY_E: return Key::E;
+        case GLFW_KEY_F: return Key::F;
+        case GLFW_KEY_G: return Key::G;
+        case GLFW_KEY_H: return Key::H;
+        case GLFW_KEY_I: return Key::I;
+        case GLFW_KEY_J: return Key::J;
+        case GLFW_KEY_K: return Key::K;
+        case GLFW_KEY_L: return Key::L;
+        case GLFW_KEY_M: return Key::M;
+        case GLFW_KEY_N: return Key::N;
+        case GLFW_KEY_O: return Key::O;
+        case GLFW_KEY_P: return Key::P;
+        case GLFW_KEY_Q: return Key::Q;
+        case GLFW_KEY_R: return Key::R;
+        case GLFW_KEY_S: return Key::S;
+        case GLFW_KEY_T: return Key::T;
+        case GLFW_KEY_U: return Key::U;
+        case GLFW_KEY_V: return Key::V;
+        case GLFW_KEY_W: return Key::W;
+        case GLFW_KEY_X: return Key::X;
+        case GLFW_KEY_Y: return Key::Y;
+        case GLFW_KEY_Z: return Key::Z;
+        case GLFW_KEY_0: return Key::Zero;
+        case GLFW_KEY_1: return Key::One;
+        case GLFW_KEY_2: return Key::Two;
+        case GLFW_KEY_3: return Key::Three;
+        case GLFW_KEY_4: return Key::Four;
+        case GLFW_KEY_5: return Key::Five;
+        case GLFW_KEY_6: return Key::Six;
+        case GLFW_KEY_7: return Key::Seven;
+        case GLFW_KEY_8: return Key::Eight;
+        case GLFW_KEY_9: return Key::Nine;
+        case GLFW_KEY_ESCAPE: return Key::Escape;
+        case GLFW_KEY_ENTER: return Key::Enter;
+        case GLFW_KEY_TAB: return Key::Tab;
+        case GLFW_KEY_BACKSPACE: return Key::Backspace;
+        case GLFW_KEY_INSERT: return Key::Insert;
+        case GLFW_KEY_DELETE: return Key::Delete;
+        case GLFW_KEY_RIGHT: return Key::Right;
+        case GLFW_KEY_LEFT: return Key::Left;
+        case GLFW_KEY_DOWN: return Key::Down;
+        case GLFW_KEY_UP: return Key::Up;
+        case GLFW_KEY_LEFT_SHIFT: return Key::LeftShift;
+        case GLFW_KEY_RIGHT_SHIFT: return Key::RightShift;
+        case GLFW_KEY_LEFT_CONTROL: return Key::LeftControl;
+        case GLFW_KEY_RIGHT_CONTROL: return Key::RightControl;
+        case GLFW_KEY_LEFT_ALT: return Key::LeftAlt;
+        case GLFW_KEY_RIGHT_ALT: return Key::RightAlt;
+        case GLFW_KEY_SPACE: return Key::Space;
+        case GLFW_KEY_F1: return Key::F1;
+        case GLFW_KEY_F2: return Key::F2;
+        case GLFW_KEY_F3: return Key::F3;
+        case GLFW_KEY_F4: return Key::F4;
+        case GLFW_KEY_F5: return Key::F5;
+        case GLFW_KEY_F6: return Key::F6;
+        case GLFW_KEY_F7: return Key::F7;
+        case GLFW_KEY_F8: return Key::F8;
+        case GLFW_KEY_F9: return Key::F9;
+        case GLFW_KEY_F10: return Key::F10;
+        case GLFW_KEY_F11: return Key::F11;
+        case GLFW_KEY_F12: return Key::F12;
+        default: UNREACHABLE("Unknown key."); return TO(Key, 0);
+    }
+}
+
+Mouse Input::from_glfw_mouse(I32 const button) {
+    switch (button) {
+        case GLFW_MOUSE_BUTTON_LEFT: return Mouse::Left;
+        case GLFW_MOUSE_BUTTON_RIGHT: return Mouse::Right;
+        case GLFW_MOUSE_BUTTON_MIDDLE: return Mouse::Middle;
+        default: UNREACHABLE("Unknown mouse button."); return TO(Mouse, 0);
+    }
+}
+
+void Input::key_callback(GLFWwindow* _window, I32 const key, I32 _scancode, I32 const action, I32 _mods) {
+    if (action == GLFW_PRESS) s_key_buffer[key_value(from_glfw_key(key))] = true;
+    else if (action == GLFW_RELEASE) s_key_buffer[key_value(from_glfw_key(key))] = false;
+}
+
+void Input::cursor_position_callback(GLFWwindow* _window, F64 x, F64 y) {
+    if (s_mouse_event_type == MouseEventType::None) s_mouse_event_type = MouseEventType::First;
+    else if (s_mouse_event_type == MouseEventType::First) s_mouse_event_type = MouseEventType::Subsequent;
+    s_mouse_position = { x, y };
+}
+
+void Input::mouse_button_callback(GLFWwindow* _window, I32 const button, I32 const action, I32 _mods) {
+    if (action == GLFW_PRESS) s_mouse_buffer[mouse_button_value(from_glfw_mouse(button))] = true;
+    else if (action == GLFW_RELEASE) s_mouse_buffer[mouse_button_value(from_glfw_mouse(button))] = false;
+}
+
+}