#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 const& current, std::unique_ptr 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 const& current, std::unique_ptr 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 const& current, std::unique_ptr 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 const& current, std::unique_ptr 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; } }