From 0a5d13baa5f209dff31b57a777fe25810d6f63f1 Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Sat, 19 Oct 2024 04:30:41 -0300 Subject: [PATCH] handle all mouse inputs & ask to capture when first opened --- src/core/libraries/error_codes.h | 7 ++ src/core/libraries/mouse/mouse.cpp | 125 ++++++++++++++++++++++++----- src/core/libraries/mouse/mouse.h | 9 ++- src/input/mouse.cpp | 95 +++++++++++----------- src/input/mouse.h | 28 ++++--- src/sdl_window.cpp | 57 ++++++++++--- 6 files changed, 228 insertions(+), 93 deletions(-) diff --git a/src/core/libraries/error_codes.h b/src/core/libraries/error_codes.h index dae285664..45dcbe87c 100644 --- a/src/core/libraries/error_codes.h +++ b/src/core/libraries/error_codes.h @@ -425,6 +425,13 @@ constexpr int ORBIS_PAD_ERROR_INVALID_REPORT_LENGTH = 0x80920103; constexpr int ORBIS_PAD_ERROR_INVALID_REPORT_ID = 0x80920104; constexpr int ORBIS_PAD_ERROR_SEND_AGAIN = 0x80920105; +// Mouse library +constexpr int ORBIS_MOUSE_ERROR_INVALID_ARG = 0x80DF0001; +constexpr int ORBIS_MOUSE_ERROR_INVALID_HANDLE = 0x80DF0003; +constexpr int ORBIS_MOUSE_ERROR_ALREADY_OPENED = 0x80DF0004; +constexpr int ORBIS_MOUSE_ERROR_NOT_INITIALIZED = 0x80DF0005; +constexpr int ORBIS_MOUSE_ERROR_FATAL = 0x80DF00FF; + // UserService library constexpr int ORBIS_USER_SERVICE_ERROR_INTERNAL = 0x80960001; constexpr int ORBIS_USER_SERVICE_ERROR_NOT_INITIALIZED = 0x80960002; diff --git a/src/core/libraries/mouse/mouse.cpp b/src/core/libraries/mouse/mouse.cpp index b45818317..550acea4c 100644 --- a/src/core/libraries/mouse/mouse.cpp +++ b/src/core/libraries/mouse/mouse.cpp @@ -3,6 +3,7 @@ // Generated By moduleGenerator #include +#include #include #include "common/logging/log.h" #include "core/libraries/error_codes.h" @@ -11,9 +12,31 @@ namespace Libraries::Mouse { -int PS4_SYSV_ABI sceMouseClose() { - LOG_ERROR(Lib_Mouse, "(STUBBED) called"); - return ORBIS_OK; +static bool g_initialized = false; +static bool g_mouse1_open = false; +static bool g_mouse2_open = false; + +constexpr auto MOUSE1_HANDLE = 0xF1; +constexpr auto MOUSE2_HANDLE = 0xF2; + +constexpr auto ORBIS_MOUSE_OPEN_PARAM_NORMAL = 0x00; +constexpr auto ORBIS_MOUSE_OPEN_PARAM_MERGED = 0x01; + +int PS4_SYSV_ABI sceMouseClose(s32 handle) { + LOG_INFO(Lib_Mouse, "called"); + if (!g_initialized) { + return ORBIS_MOUSE_ERROR_NOT_INITIALIZED; + } + if (handle == MOUSE1_HANDLE && g_mouse1_open) { + g_mouse1_open = false; + return ORBIS_OK; + } + if (handle == MOUSE2_HANDLE && g_mouse2_open) { + g_mouse2_open = false; + return ORBIS_OK; + } + + return ORBIS_MOUSE_ERROR_INVALID_HANDLE; } int PS4_SYSV_ABI sceMouseConnectPort() { @@ -48,6 +71,7 @@ int PS4_SYSV_ABI sceMouseGetDeviceInfo() { int PS4_SYSV_ABI sceMouseInit() { LOG_INFO(Lib_Mouse, "called"); + g_initialized = true; return ORBIS_OK; } @@ -57,28 +81,93 @@ int PS4_SYSV_ABI sceMouseMbusInit() { } int PS4_SYSV_ABI sceMouseOpen(s32 userId, s32 type, s32 index, OrbisMouseOpenParam* pParam) { - LOG_INFO(Lib_Mouse, "(DUMMY) called"); - return 2; // dummy + LOG_INFO(Lib_Mouse, "called"); + if (!g_initialized) { + return ORBIS_MOUSE_ERROR_NOT_INITIALIZED; + } + bool merge = pParam != nullptr && (pParam->behaviorFlag & ORBIS_MOUSE_OPEN_PARAM_MERGED) != 0; + + if (merge || index == 0) { + if (g_mouse1_open) { + return ORBIS_PAD_ERROR_ALREADY_OPENED; + } + g_mouse1_open = true; + if (!Common::Singleton::Instance()->m_connected) { + MsgDialog::ShowMsgDialog( + MsgDialog::MsgDialogState(MsgDialog::MsgDialogState::UserState{ + .type = MsgDialog::ButtonType::YESNO, + .msg = "Game wants to use your mouse.\nDo you want to allow it?", + }), + false, [](MsgDialog::DialogResult result) { + if (result.buttonId == MsgDialog::ButtonId::YES) { + auto* mouse = Common::Singleton::Instance(); + mouse->m_connected = true; + } + }); + } + return MOUSE1_HANDLE; + } + if (index == 1) { + if (g_mouse2_open) { + return ORBIS_PAD_ERROR_ALREADY_OPENED; + } + g_mouse2_open = true; + return MOUSE2_HANDLE; + } + return ORBIS_MOUSE_ERROR_INVALID_ARG; } int PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num) { - bool connected = false; - Input::MouseState states[64]; - auto* mouse = Common::Singleton::Instance(); - int ret_num = mouse->ReadStates(states, num, &connected); + LOG_TRACE(Lib_Mouse, "called"); - if (!connected) { - ret_num = 1; + if (!g_initialized) { + return ORBIS_MOUSE_ERROR_NOT_INITIALIZED; } + if (num < 1 || num > 64 || pData == nullptr) { + return ORBIS_MOUSE_ERROR_INVALID_ARG; + } + + auto* mouse = Common::Singleton::Instance(); + + if (handle == MOUSE1_HANDLE) { + if (!g_mouse1_open) { + return ORBIS_MOUSE_ERROR_INVALID_HANDLE; + } + } else if (handle == MOUSE2_HANDLE) { + if (!g_mouse2_open) { + return ORBIS_MOUSE_ERROR_INVALID_HANDLE; + } + // Mouse 2 will never be connected + pData[0] = OrbisMouseData{ + .connected = false, + }; + return 1; + } else { + return ORBIS_MOUSE_ERROR_INVALID_HANDLE; + } + + if (!mouse->m_connected) { + pData[0] = OrbisMouseData{ + .connected = false, + }; + return 1; + } + + Input::MouseState states[64]; + int ret_num = mouse->ReadStates(states, num); + for (int i = 0; i < ret_num; i++) { - pData[i].buttons = states[i].buttonsState; - pData[i].connected = connected; - pData[i].timestamp = states[i].time; - pData[i].xAxis = 0; - pData[i].yAxis = 0; - pData[i].wheel = 0; - pData[i].tilt = 0; + const auto& s = states[i]; + pData[i] = OrbisMouseData{ + .timestamp = s.time, + .connected = true, + .buttons = s.button_state, + .xAxis = s.x_axis, + .yAxis = s.y_axis, + .wheel = s.wheel, + .tilt = s.tilt, + }; } return ret_num; } diff --git a/src/core/libraries/mouse/mouse.h b/src/core/libraries/mouse/mouse.h index a0d276af9..301877de4 100644 --- a/src/core/libraries/mouse/mouse.h +++ b/src/core/libraries/mouse/mouse.h @@ -23,15 +23,18 @@ struct OrbisMouseData { s32 yAxis; s32 wheel; s32 tilt; - u8 reserve[8]; + std::array reserve{}; }; enum OrbisMouseButtonDataOffset { ORBIS_MOUSE_BUTTON_PRIMARY = 0x00000001, - ORBIS_MOUSE_BUTTON_SECONDARY = 0x00000002 + ORBIS_MOUSE_BUTTON_SECONDARY = 0x00000002, + ORBIS_MOUSE_BUTTON_OPTIONAL = 0x00000004, + ORBIS_MOUSE_BUTTON_OPTIONAL2 = 0x00000008, + ORBIS_MOUSE_BUTTON_OPTIONAL3 = 0x00000010, }; -int PS4_SYSV_ABI sceMouseClose(); +int PS4_SYSV_ABI sceMouseClose(s32 handle); int PS4_SYSV_ABI sceMouseConnectPort(); int PS4_SYSV_ABI sceMouseDebugGetDeviceId(); int PS4_SYSV_ABI sceMouseDeviceOpen(); diff --git a/src/input/mouse.cpp b/src/input/mouse.cpp index 6f6527ad7..afc2a8750 100644 --- a/src/input/mouse.cpp +++ b/src/input/mouse.cpp @@ -11,70 +11,71 @@ GameMouse::GameMouse() { m_last_state = MouseState(); } -int GameMouse::ReadStates(MouseState* states, int states_num, bool* isConnected) { +int GameMouse::ReadStates(MouseState* states, int states_num) { std::scoped_lock lock{m_mutex}; - *isConnected = m_connected; + const u32 count = std::min(m_states_num, u32(states_num)); - int ret_num = 0; - - if (m_connected) { - if (m_states_num == 0) { - ret_num = 1; - states[0] = m_last_state; - } else { - for (uint32_t i = 0; i < m_states_num; i++) { - if (ret_num >= states_num) { - break; - } - auto index = (m_first_state + i) % MAX_MOUSE_STATES; - if (!m_private[index].obtained) { - m_private[index].obtained = true; - - states[ret_num++] = m_states[index]; - } - } - } + u32 begin = (m_index - m_states_num + 1) % MAX_MOUSE_STATES; + for (u32 i = 0; i < count; i++) { + u32 idx = (begin + i) % MAX_MOUSE_STATES; + states[i] = m_states[idx]; } - return ret_num; -} - -MouseState GameMouse::GetLastState() const { - if (m_states_num == 0) { - return m_last_state; - } - - auto last = (m_first_state + m_states_num - 1) % MAX_MOUSE_STATES; - - return m_states[last]; + m_states_num -= count; + return static_cast(count); } void GameMouse::AddState(const MouseState& state) { - if (m_states_num >= MAX_MOUSE_STATES) { - m_states_num = MAX_MOUSE_STATES - 1; - m_first_state = (m_first_state + 1) % MAX_MOUSE_STATES; + std::scoped_lock lock{m_mutex}; + + m_index = (m_index + 1) % MAX_MOUSE_STATES; + if (m_states_num < MAX_MOUSE_STATES) { + ++m_states_num; } - - auto index = (m_first_state + m_states_num) % MAX_MOUSE_STATES; - - m_states[index] = state; - m_last_state = state; - m_private[index].obtained = false; - m_states_num++; + m_states[m_index] = state; + m_last_state = MouseState{ + .button_state = state.button_state, + }; } -void GameMouse::CheckButton(int id, u32 button, bool isPressed) { - std::scoped_lock lock{m_mutex}; - auto state = GetLastState(); +void GameMouse::CheckButton(u32 button, bool isPressed) { + if (!m_connected) { + return; + } + MouseState state = m_last_state; state.time = Libraries::Kernel::sceKernelGetProcessTime(); if (isPressed) { - state.buttonsState |= button; + state.button_state |= button; } else { - state.buttonsState &= ~button; + state.button_state &= ~button; } AddState(state); } +void GameMouse::CheckMove(int x, int y) { + if (!m_connected) { + return; + } + MouseState state = m_last_state; + state.time = Libraries::Kernel::sceKernelGetProcessTime(); + state.x_axis = x; + state.y_axis = y; + + AddState(state); +} + +void GameMouse::CheckWheel(int x, int y) { + if (!m_connected) { + return; + } + MouseState state = m_last_state; + state.time = Libraries::Kernel::sceKernelGetProcessTime(); + state.wheel = y; + state.tilt = x; + + AddState(state); +} + }; // namespace Input diff --git a/src/input/mouse.h b/src/input/mouse.h index e5a112cb3..66477b990 100644 --- a/src/input/mouse.h +++ b/src/input/mouse.h @@ -8,8 +8,12 @@ namespace Input { struct MouseState { - u32 buttonsState = 0; u64 time = 0; + u32 button_state = 0; + s32 x_axis = 0; + s32 y_axis = 0; + s32 wheel = 0; + s32 tilt = 0; }; constexpr u32 MAX_MOUSE_STATES = 64; @@ -19,25 +23,23 @@ public: GameMouse(); virtual ~GameMouse() = default; - int ReadStates(MouseState* states, int states_num, bool* isConnected); - MouseState GetLastState() const; - void CheckButton(int id, u32 button, bool isPressed); - void AddState(const MouseState& state); + int ReadStates(MouseState* states, int states_num); + + void CheckButton(u32 button, bool isPressed); + void CheckMove(int x, int y); + void CheckWheel(int x, int y); + + bool m_connected = false; + float speed = 1.0f; private: - struct StateInternal { - bool obtained = false; - }; + void AddState(const MouseState& state); std::mutex m_mutex; - bool m_connected = true; MouseState m_last_state; - int m_connected_count = 0; u32 m_states_num = 0; - u32 m_first_state = 0; + u32 m_index = 0; std::array m_states; - std::array m_private; - }; } // namespace Input \ No newline at end of file diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index bd866037a..d478fae1b 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -118,8 +118,10 @@ void WindowSDL::waitEvent() { is_open = false; break; + case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_WHEEL: onMouseAction(&event); break; default: @@ -127,19 +129,50 @@ void WindowSDL::waitEvent() { } } void WindowSDL::onMouseAction(const SDL_Event* event) { - auto* mouse = Common::Singleton::Instance(); - using Libraries::Mouse::OrbisMouseButtonDataOffset; - u32 button = 0; - switch (event->button.button) { - case SDL_BUTTON_LEFT: - button = OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_PRIMARY; - break; - case SDL_BUTTON_RIGHT: - button = OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_SECONDARY; - break; + auto& mouse = *Common::Singleton::Instance(); + + if (mouse.m_connected && !is_capturing_mouse) { + SDL_SetWindowRelativeMouseMode(window, true); + is_capturing_mouse = true; + } else if (!mouse.m_connected && is_capturing_mouse) { + SDL_SetWindowRelativeMouseMode(window, false); + is_capturing_mouse = false; } - if (button != 0) { - mouse->CheckButton(0, button, event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); + + bool pressed_down = false; + switch (event->type) { + case SDL_EVENT_MOUSE_BUTTON_DOWN: + pressed_down = true; + [[fallthrough]]; + case SDL_EVENT_MOUSE_BUTTON_UP: { + using Libraries::Mouse::OrbisMouseButtonDataOffset; + + auto btn = event->button.button; + if (btn < 1 || btn > 5) { // 1..5 range + return; + } + constexpr static std::array sdl_to_orbis_buttons = { + static_cast(0x00), + OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_PRIMARY, + OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_OPTIONAL, + OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_SECONDARY, + OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_OPTIONAL2, + OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_OPTIONAL3, + }; + mouse.CheckButton(sdl_to_orbis_buttons[btn], pressed_down); + } break; + case SDL_EVENT_MOUSE_MOTION: { + const auto x = static_cast(event->motion.xrel * mouse.speed); + const auto y = static_cast(event->motion.yrel * mouse.speed); + mouse.CheckMove(x, y); + } break; + case SDL_EVENT_MOUSE_WHEEL: { + const auto x = static_cast(event->wheel.x); + const auto y = static_cast(event->wheel.y); + mouse.CheckWheel(x, y); + } break; + default: + break; } } void WindowSDL::onResize() {