AnyPS5/core/libs/prx/libSceVideoOut/tests/MouseInput.cpp

121 lines
4.6 KiB
C++

#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 <cstdint>
#include <cstdio>
#include <cstdlib>
#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;
}