#include "prx/libSceVideoOut/include/MouseInput.hpp" #include "prx/libSceMouse/include/mouse_structs.h" #include "prx/libc/include/general/VabiMacros.hpp" #include "SDL.h" #include "SDL_events.h" #include "SDL_mouse.h" #include #include #include #undef main extern "C" { int APS5_VABI sceMouseInit(); int APS5_VABI sceMouseOpen(int userId, std::int32_t type, std::int32_t index, const void* param); int APS5_VABI sceMouseRead(std::int32_t handle, MouseData* data, std::int32_t num); int APS5_VABI sceMouseClose(std::int32_t handle); } namespace { void Require(bool condition, const char* reason) { if (!condition) { std::fprintf(stderr, "mouse input: %s\n", reason); std::abort(); } } SDL_Event Motion(unsigned windowId, int xrel, int yrel) { SDL_Event event{}; event.type = SDL_MOUSEMOTION; event.motion.windowID = windowId; event.motion.xrel = xrel; event.motion.yrel = yrel; return event; } SDL_Event Window(unsigned windowId, std::uint8_t kind) { SDL_Event event{}; event.type = SDL_WINDOWEVENT; event.window.windowID = windowId; event.window.event = kind; return event; } void CaptureDecision(MouseInput& input, std::int32_t handle) { Require(input.CaptureWanted(true), "a focused window with an open mouse does not want the capture"); Require(!input.CaptureWanted(false), "the pad's mouse-to-stick toggle does not release the capture"); input.HandleEvent(Window(3, SDL_WINDOWEVENT_FOCUS_LOST), 3); Require(!input.CaptureWanted(true), "losing focus does not release the capture"); input.HandleEvent(Window(3, SDL_WINDOWEVENT_FOCUS_GAINED), 3); Require(input.CaptureWanted(true), "regaining focus does not restore the capture"); input.HandleEvent(Window(4, SDL_WINDOWEVENT_FOCUS_LOST), 3); Require(input.CaptureWanted(true), "another window's focus loss released the capture"); Require(sceMouseClose(handle) == 0, "close failed"); Require(!input.CaptureWanted(true), "a closed mouse keeps the capture"); Require(sceMouseOpen(255, 0, 0, nullptr) >= 0, "reopen failed"); Require(input.CaptureWanted(true), "a reopened mouse does not want the capture"); input.HandleEvent(Window(3, SDL_WINDOWEVENT_CLOSE), 3); Require(!input.CaptureWanted(true), "a closed window keeps the capture"); input.HandleEvent(Window(3, SDL_WINDOWEVENT_FOCUS_GAINED), 3); } void CaptureApplied(MouseInput& input) { SDL_SetHint("SDL_VIDEODRIVER", "dummy"); if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::fprintf(stderr, "mouse input: SDL video unavailable (%s): capture application not checked\n", SDL_GetError()); return; } input.UpdateCapture(true); const bool applied = SDL_GetRelativeMouseMode() == SDL_TRUE; input.UpdateCapture(false); Require(SDL_GetRelativeMouseMode() == SDL_FALSE, "the capture was not released"); std::printf("mouse input: SDL %s relative mode under the %s driver\n", applied ? "applied" : "refused", SDL_GetCurrentVideoDriver()); SDL_Quit(); } void Sum(std::int32_t handle, std::int32_t& x, std::int32_t& y) { MouseData data[MOUSE_MAX_DATA_NUM]{}; const int count = sceMouseRead(handle, data, MOUSE_MAX_DATA_NUM); Require(count >= 0, "read failed"); x = 0; y = 0; for (int index = 0; index < count; ++index) { x += data[index].x_axis; y += data[index].y_axis; } } } int main() { Require(sceMouseInit() == 0, "init failed"); const std::int32_t handle = sceMouseOpen(255, 0, 0, nullptr); Require(handle >= 0, "open failed"); MouseInput input; std::int32_t x = 0; std::int32_t y = 0; input.HandleEvent(Motion(3, 10, -7), 3); input.HandleEvent(Motion(4, 100, 100), 3); Sum(handle, x, y); Require(x == 10 && y == -7, "unscaled deltas are not passed through or another window's motion was not ignored"); input.SetPresentation(1920, 1080, 1843, 1037); for (int step = 0; step < 5; ++step) input.HandleEvent(Motion(3, 10, -7), 3); Sum(handle, x, y); Require(x == 52 && y == -36, "deltas are not scaled by the presented image with sub-pixel carry"); input.SetPresentation(1920, 1080, 960, 540); input.HandleEvent(Motion(3, 1, 1), 3); input.HandleEvent(Motion(3, 1, 1), 3); Sum(handle, x, y); Require(x == 4 && y == 4, "a half-size presentation does not double the deltas"); input.SetPresentation(0, 0, 0, 0); input.HandleEvent(Motion(3, 3, 3), 3); Sum(handle, x, y); Require(x == 6 && y == 6, "an empty presentation changed the scale"); CaptureDecision(input, handle); CaptureApplied(input); std::puts("mouse input tests passed"); return 0; }