#ifndef CORE_LIBS_PRX_LIBSCEVIDEOOUT_TESTS_PADSIMULATION_HPP #define CORE_LIBS_PRX_LIBSCEVIDEOOUT_TESTS_PADSIMULATION_HPP #include "prx/libScePad/include/KeyboardMouse.hpp" #include #include #include #include "SDL_keyboard.h" namespace PadSimulation { struct TimedEvent { double ms = 0.0; SDL_Event event{}; bool setMouseMode = false; bool mouseMode = false; bool release = false; }; struct Sample { double ms = 0.0; PadInputState state; }; inline SDL_Event MotionEvent(int deltaX, int deltaY) { SDL_Event event{}; event.type = SDL_MOUSEMOTION; event.motion.xrel = deltaX; event.motion.yrel = deltaY; return event; } inline SDL_Event KeyEvent(SDL_Scancode key, bool down) { SDL_Event event{}; event.type = down ? SDL_KEYDOWN : SDL_KEYUP; event.key.keysym.scancode = key; event.key.state = down ? SDL_PRESSED : SDL_RELEASED; return event; } inline SDL_Event ButtonEvent(Uint8 button, bool down) { SDL_Event event{}; event.type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; event.button.button = button; event.button.state = down ? SDL_PRESSED : SDL_RELEASED; return event; } inline SDL_Event FocusLostEvent() { SDL_Event event{}; event.type = SDL_WINDOWEVENT; event.window.event = SDL_WINDOWEVENT_FOCUS_LOST; return event; } inline SDL_Event WheelEvent(int direction) { SDL_Event event{}; event.type = SDL_MOUSEWHEEL; event.wheel.y = direction; event.wheel.direction = SDL_MOUSEWHEEL_NORMAL; return event; } inline TimedEvent At(double ms, const SDL_Event& event) { return {ms, event, false, false, false}; } inline TimedEvent MouseModeAt(double ms, bool enabled) { return {ms, SDL_Event{}, true, enabled, false}; } inline TimedEvent ReleaseAt(double ms) { return {ms, SDL_Event{}, false, false, true}; } inline void AppendMotion(std::vector& events, double startMs, double durationMs, double countsPerSecondX, double countsPerSecondY, double reportHz = 1000.0) { const double periodMs = 1000.0 / reportHz; double owedX = 0.0; double owedY = 0.0; for (double ms = startMs + periodMs; ms <= startMs + durationMs + 1e-9; ms += periodMs) { owedX += countsPerSecondX * periodMs / 1000.0; owedY += countsPerSecondY * periodMs / 1000.0; const int deltaX = static_cast(std::trunc(owedX)); const int deltaY = static_cast(std::trunc(owedY)); owedX -= deltaX; owedY -= deltaY; if (deltaX != 0 || deltaY != 0) events.push_back(At(ms, MotionEvent(deltaX, deltaY))); } } inline std::vector Simulate(const Pad::InputConfiguration& configuration, const std::vector& events, double pollMs, double endMs) { using Clock = Pad::KeyboardMouse::Clock; const auto origin = Clock::time_point{} + std::chrono::hours(1); const auto at = [origin](double ms) { return origin + std::chrono::duration_cast(std::chrono::duration(ms)); }; Pad::KeyboardMouse keyboardMouse(configuration); keyboardMouse.Advance(at(0.0)); std::vector samples; std::size_t next = 0; const auto steps = static_cast(std::floor(endMs / pollMs + 1e-9)); for (long long step = 1; step <= steps; ++step) { const double ms = static_cast(step) * pollMs; const auto now = at(ms); for (; next < events.size() && events[next].ms <= ms + 1e-9; ++next) { const auto& timed = events[next]; if (timed.release) { keyboardMouse.Release(); continue; } if (timed.setMouseMode) { keyboardMouse.SetMouseMode(timed.mouseMode); continue; } const auto requests = keyboardMouse.HandleEvent(timed.event, now); if (requests.toggleMouse) keyboardMouse.SetMouseMode(!keyboardMouse.MouseMode()); if (requests.releaseMouse) keyboardMouse.SetMouseMode(false); } keyboardMouse.Advance(now); samples.push_back({ms, keyboardMouse.Compose(PadInputState{})}); } return samples; } } #endif