#include #include #include #include namespace Game { const bool* Input::mCurrentKeyStates = nullptr; std::vector Input::mPreviousKeyStates = {}; int Input::mNumKeys = 0; int Input::mPrevNumKeys = 0; SDL_MouseButtonFlags Input::mCurrentMouseButtonStates = 0; SDL_MouseButtonFlags Input::mPreviousMouseButtonStates = 0; float Input::mMouseX = 0.0f; float Input::mMouseY = 0.0f; std::mutex Input::mTextMutex; std::vector Input::mPendingText; void Input::update() { // Copy the previous keyboard state (snapshot) so we can detect just-pressed if (mCurrentKeyStates && mNumKeys > 0) { mPreviousKeyStates.assign(mCurrentKeyStates, mCurrentKeyStates + mNumKeys); mPrevNumKeys = mNumKeys; } else { // If we don't have a previous snapshot, initialize previous vector to zeros with current size if (mNumKeys > 0) mPreviousKeyStates.assign(mNumKeys, 0); mPrevNumKeys = mNumKeys; } mCurrentKeyStates = SDL_GetKeyboardState(&mNumKeys); mPreviousMouseButtonStates = mCurrentMouseButtonStates; float rawMouseX = 0.0f; float rawMouseY = 0.0f; mCurrentMouseButtonStates = SDL_GetMouseState(&rawMouseX, &rawMouseY); // Convert mouse coordinates from real display/window pixels into // centered logical game coordinates (1280x720 world space). static constexpr float LOGICAL_WIDTH = 1280.0f; static constexpr float LOGICAL_HEIGHT = 720.0f; float displayW = LOGICAL_WIDTH; float displayH = LOGICAL_HEIGHT; SDL_Window* sdlWindow = Window::Window::getSDLWindowBackend(); if (sdlWindow) { int windowPixelsW = static_cast(LOGICAL_WIDTH); int windowPixelsH = static_cast(LOGICAL_HEIGHT); SDL_GetWindowSizeInPixels(sdlWindow, &windowPixelsW, &windowPixelsH); SDL_DisplayID displayId = SDL_GetDisplayForWindow(sdlWindow); const SDL_DisplayMode* displayMode = SDL_GetCurrentDisplayMode(displayId); if (displayMode && displayMode->w > 0 && displayMode->h > 0) { displayW = static_cast(displayMode->w); displayH = static_cast(displayMode->h); } else if (windowPixelsW > 0 && windowPixelsH > 0) { displayW = static_cast(windowPixelsW); displayH = static_cast(windowPixelsH); } } const float invScaleX = LOGICAL_WIDTH / displayW; const float invScaleY = LOGICAL_HEIGHT / displayH; mMouseX = rawMouseX * invScaleX - (LOGICAL_WIDTH * 0.5f); mMouseY = rawMouseY * invScaleY - (LOGICAL_HEIGHT * 0.5f); // Consume and deliver queued text input from window thread to focused textbox std::vector texts; consumeText(texts); if (!texts.empty()) { auto entities = State::GameState::getInstance().getEntitiesSnapshot(); for (auto* e : entities) { if (!e) continue; auto* tb = dynamic_cast(e); if (tb && tb->isFocused()) { for (auto& s : texts) { tb->insertText(s); } break; // Deliver to first focused textbox only } } } } bool Input::isKeyPressed(SDL_Scancode key) { if (key < 0 || key >= mNumKeys) return false; return mCurrentKeyStates && mCurrentKeyStates[key]; } bool Input::isKeyJustPressed(SDL_Scancode key) { if (key < 0 || key >= mNumKeys) return false; bool cur = mCurrentKeyStates && mCurrentKeyStates[key]; bool prev = (key < static_cast(mPreviousKeyStates.size())) ? static_cast(mPreviousKeyStates[key]) : false; return cur && !prev; } bool Input::isKeyJustReleased(SDL_Scancode key) { if (key < 0 || key >= mNumKeys) return false; bool cur = mCurrentKeyStates && mCurrentKeyStates[key]; bool prev = (key < static_cast(mPreviousKeyStates.size())) ? static_cast(mPreviousKeyStates[key]) : false; return !cur && prev; } bool Input::isMouseButtonPressed(Uint8 button) { return (mCurrentMouseButtonStates & SDL_BUTTON_MASK(button)) != 0; } bool Input::isMouseButtonJustPressed(Uint8 button) { return (mCurrentMouseButtonStates & SDL_BUTTON_MASK(button)) != 0 && (mPreviousMouseButtonStates & SDL_BUTTON_MASK(button)) == 0; } bool Input::isMouseButtonJustReleased(Uint8 button) { return (mCurrentMouseButtonStates & SDL_BUTTON_MASK(button)) == 0 && (mPreviousMouseButtonStates & SDL_BUTTON_MASK(button)) != 0; } float Input::getMouseX() { return mMouseX; } float Input::getMouseY() { return mMouseY; } void Input::pushText(const std::string& utf8) { std::scoped_lock lock(mTextMutex); mPendingText.push_back(utf8); } void Input::consumeText(std::vector& out) { std::scoped_lock lock(mTextMutex); out.swap(mPendingText); } }