From 8fac768b9c63a810d1a5d8726999085b55031cea Mon Sep 17 00:00:00 2001 From: Julien Legay Date: Mon, 28 Sep 2026 11:45:04 +0200 Subject: [PATCH 1/2] feat(libSceMouse): implement stateful mouse API exports Keep the existing Export.cpp entry point and System V ABI while moving mouse state into the library implementation.`n`nTrack initialization, a single handle, button state, timestamps, and a bounded non-blocking event queue. Define and assert the guest MouseData layout and expose an input publisher for the host backend. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- core/libs/prx/libSceMouse/CMakeLists.txt | 7 ++ core/libs/prx/libSceMouse/Export.cpp | 37 +++--- .../prx/libSceMouse/include/MouseState.hpp | 28 +++++ .../prx/libSceMouse/include/mouse_structs.h | 34 ++++++ core/libs/prx/libSceMouse/src/mouse_impl.cpp | 106 ++++++++++++++++++ 5 files changed, 188 insertions(+), 24 deletions(-) create mode 100644 core/libs/prx/libSceMouse/CMakeLists.txt create mode 100644 core/libs/prx/libSceMouse/include/MouseState.hpp create mode 100644 core/libs/prx/libSceMouse/include/mouse_structs.h create mode 100644 core/libs/prx/libSceMouse/src/mouse_impl.cpp diff --git a/core/libs/prx/libSceMouse/CMakeLists.txt b/core/libs/prx/libSceMouse/CMakeLists.txt new file mode 100644 index 000000000..99c3cbbfc --- /dev/null +++ b/core/libs/prx/libSceMouse/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(libSceMouse SHARED EXCLUDE_FROM_ALL + ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/mouse_impl.cpp +) +target_include_directories(libSceMouse PRIVATE ${LIBS_INCLUDE_DIR}) +set_target_properties(libSceMouse PROPERTIES CXX_EXTENSIONS OFF) +configure_windows_unwind(libSceMouse) diff --git a/core/libs/prx/libSceMouse/Export.cpp b/core/libs/prx/libSceMouse/Export.cpp index 5e6120682..9d820d245 100644 --- a/core/libs/prx/libSceMouse/Export.cpp +++ b/core/libs/prx/libSceMouse/Export.cpp @@ -1,36 +1,25 @@ -#include -#include -#include "SceTypes.hpp" -#include "prx/libc/include/General.hpp" +#include "prx/libSceMouse/include/MouseState.hpp" extern "C" { -int APS5_VABI sceMouseClose(int32_t handle) { - (void)handle; - NotImplemented_nid_no_patch(__func__); - return 0; +int APS5_VABI sceMouseInit() { + return Mouse::Initialize(); } -int APS5_VABI sceMouseInit(void) { - NotImplemented_nid_no_patch(__func__); - return 0; +int APS5_VABI sceMouseOpen(int userId, std::int32_t type, std::int32_t index, const void* param) { + return Mouse::Open(userId, type, index, static_cast(param)); } -int APS5_VABI sceMouseOpen(int user_id, int32_t type, int32_t index, const void* param) { - (void)user_id; - (void)type; - (void)index; - (void)param; - NotImplemented_nid_no_patch(__func__); - return 0; +int APS5_VABI sceMouseClose(std::int32_t handle) { + return Mouse::Close(handle); } -int APS5_VABI sceMouseRead(int32_t handle, MouseData* data, int32_t num) { - (void)handle; - (void)data; - (void)num; - NotImplemented_nid_no_patch(__func__); - return 0; +int APS5_VABI sceMouseRead(std::int32_t handle, MouseData* data, std::int32_t num) { + return Mouse::Read(handle, data, num); +} + +void MousePublishInput_nid_postfix(const MouseInputEvent& event) { + Mouse::Publish(event); } } diff --git a/core/libs/prx/libSceMouse/include/MouseState.hpp b/core/libs/prx/libSceMouse/include/MouseState.hpp new file mode 100644 index 000000000..bf7d57a09 --- /dev/null +++ b/core/libs/prx/libSceMouse/include/MouseState.hpp @@ -0,0 +1,28 @@ +#ifndef CORE_LIBS_PRX_LIBSCEMOUSE_MOUSESTATE_HPP +#define CORE_LIBS_PRX_LIBSCEMOUSE_MOUSESTATE_HPP + +#include "prx/libSceMouse/include/mouse_structs.h" + +struct MouseInputEvent { + std::int32_t x = 0; + std::int32_t y = 0; + std::int32_t wheel = 0; + std::int32_t tilt = 0; + std::uint32_t button = 0; + bool pressed = false; + bool resetButtons = false; + bool connectionChange = false; + bool connected = true; +}; + +namespace Mouse { +int Initialize(); +int Open(int userId, std::int32_t type, std::int32_t index, const MouseOpenParam* param); +int Close(std::int32_t handle); +int Read(std::int32_t handle, MouseData* data, std::int32_t num); +void Publish(const MouseInputEvent& event); +} + +extern "C" void MousePublishInput_nid_postfix(const MouseInputEvent& event); + +#endif diff --git a/core/libs/prx/libSceMouse/include/mouse_structs.h b/core/libs/prx/libSceMouse/include/mouse_structs.h new file mode 100644 index 000000000..30c7d3a8f --- /dev/null +++ b/core/libs/prx/libSceMouse/include/mouse_structs.h @@ -0,0 +1,34 @@ +#ifndef CORE_LIBS_PRX_LIBSCEMOUSE_MOUSE_STRUCTS_H +#define CORE_LIBS_PRX_LIBSCEMOUSE_MOUSE_STRUCTS_H + +#include +#include +#include "SceTypes.hpp" + +struct MouseOpenParam { + std::uint8_t behaviorFlag; + std::uint8_t reserved[7]; +}; + +constexpr int MOUSE_OK = 0; +constexpr int MOUSE_ERROR_INVALID_ARG = static_cast(0x80df0001u); +constexpr int MOUSE_ERROR_INVALID_HANDLE = static_cast(0x80df0003u); +constexpr int MOUSE_ERROR_ALREADY_OPENED = static_cast(0x80df0004u); +constexpr int MOUSE_ERROR_NOT_INITIALIZED = static_cast(0x80df0005u); +constexpr int MOUSE_MAX_DATA_NUM = 64; +constexpr int MOUSE_HANDLE = 1; +constexpr std::uint8_t MOUSE_OPEN_PARAM_MERGED = 1; + +static_assert(sizeof(MouseOpenParam) == 8); +static_assert(sizeof(MouseData) == 40); +static_assert(alignof(MouseData) == 8); +static_assert(offsetof(MouseData, timestamp) == 0); +static_assert(offsetof(MouseData, connected) == 8); +static_assert(offsetof(MouseData, buttons) == 12); +static_assert(offsetof(MouseData, x_axis) == 16); +static_assert(offsetof(MouseData, y_axis) == 20); +static_assert(offsetof(MouseData, wheel) == 24); +static_assert(offsetof(MouseData, tilt) == 28); +static_assert(offsetof(MouseData, reserved) == 32); + +#endif diff --git a/core/libs/prx/libSceMouse/src/mouse_impl.cpp b/core/libs/prx/libSceMouse/src/mouse_impl.cpp new file mode 100644 index 000000000..5bcf78e72 --- /dev/null +++ b/core/libs/prx/libSceMouse/src/mouse_impl.cpp @@ -0,0 +1,106 @@ +#include "prx/libSceMouse/include/MouseState.hpp" +#include "prx/libkernel/Time/include/Time.hpp" + +#include +#include +#include + +namespace { +std::mutex mouseMutex; +std::array history{}; +int head = 0; +int count = 0; +bool initialized = false; +bool opened = false; +bool connected = true; +std::uint32_t buttons = 0; + +void enqueue(const MouseData& data) { + if (count == MOUSE_MAX_DATA_NUM) { + head = (head + 1) % MOUSE_MAX_DATA_NUM; + --count; + } + history[(head + count) % MOUSE_MAX_DATA_NUM] = data; + ++count; +} +} + +namespace Mouse { + +int Initialize() { + std::lock_guard lock(mouseMutex); + initialized = true; + return MOUSE_OK; +} + +int Open(int userId, std::int32_t type, std::int32_t index, const MouseOpenParam* param) { + std::lock_guard lock(mouseMutex); + if (!initialized) return MOUSE_ERROR_NOT_INITIALIZED; + if (userId < 0 || type != 0 || index != 0 || + (param != nullptr && (param->behaviorFlag & ~MOUSE_OPEN_PARAM_MERGED) != 0)) { + return MOUSE_ERROR_INVALID_ARG; + } + if (opened) return MOUSE_ERROR_ALREADY_OPENED; + opened = true; + buttons = 0; + head = 0; + count = 0; + MouseData initial{}; + initial.timestamp = sceKernelGetProcessTime(); + initial.connected = connected; + enqueue(initial); + return MOUSE_HANDLE; +} + +int Close(std::int32_t handle) { + std::lock_guard lock(mouseMutex); + if (!initialized) return MOUSE_ERROR_NOT_INITIALIZED; + if (handle != MOUSE_HANDLE || !opened) return MOUSE_ERROR_INVALID_HANDLE; + opened = false; + buttons = 0; + head = 0; + count = 0; + return MOUSE_OK; +} + +int Read(std::int32_t handle, MouseData* data, std::int32_t num) { + std::lock_guard lock(mouseMutex); + if (!initialized) return MOUSE_ERROR_NOT_INITIALIZED; + if (handle != MOUSE_HANDLE || !opened) return MOUSE_ERROR_INVALID_HANDLE; + if (data == nullptr || num <= 0 || num > MOUSE_MAX_DATA_NUM) return MOUSE_ERROR_INVALID_ARG; + const int available = std::min(count, num); + for (int i = 0; i < available; ++i) { + data[i] = history[head]; + head = (head + 1) % MOUSE_MAX_DATA_NUM; + } + count -= available; + return available; +} + +void Publish(const MouseInputEvent& event) { + std::lock_guard lock(mouseMutex); + if (event.connectionChange) { + if (connected == event.connected) return; + connected = event.connected; + if (!connected) buttons = 0; + } else if (!connected) { + return; + } + if (!opened) return; + if (event.resetButtons) buttons = 0; + if (event.button != 0) { + if (event.pressed) buttons |= event.button; + else buttons &= ~event.button; + } + MouseData data{}; + data.timestamp = sceKernelGetProcessTime(); + data.connected = connected; + data.buttons = buttons; + data.x_axis = event.x; + data.y_axis = event.y; + data.wheel = event.wheel; + data.tilt = event.tilt; + enqueue(data); +} + +} From ddb8add7539d826582770c2ebf4bf8e434b3dfce Mon Sep 17 00:00:00 2001 From: Julien Legay Date: Mon, 28 Sep 2026 11:45:31 +0200 Subject: [PATCH 2/2] feat(libSceVideoOut): route SDL mouse events to libSceMouse Forward relative motion, supported button transitions, and horizontal and vertical scrolling from the existing SDL event loop. Reset pressed buttons on focus loss without reporting a device disconnect, and track window close and refocus transitions. Link libSceVideoOut to the mouse library using the existing Pad integration pattern. Add targeted coverage for API errors, event mapping, focus changes, history overflow, and reopening. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- core/libs/prx/libSceMouse/CMakeLists.txt | 15 +++ core/libs/prx/libSceMouse/tests/Mouse.cpp | 108 ++++++++++++++++++ core/libs/prx/libSceVideoOut/CMakeLists.txt | 3 +- .../prx/libSceVideoOut/include/MouseInput.hpp | 14 +++ .../prx/libSceVideoOut/src/MouseInput.cpp | 55 +++++++++ .../prx/libSceVideoOut/src/VideoOutDriver.cpp | 3 + 6 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 core/libs/prx/libSceMouse/tests/Mouse.cpp create mode 100644 core/libs/prx/libSceVideoOut/include/MouseInput.hpp create mode 100644 core/libs/prx/libSceVideoOut/src/MouseInput.cpp diff --git a/core/libs/prx/libSceMouse/CMakeLists.txt b/core/libs/prx/libSceMouse/CMakeLists.txt index 99c3cbbfc..76b0c4fe8 100644 --- a/core/libs/prx/libSceMouse/CMakeLists.txt +++ b/core/libs/prx/libSceMouse/CMakeLists.txt @@ -5,3 +5,18 @@ add_library(libSceMouse SHARED EXCLUDE_FROM_ALL target_include_directories(libSceMouse PRIVATE ${LIBS_INCLUDE_DIR}) set_target_properties(libSceMouse PROPERTIES CXX_EXTENSIONS OFF) configure_windows_unwind(libSceMouse) + +if(BUILD_TESTING) + add_executable(mouse_tests + ${CMAKE_CURRENT_SOURCE_DIR}/tests/Mouse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libSceVideoOut/src/MouseInput.cpp + ) + target_include_directories(mouse_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/3rdparty/SDL2/include) + target_link_libraries(mouse_tests PRIVATE libSceMouse libkernel libc) + configure_windows_unwind(mouse_tests) + add_test(NAME mouse_input COMMAND mouse_tests) + if(WIN32) + set_tests_properties(mouse_input PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/libSceMouse/tests/Mouse.cpp b/core/libs/prx/libSceMouse/tests/Mouse.cpp new file mode 100644 index 000000000..e01f3f9b4 --- /dev/null +++ b/core/libs/prx/libSceMouse/tests/Mouse.cpp @@ -0,0 +1,108 @@ +#include "prx/libSceMouse/include/mouse_structs.h" +#include "prx/libSceMouse/include/MouseState.hpp" +#include "prx/libSceVideoOut/include/MouseInput.hpp" +#include "SDL_events.h" +#include "SDL_mouse.h" + +#include + +extern "C" { +int APS5_VABI sceMouseInit(); +int APS5_VABI sceMouseOpen(int, std::int32_t, std::int32_t, const void*); +int APS5_VABI sceMouseClose(std::int32_t); +int APS5_VABI sceMouseRead(std::int32_t, MouseData*, std::int32_t); +} + +static void Require(bool value) { if (!value) std::abort(); } + +int main() { + MouseData data[64]{}; + Require(sceMouseOpen(1, 0, 0, nullptr) == MOUSE_ERROR_NOT_INITIALIZED); + Require(sceMouseInit() == MOUSE_OK); + Require(sceMouseInit() == MOUSE_OK); + Require(sceMouseOpen(1, 0, 1, nullptr) == MOUSE_ERROR_INVALID_ARG); + MouseOpenParam unsupported{}; + unsupported.behaviorFlag = 2; + Require(sceMouseOpen(1, 0, 0, &unsupported) == MOUSE_ERROR_INVALID_ARG); + Require(sceMouseOpen(1, 0, 0, nullptr) == MOUSE_HANDLE); + Require(sceMouseOpen(1, 0, 0, nullptr) == MOUSE_ERROR_ALREADY_OPENED); + Require(sceMouseRead(42, data, 1) == MOUSE_ERROR_INVALID_HANDLE); + Require(sceMouseRead(MOUSE_HANDLE, nullptr, 1) == MOUSE_ERROR_INVALID_ARG); + Require(sceMouseRead(MOUSE_HANDLE, data, 65) == MOUSE_ERROR_INVALID_ARG); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 1); + Require(data[0].connected && data[0].buttons == 0); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 0); + + MouseInput input; + SDL_Event event{}; + event.type = SDL_MOUSEMOTION; + event.motion.windowID = 7; + event.motion.xrel = 9; + event.motion.yrel = -4; + input.HandleEvent(event, 8); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 0); + input.HandleEvent(event, 7); + + event = {}; + event.type = SDL_MOUSEBUTTONDOWN; + event.button.windowID = 7; + event.button.button = SDL_BUTTON_RIGHT; + input.HandleEvent(event, 7); + event = {}; + event.type = SDL_MOUSEWHEEL; + event.wheel.windowID = 7; + event.wheel.x = 2; + event.wheel.y = -3; + event.wheel.direction = SDL_MOUSEWHEEL_FLIPPED; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 3) == 3); + Require(data[0].x_axis == 9 && data[0].y_axis == -4 && data[0].buttons == 0); + Require(data[1].buttons == 2); + Require(data[2].buttons == 2 && data[2].wheel == 3 && data[2].tilt == -2); + Require(data[0].timestamp <= data[2].timestamp); + event = {}; + event.type = SDL_MOUSEBUTTONDOWN; + event.button.windowID = 7; + event.button.button = SDL_BUTTON_X1; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 0); + + event = {}; + event.type = SDL_WINDOWEVENT; + event.window.windowID = 7; + event.window.event = SDL_WINDOWEVENT_FOCUS_LOST; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 1); + Require(data[0].connected && data[0].buttons == 0); + event.type = SDL_MOUSEMOTION; + event.motion.xrel = 5; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 0); + event.type = SDL_WINDOWEVENT; + event.window.event = SDL_WINDOWEVENT_FOCUS_GAINED; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 0); + event.window.event = SDL_WINDOWEVENT_CLOSE; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 1 && !data[0].connected); + event.window.event = SDL_WINDOWEVENT_FOCUS_GAINED; + input.HandleEvent(event, 7); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 1 && data[0].connected); + + for (int i = 0; i < 70; ++i) { + MouseInputEvent motion{}; + motion.x = i; + MousePublishInput_nid_postfix(motion); + } + Require(sceMouseRead(MOUSE_HANDLE, data, 64) == 64); + Require(data[0].x_axis == 6 && data[63].x_axis == 69); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 0); + Require(sceMouseClose(MOUSE_HANDLE) == MOUSE_OK); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == MOUSE_ERROR_INVALID_HANDLE); + Require(sceMouseClose(MOUSE_HANDLE) == MOUSE_ERROR_INVALID_HANDLE); + MouseOpenParam merged{}; + merged.behaviorFlag = MOUSE_OPEN_PARAM_MERGED; + Require(sceMouseOpen(1, 0, 0, &merged) == MOUSE_HANDLE); + Require(sceMouseRead(MOUSE_HANDLE, data, 1) == 1 && data[0].buttons == 0); + Require(sceMouseClose(MOUSE_HANDLE) == MOUSE_OK); +} diff --git a/core/libs/prx/libSceVideoOut/CMakeLists.txt b/core/libs/prx/libSceVideoOut/CMakeLists.txt index e41cf34bd..e039c0529 100644 --- a/core/libs/prx/libSceVideoOut/CMakeLists.txt +++ b/core/libs/prx/libSceVideoOut/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(libSceVideoOut SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/src/VideoOutDriver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/DisplayWindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/PadInput.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/MouseInput.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/InputMapping.cpp ) @@ -14,7 +15,7 @@ target_include_directories(libSceVideoOut PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/SDL2/include ${CMAKE_SOURCE_DIR}/3rdparty/Vulkan-Headers/include ) -target_link_libraries(libSceVideoOut PRIVATE libSceAgcDriver libScePad libc libkernel SDL2-static) +target_link_libraries(libSceVideoOut PRIVATE libSceAgcDriver libScePad libSceMouse libc libkernel SDL2-static) if(WIN32) target_link_libraries(libSceVideoOut PRIVATE comctl32) endif() diff --git a/core/libs/prx/libSceVideoOut/include/MouseInput.hpp b/core/libs/prx/libSceVideoOut/include/MouseInput.hpp new file mode 100644 index 000000000..56ea31b6d --- /dev/null +++ b/core/libs/prx/libSceVideoOut/include/MouseInput.hpp @@ -0,0 +1,14 @@ +#ifndef CORE_LIBS_PRX_LIBSCEVIDEOOUT_MOUSEINPUT_HPP +#define CORE_LIBS_PRX_LIBSCEVIDEOOUT_MOUSEINPUT_HPP + +#include "SDL_events.h" + +class MouseInput { +public: + void HandleEvent(const SDL_Event& event, unsigned windowId); + +private: + bool focused = true; +}; + +#endif diff --git a/core/libs/prx/libSceVideoOut/src/MouseInput.cpp b/core/libs/prx/libSceVideoOut/src/MouseInput.cpp new file mode 100644 index 000000000..3a5443e6e --- /dev/null +++ b/core/libs/prx/libSceVideoOut/src/MouseInput.cpp @@ -0,0 +1,55 @@ +#include "prx/libSceVideoOut/include/MouseInput.hpp" +#include "prx/libSceMouse/include/MouseState.hpp" + +#include "SDL_mouse.h" + +void MouseInput::HandleEvent(const SDL_Event& event, unsigned windowId) { + MouseInputEvent input{}; + switch (event.type) { + case SDL_MOUSEMOTION: + if (event.motion.windowID != windowId || !focused) return; + input.x = event.motion.xrel; + input.y = event.motion.yrel; + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + if (event.button.windowID != windowId || !focused) return; + switch (event.button.button) { + case SDL_BUTTON_LEFT: input.button = 1; break; + case SDL_BUTTON_RIGHT: input.button = 2; break; + case SDL_BUTTON_MIDDLE: input.button = 4; break; + default: return; + } + input.pressed = event.type == SDL_MOUSEBUTTONDOWN; + break; + case SDL_MOUSEWHEEL: + if (event.wheel.windowID != windowId || !focused) return; + input.wheel = event.wheel.y; + input.tilt = event.wheel.x; + if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) { + input.wheel = -input.wheel; + input.tilt = -input.tilt; + } + if (input.wheel == 0 && input.tilt == 0) return; + break; + case SDL_WINDOWEVENT: + if (event.window.windowID != windowId) return; + if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { + focused = false; + input.resetButtons = true; + } else if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { + focused = true; + input.connectionChange = true; + } else if (event.window.event == SDL_WINDOWEVENT_CLOSE) { + focused = false; + input.connectionChange = true; + input.connected = false; + } else { + return; + } + break; + default: + return; + } + MousePublishInput_nid_postfix(input); +} diff --git a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp index d413eab44..82bc028fc 100644 --- a/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp +++ b/core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp @@ -9,6 +9,7 @@ #include "SDL.h" #include "SDL_vulkan.h" #include "prx/libSceVideoOut/include/PadInput.hpp" +#include "prx/libSceVideoOut/include/MouseInput.hpp" #include "prx/libScePad/include/PadState.hpp" #include "prx/libkernel/Equeue/Equeue.hpp" #include "prx/libkernel/Time/include/Time.hpp" @@ -465,6 +466,7 @@ void VideoOutDriver::presentLoop(std::stop_token token) { std::shared_ptr current; try { PadInput padInput; + MouseInput mouseInput; while (!token.stop_requested()) { { std::unique_lock lock(flipQueue->mutex); @@ -480,6 +482,7 @@ void VideoOutDriver::presentLoop(std::stop_token token) { while (SDL_PollEvent(&event)) { require(event.type != SDL_QUIT, "window was closed"); padInput.HandleEvent(event, window); + if (window.Handle() != nullptr) mouseInput.HandleEvent(event, SDL_GetWindowID(window.Handle())); } padInput.Update(); if (current) {