From b1f764dae5fa63b9d2365bb49705874ec5527be6 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 28 Aug 2024 19:02:13 +0300 Subject: [PATCH 1/5] adding mouse module (initial) --- CMakeLists.txt | 4 +- src/common/logging/filter.cpp | 6 ++ src/common/logging/types.h | 1 + src/core/libraries/mouse/mouse.cpp | 99 ++++++++++++++++++++++++++++++ src/core/libraries/mouse/mouse.h | 29 +++++++++ 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/core/libraries/mouse/mouse.cpp create mode 100644 src/core/libraries/mouse/mouse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 27b11aa288..2bcd9c8868 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,7 +283,7 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp src/core/libraries/ngs2/ngs2_impl.cpp src/core/libraries/ngs2/ngs2_impl.h src/core/libraries/ajm/ajm_error.h - src/core/libraries/audio3d/audio3d.cpp + src/core/libraries/audio3d/audio3d.cpp src/core/libraries/audio3d/audio3d.h src/core/libraries/audio3d/audio3d_error.h src/core/libraries/audio3d/audio3d_impl.cpp @@ -296,6 +296,8 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp src/core/libraries/remote_play/remoteplay.h src/core/libraries/share_play/shareplay.cpp src/core/libraries/share_play/shareplay.h + src/core/libraries/mouse/mouse.cpp + src/core/libraries/mouse/mouse.h ) set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 051bbd79e5..1055f0297b 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -118,6 +118,12 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, GameLiveStreaming) \ SUB(Lib, Remoteplay) \ SUB(Lib, SharePlay) \ + SUB(LibSUB(Lib, Fiber) \ + SUB(Lib, Mouse) \ + SUB(Lib, Ime) \ + SUB(Lib, GameLiveStreaming) \ + SUB(Lib, Remoteplay) \ + SUB(Lib, SharePlay) \ SUB(Lib, Fiber) \ CLS(Frontend) \ CLS(Render) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 39319d0dc2..b1a03e0478 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -86,6 +86,7 @@ enum class Class : u8 { Lib_Remoteplay, ///< The LibSceRemotePlay implementation Lib_SharePlay, ///< The LibSceSharePlay implemenation Lib_Fiber, ///< The LibSceFiber implementation. + Lib_Mouse, ///< The LibSceMouse implementation Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/mouse/mouse.cpp b/src/core/libraries/mouse/mouse.cpp new file mode 100644 index 0000000000..2669426fb4 --- /dev/null +++ b/src/core/libraries/mouse/mouse.cpp @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// Generated By moduleGenerator +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "mouse.h" + +namespace Libraries::Mouse { + +int PS4_SYSV_ABI sceMouseClose() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseConnectPort() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseDebugGetDeviceId() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseDeviceOpen() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseDisconnectDevice() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseDisconnectPort() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseGetDeviceInfo() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseInit() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseMbusInit() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseOpen() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseRead() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseSetHandType() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseSetPointerSpeed() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseSetProcessPrivilege() { + LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + return ORBIS_OK; +} + +void RegisterlibSceMouse(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("cAnT0Rw-IwU", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseClose); + LIB_FUNCTION("Ymyy1HSSJLQ", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseConnectPort); + LIB_FUNCTION("BRXOoXQtb+k", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDebugGetDeviceId); + LIB_FUNCTION("WiGKINCZWkc", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDeviceOpen); + LIB_FUNCTION("eDQTFHbgeTU", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDisconnectDevice); + LIB_FUNCTION("jJP1vYMEPd4", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDisconnectPort); + LIB_FUNCTION("QA9Qupz3Zjw", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseGetDeviceInfo); + LIB_FUNCTION("Qs0wWulgl7U", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseInit); + LIB_FUNCTION("1FeceR5YhAo", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseMbusInit); + LIB_FUNCTION("RaqxZIf6DvE", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseOpen); + LIB_FUNCTION("x8qnXqh-tiM", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseRead); + LIB_FUNCTION("crkFfp-cmFo", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseSetHandType); + LIB_FUNCTION("ghLUU2Z5Lcg", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseSetPointerSpeed); + LIB_FUNCTION("6aANndpS0Wo", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseSetProcessPrivilege); +}; + +} // namespace Libraries::Mouse \ No newline at end of file diff --git a/src/core/libraries/mouse/mouse.h b/src/core/libraries/mouse/mouse.h new file mode 100644 index 0000000000..8264f62e05 --- /dev/null +++ b/src/core/libraries/mouse/mouse.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once +#include "common/types.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::Mouse { + +int PS4_SYSV_ABI sceMouseClose(); +int PS4_SYSV_ABI sceMouseConnectPort(); +int PS4_SYSV_ABI sceMouseDebugGetDeviceId(); +int PS4_SYSV_ABI sceMouseDeviceOpen(); +int PS4_SYSV_ABI sceMouseDisconnectDevice(); +int PS4_SYSV_ABI sceMouseDisconnectPort(); +int PS4_SYSV_ABI sceMouseGetDeviceInfo(); +int PS4_SYSV_ABI sceMouseInit(); +int PS4_SYSV_ABI sceMouseMbusInit(); +int PS4_SYSV_ABI sceMouseOpen(); +int PS4_SYSV_ABI sceMouseRead(); +int PS4_SYSV_ABI sceMouseSetHandType(); +int PS4_SYSV_ABI sceMouseSetPointerSpeed(); +int PS4_SYSV_ABI sceMouseSetProcessPrivilege(); + +void RegisterlibSceMouse(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Mouse \ No newline at end of file From bdf31fac3c5133f9dd1a52d984795033c60abcad Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 28 Aug 2024 20:47:08 +0300 Subject: [PATCH 2/5] more work in mouse lib --- CMakeLists.txt | 2 + src/core/libraries/libs.cpp | 2 + src/core/libraries/mouse/mouse.cpp | 33 +++++++++--- src/core/libraries/mouse/mouse.h | 25 +++++++++- src/input/mouse.cpp | 80 ++++++++++++++++++++++++++++++ src/input/mouse.h | 43 ++++++++++++++++ src/sdl_window.cpp | 25 +++++++++- src/sdl_window.h | 2 +- 8 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 src/input/mouse.cpp create mode 100644 src/input/mouse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bcd9c8868..7807ff339c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -693,6 +693,8 @@ set(IMGUI src/imgui/imgui_config.h set(INPUT src/input/controller.cpp src/input/controller.h + src/input/mouse.cpp + src/input/mouse.h ) set(EMULATOR src/emulator.cpp diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index caa254fd84..c6c9724e95 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -42,6 +42,7 @@ #include "core/libraries/system/userservice.h" #include "core/libraries/usbd/usbd.h" #include "core/libraries/videoout/video_out.h" +#include "src/core/libraries/mouse/mouse.h" namespace Libraries { @@ -85,6 +86,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::GameLiveStreaming::RegisterlibSceGameLiveStreaming(sym); Libraries::SharePlay::RegisterlibSceSharePlay(sym); Libraries::Remoteplay::RegisterlibSceRemoteplay(sym); + Libraries::Mouse::RegisterlibSceMouse(sym); } } // namespace Libraries diff --git a/src/core/libraries/mouse/mouse.cpp b/src/core/libraries/mouse/mouse.cpp index 2669426fb4..428ee4e072 100644 --- a/src/core/libraries/mouse/mouse.cpp +++ b/src/core/libraries/mouse/mouse.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Generated By moduleGenerator +#include +#include #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" @@ -45,7 +47,7 @@ int PS4_SYSV_ABI sceMouseGetDeviceInfo() { } int PS4_SYSV_ABI sceMouseInit() { - LOG_ERROR(Lib_Mouse, "(STUBBED) called"); + LOG_INFO(Lib_Mouse, "called"); return ORBIS_OK; } @@ -54,14 +56,31 @@ int PS4_SYSV_ABI sceMouseMbusInit() { return ORBIS_OK; } -int PS4_SYSV_ABI sceMouseOpen() { - LOG_ERROR(Lib_Mouse, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceMouseOpen(s32 userId, s32 type, s32 index, OrbisMouseOpenParam* pParam) { + LOG_INFO(Lib_Mouse, "(DUMMY) called"); + return 2; // dummy } -int PS4_SYSV_ABI sceMouseRead() { - LOG_ERROR(Lib_Mouse, "(STUBBED) called"); - return ORBIS_OK; +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); + + if (!connected) { + ret_num = 1; + } + + for (int i = 0; i < ret_num; i++) { + pData[i].buttons = states[i].buttonsState; + pData[i].connected = true; + pData[i].timestamp = states[i].time; + pData[i].xAxis = 0; + pData[i].yAxis = 0; + pData[i].wheel = 0; + pData[i].tilt = 0; + } + return ret_num; } int PS4_SYSV_ABI sceMouseSetHandType() { diff --git a/src/core/libraries/mouse/mouse.h b/src/core/libraries/mouse/mouse.h index 8264f62e05..a0d276af99 100644 --- a/src/core/libraries/mouse/mouse.h +++ b/src/core/libraries/mouse/mouse.h @@ -10,6 +10,27 @@ class SymbolsResolver; namespace Libraries::Mouse { +struct OrbisMouseOpenParam { + u8 behaviorFlag; + u8 reserve[7]; +}; + +struct OrbisMouseData { + u64 timestamp; + bool connected; + u32 buttons; + s32 xAxis; + s32 yAxis; + s32 wheel; + s32 tilt; + u8 reserve[8]; +}; + +enum OrbisMouseButtonDataOffset { + ORBIS_MOUSE_BUTTON_PRIMARY = 0x00000001, + ORBIS_MOUSE_BUTTON_SECONDARY = 0x00000002 +}; + int PS4_SYSV_ABI sceMouseClose(); int PS4_SYSV_ABI sceMouseConnectPort(); int PS4_SYSV_ABI sceMouseDebugGetDeviceId(); @@ -19,8 +40,8 @@ int PS4_SYSV_ABI sceMouseDisconnectPort(); int PS4_SYSV_ABI sceMouseGetDeviceInfo(); int PS4_SYSV_ABI sceMouseInit(); int PS4_SYSV_ABI sceMouseMbusInit(); -int PS4_SYSV_ABI sceMouseOpen(); -int PS4_SYSV_ABI sceMouseRead(); +int PS4_SYSV_ABI sceMouseOpen(s32 userId, s32 type, s32 index, OrbisMouseOpenParam* pParam); +int PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num); int PS4_SYSV_ABI sceMouseSetHandType(); int PS4_SYSV_ABI sceMouseSetPointerSpeed(); int PS4_SYSV_ABI sceMouseSetProcessPrivilege(); diff --git a/src/input/mouse.cpp b/src/input/mouse.cpp new file mode 100644 index 0000000000..6f6527ad76 --- /dev/null +++ b/src/input/mouse.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/libraries/kernel/time_management.h" +#include "input/mouse.h" + +namespace Input { + +GameMouse::GameMouse() { + m_states_num = 0; + m_last_state = MouseState(); +} + +int GameMouse::ReadStates(MouseState* states, int states_num, bool* isConnected) { + std::scoped_lock lock{m_mutex}; + + *isConnected = m_connected; + + 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]; + } + } + } + } + + 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]; +} + +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; + } + + 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++; +} + +void GameMouse::CheckButton(int id, u32 button, bool isPressed) { + std::scoped_lock lock{m_mutex}; + auto state = GetLastState(); + state.time = Libraries::Kernel::sceKernelGetProcessTime(); + if (isPressed) { + state.buttonsState |= button; + } else { + state.buttonsState &= ~button; + } + + AddState(state); +} + +}; // namespace Input diff --git a/src/input/mouse.h b/src/input/mouse.h new file mode 100644 index 0000000000..e5a112cb33 --- /dev/null +++ b/src/input/mouse.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once +#include +#include "common/types.h" + +namespace Input { + +struct MouseState { + u32 buttonsState = 0; + u64 time = 0; +}; + +constexpr u32 MAX_MOUSE_STATES = 64; + +class GameMouse { +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); + +private: + struct StateInternal { + bool obtained = false; + }; + + 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; + 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 bf29b37f68..bd866037ab 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -17,6 +17,9 @@ #ifdef __APPLE__ #include #endif +#include +#include +#include namespace Frontend { @@ -114,11 +117,31 @@ void WindowSDL::waitEvent() { case SDL_EVENT_QUIT: is_open = false; break; + + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + onMouseAction(&event); + break; default: break; } } - +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; + } + if (button != 0) { + mouse->CheckButton(0, button, event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); + } +} void WindowSDL::onResize() { SDL_GetWindowSizeInPixels(window, &width, &height); ImGui::Core::OnResize(); diff --git a/src/sdl_window.h b/src/sdl_window.h index 2a5aeb38c0..4bcaf46d12 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -72,7 +72,7 @@ class WindowSDL { void onResize(); void onKeyPress(const SDL_Event* event); void onGamepadEvent(const SDL_Event* event); - + void onMouseAction(const SDL_Event* event); int sdlGamepadToOrbisButton(u8 button); private: From 2ee4e87cf77753cdf836c11aca10d87e7b8a4cf3 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 28 Aug 2024 21:02:12 +0300 Subject: [PATCH 3/5] fixed a test --- src/core/libraries/mouse/mouse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/mouse/mouse.cpp b/src/core/libraries/mouse/mouse.cpp index 428ee4e072..b45818317a 100644 --- a/src/core/libraries/mouse/mouse.cpp +++ b/src/core/libraries/mouse/mouse.cpp @@ -73,7 +73,7 @@ int PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num) { for (int i = 0; i < ret_num; i++) { pData[i].buttons = states[i].buttonsState; - pData[i].connected = true; + pData[i].connected = connected; pData[i].timestamp = states[i].time; pData[i].xAxis = 0; pData[i].yAxis = 0; From 92b990346766a764f6b8953aac1e68e277e4f64b Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 17 Oct 2024 15:12:06 +0300 Subject: [PATCH 4/5] fix filter --- src/common/logging/filter.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 1055f0297b..bda7f00d62 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -118,13 +118,8 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, GameLiveStreaming) \ SUB(Lib, Remoteplay) \ SUB(Lib, SharePlay) \ - SUB(LibSUB(Lib, Fiber) \ - SUB(Lib, Mouse) \ - SUB(Lib, Ime) \ - SUB(Lib, GameLiveStreaming) \ - SUB(Lib, Remoteplay) \ - SUB(Lib, SharePlay) \ SUB(Lib, Fiber) \ + SUB(Lib, Mouse) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ From 8dc956a476910c6661b7ffff36679f35cf899242 Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Sat, 19 Oct 2024 04:45:31 -0300 Subject: [PATCH 5/5] More Lib mouse (#1414) * system/msgdialog: callback available to be used by host * sdl window: mouse capture var * lib/pad: basic special pad impl scaffold & steering wheel (config specialPadClass set to 6 is required) * handle all mouse inputs & ask to capture when first opened --- src/core/libraries/error_codes.h | 7 + src/core/libraries/mouse/mouse.cpp | 123 +++++- src/core/libraries/mouse/mouse.h | 9 +- src/core/libraries/pad/pad.cpp | 446 +++++++++++++++------ src/core/libraries/pad/pad.h | 6 + src/core/libraries/system/msgdialog_ui.cpp | 37 +- src/core/libraries/system/msgdialog_ui.h | 22 +- src/imgui/renderer/imgui_core.cpp | 2 +- src/imgui/renderer/imgui_impl_sdl3.cpp | 20 +- src/imgui/renderer/imgui_impl_sdl3.h | 6 +- src/input/mouse.cpp | 93 ++--- src/input/mouse.h | 28 +- src/sdl_window.cpp | 57 ++- src/sdl_window.h | 6 + 14 files changed, 635 insertions(+), 227 deletions(-) diff --git a/src/core/libraries/error_codes.h b/src/core/libraries/error_codes.h index dae2856644..45dcbe87c6 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 b45818317a..550acea4c6 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]; + LOG_TRACE(Lib_Mouse, "called"); + + 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(); - int ret_num = mouse->ReadStates(states, num, &connected); - if (!connected) { - ret_num = 1; + 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 a0d276af99..301877de46 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/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index d786647c2b..43a18da84a 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -12,8 +12,62 @@ namespace Libraries::Pad { +static bool g_initialized = false; + +static bool g_pad_standard_connected = false; +static bool g_pad_standard_special_connected = false; + +constexpr auto PAD_STANDARD_HANDLER = 0xBC1; +constexpr auto PAD_SPECIAL_HANDLER = 0xBC2; + +void OrbisPadData::CopyFromState(const Input::State& state) { + buttons = state.buttonsState; + leftStick.x = state.axes[static_cast(Input::Axis::LeftX)]; + leftStick.y = state.axes[static_cast(Input::Axis::LeftY)]; + rightStick.x = state.axes[static_cast(Input::Axis::RightX)]; + rightStick.y = state.axes[static_cast(Input::Axis::RightY)]; + analogButtons.l2 = state.axes[static_cast(Input::Axis::TriggerLeft)]; + analogButtons.r2 = state.axes[static_cast(Input::Axis::TriggerRight)]; + orientation.x = 0.0f; + orientation.y = 0.0f; + orientation.z = 0.0f; + orientation.w = 1.0f; + acceleration.x = 0.0f; + acceleration.y = 0.0f; + acceleration.z = 0.0f; + angularVelocity.x = 0.0f; + angularVelocity.y = 0.0f; + angularVelocity.z = 0.0f; + touchData.touchNum = (state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0); + touchData.touch[0].x = state.touchpad[0].x; + touchData.touch[0].y = state.touchpad[0].y; + touchData.touch[0].id = 1; + touchData.touch[1].x = state.touchpad[1].x; + touchData.touch[1].y = state.touchpad[1].y; + touchData.touch[1].id = 2; + connected = true; + timestamp = state.time; + connectedCount = 1; + deviceUniqueDataLen = 0; +} + int PS4_SYSV_ABI scePadClose(s32 handle) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); + LOG_DEBUG(Lib_Pad, "called handle = {}", handle); + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; + } + if (handle == PAD_STANDARD_HANDLER) { + if (!g_pad_standard_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + g_pad_standard_connected = false; + } + if (handle == PAD_SPECIAL_HANDLER) { + if (!g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + g_pad_standard_special_connected = false; + } return ORBIS_OK; } @@ -24,16 +78,135 @@ int PS4_SYSV_ABI scePadConnectPort() { int PS4_SYSV_ABI scePadDeviceClassGetExtendedInformation( s32 handle, OrbisPadDeviceClassExtendedInformation* pExtInfo) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); - if (Config::getUseSpecialPad()) { + LOG_DEBUG(Lib_Pad, "called handle = {}", handle); + + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; + } + + if (pExtInfo == nullptr) { + return ORBIS_PAD_ERROR_INVALID_ARG; + } + + if (handle == PAD_STANDARD_HANDLER) { + if (!g_pad_standard_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + pExtInfo->deviceClass = ORBIS_PAD_DEVICE_CLASS_STANDARD; + return ORBIS_OK; + } + if (handle == PAD_SPECIAL_HANDLER) { + if (!g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } pExtInfo->deviceClass = (OrbisPadDeviceClass)Config::getSpecialPadClass(); + switch (pExtInfo->deviceClass) { + case ORBIS_PAD_DEVICE_CLASS_STEERING_WHEEL: { + auto& data = pExtInfo->classData.steeringWheel; + data.maxPhysicalWheelAngle = 360; + data.capability = 0b1110; // Handbrake, Shift, 3 pedals + } break; + default: + memset(pExtInfo->classData.data, 0, sizeof(pExtInfo->classData.data)); + break; + } + return ORBIS_OK; } - return ORBIS_OK; + + return ORBIS_PAD_ERROR_INVALID_HANDLE; } int PS4_SYSV_ABI scePadDeviceClassParseData(s32 handle, const OrbisPadData* pData, OrbisPadDeviceClassData* pDeviceClassData) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); + LOG_TRACE(Lib_Pad, "called handle = {}", handle); + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; + } + if (pData == nullptr || pDeviceClassData == nullptr) { + return ORBIS_PAD_ERROR_INVALID_ARG; + } + + if (handle == PAD_STANDARD_HANDLER) { + if (!g_pad_standard_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + pDeviceClassData->deviceClass = ORBIS_PAD_DEVICE_CLASS_STANDARD; + return ORBIS_OK; + } + + if (handle == PAD_SPECIAL_HANDLER) { + if (!g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + auto pad_class = (OrbisPadDeviceClass)Config::getSpecialPadClass(); + pDeviceClassData->deviceClass = pad_class; + switch (pad_class) { + case ORBIS_PAD_DEVICE_CLASS_GUITAR: { + LOG_ERROR(Lib_Pad, "(STUBBED) guitar not implemented"); + auto& data = pDeviceClassData->classData.guitar; + // TODO implement guitar + } break; + case ORBIS_PAD_DEVICE_CLASS_DRUM: { + LOG_ERROR(Lib_Pad, "(STUBBED) drum not implemented"); + auto& data = pDeviceClassData->classData.drum; + // TODO implement drum + } break; + case ORBIS_PAD_DEVICE_CLASS_STEERING_WHEEL: { + auto& data = pDeviceClassData->classData.steeringWheel; + // TODO proper implement steering wheel + auto& left_stick = pData->leftStick.x; + data.steeringWheelAngle = static_cast(left_stick - 0x7F) / 127.0f * 180.0f; + if (data.steeringWheelAngle == 0.0) { + data.steeringWheel = 0x80; + } else { + data.steeringWheel = + static_cast((data.steeringWheelAngle / 360.0f + 0.5f) * 0xFFFF); + } + data.acceleratorPedal = static_cast(pData->analogButtons.r2) * 0x102; + data.brakePedal = static_cast(pData->analogButtons.l2) * 0x102; + data.clutchPedal = pData->buttons & ORBIS_PAD_BUTTON_L1 ? 0xFFFF : 0x0000; + data.handBrake = pData->buttons & ORBIS_PAD_BUTTON_R1 ? 0xFFFF : 0x0000; + + static int gear = 1; + static bool switch_gear_up_pressed_last = false; + static bool switch_gear_down_pressed_last = false; + bool switch_gear_up_pressed = pData->buttons & ORBIS_PAD_BUTTON_SQUARE; + bool switch_gear_down_pressed = pData->buttons & ORBIS_PAD_BUTTON_CROSS; + if (switch_gear_up_pressed != switch_gear_up_pressed_last) { + switch_gear_up_pressed_last = switch_gear_up_pressed; + if (switch_gear_up_pressed) { + if (gear < 7) { + ++gear; + } + } + } + if (switch_gear_down_pressed != switch_gear_down_pressed_last) { + switch_gear_down_pressed_last = switch_gear_down_pressed; + if (switch_gear_down_pressed) { + if (gear > 0) { + --gear; + } + } + } + + if (gear == 0) { + data.gear = 1 << 7; + } else { + data.gear = 1 << (gear - 1); + } + } break; + case ORBIS_PAD_DEVICE_CLASS_FLIGHT_STICK: { + LOG_ERROR(Lib_Pad, "(STUBBED) flight stick not implemented"); + auto& data = pDeviceClassData->classData.flightStick; + // TODO implement flight stick + } break; + default: + pDeviceClassData->bDataValid = false; + break; + } + return ORBIS_OK; + } + return ORBIS_OK; } @@ -89,32 +262,39 @@ int PS4_SYSV_ABI scePadGetCapability() { int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerInformation* pInfo) { LOG_DEBUG(Lib_Pad, "called handle = {}", handle); - if (handle < 0) { - pInfo->touchPadInfo.pixelDensity = 1; - pInfo->touchPadInfo.resolution.x = 1920; - pInfo->touchPadInfo.resolution.y = 950; - pInfo->stickInfo.deadZoneLeft = 2; - pInfo->stickInfo.deadZoneRight = 2; - pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD; - pInfo->connectedCount = 1; - pInfo->connected = false; - pInfo->deviceClass = ORBIS_PAD_DEVICE_CLASS_STANDARD; - return SCE_OK; + + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; + } + + if (handle == PAD_STANDARD_HANDLER) { + if (!g_pad_standard_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + } else if (handle == PAD_SPECIAL_HANDLER) { + if (!g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + } else { + return ORBIS_PAD_ERROR_INVALID_HANDLE; } + pInfo->touchPadInfo.pixelDensity = 1; pInfo->touchPadInfo.resolution.x = 1920; pInfo->touchPadInfo.resolution.y = 950; pInfo->stickInfo.deadZoneLeft = 2; pInfo->stickInfo.deadZoneRight = 2; - pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD; + pInfo->connectionType = 0; // Local connection pInfo->connectedCount = 1; pInfo->connected = true; - pInfo->deviceClass = ORBIS_PAD_DEVICE_CLASS_STANDARD; - if (Config::getUseSpecialPad()) { - pInfo->connectionType = ORBIS_PAD_PORT_TYPE_SPECIAL; + if (handle == PAD_STANDARD_HANDLER) { + pInfo->deviceClass = ORBIS_PAD_DEVICE_CLASS_STANDARD; + } else if (handle == PAD_SPECIAL_HANDLER) { pInfo->deviceClass = (OrbisPadDeviceClass)Config::getSpecialPadClass(); + } else { + UNREACHABLE(); } - return SCE_OK; + return ORBIS_OK; } int PS4_SYSV_ABI scePadGetDataInternal() { @@ -134,7 +314,7 @@ int PS4_SYSV_ABI scePadGetDeviceInfo() { int PS4_SYSV_ABI scePadGetExtControllerInformation(s32 handle, OrbisPadExtendedControllerInformation* pInfo) { - LOG_INFO(Lib_Pad, "called handle = {}", handle); + LOG_DEBUG(Lib_Pad, "called handle = {}", handle); pInfo->padType1 = 0; pInfo->padType2 = 0; @@ -200,7 +380,8 @@ int PS4_SYSV_ABI scePadGetVersionInfo() { } int PS4_SYSV_ABI scePadInit() { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); + LOG_DEBUG(Lib_Pad, "called"); + g_initialized = true; return ORBIS_OK; } @@ -245,28 +426,40 @@ int PS4_SYSV_ABI scePadMbusTerm() { } int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenParam* pParam) { - LOG_INFO(Lib_Pad, "(DUMMY) called user_id = {} type = {} index = {}", userId, type, index); - if (Config::getUseSpecialPad()) { - if (type != ORBIS_PAD_PORT_TYPE_SPECIAL) - return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; - } else { - if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL) + LOG_DEBUG(Lib_Pad, "Called user_id = {} type = {} index = {}", userId, + type == ORBIS_PAD_PORT_TYPE_STANDARD ? "standard" + : type == ORBIS_PAD_PORT_TYPE_SPECIAL ? "special" + : "unknown", + index); + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; + } + if (type == ORBIS_PAD_PORT_TYPE_STANDARD) { + if (g_pad_standard_connected) { + return ORBIS_PAD_ERROR_ALREADY_OPENED; + } + g_pad_standard_connected = true; + return PAD_STANDARD_HANDLER; + } + + if (type == ORBIS_PAD_PORT_TYPE_SPECIAL) { + if (!Config::getUseSpecialPad()) { return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; + } + if (g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_ALREADY_OPENED; + } + g_pad_standard_special_connected = true; + return PAD_SPECIAL_HANDLER; } - return 1; // dummy + + return ORBIS_PAD_ERROR_INVALID_ARG; } int PS4_SYSV_ABI scePadOpenExt(s32 userId, s32 type, s32 index, const OrbisPadOpenExtParam* pParam) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); - if (Config::getUseSpecialPad()) { - if (type != ORBIS_PAD_PORT_TYPE_SPECIAL) - return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; - } else { - if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL) - return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; - } - return 1; // dummy + LOG_DEBUG(Lib_Pad, "Redirecting call to scePadOpen"); + return scePadOpen(userId, type, index, nullptr); } int PS4_SYSV_ABI scePadOpenExt2() { @@ -280,49 +473,80 @@ int PS4_SYSV_ABI scePadOutputReport() { } int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) { - int connected_count = 0; - bool connected = false; - Input::State states[64]; - auto* controller = Common::Singleton::Instance(); - int ret_num = controller->ReadStates(states, num, &connected, &connected_count); - - if (!connected) { - ret_num = 1; + LOG_TRACE(Lib_Pad, "called handle = {} num = {}", handle, num); + + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; } - for (int i = 0; i < ret_num; i++) { - pData[i].buttons = states[i].buttonsState; - pData[i].leftStick.x = states[i].axes[static_cast(Input::Axis::LeftX)]; - pData[i].leftStick.y = states[i].axes[static_cast(Input::Axis::LeftY)]; - pData[i].rightStick.x = states[i].axes[static_cast(Input::Axis::RightX)]; - pData[i].rightStick.y = states[i].axes[static_cast(Input::Axis::RightY)]; - pData[i].analogButtons.l2 = states[i].axes[static_cast(Input::Axis::TriggerLeft)]; - pData[i].analogButtons.r2 = states[i].axes[static_cast(Input::Axis::TriggerRight)]; - pData[i].orientation.x = 0.0f; - pData[i].orientation.y = 0.0f; - pData[i].orientation.z = 0.0f; - pData[i].orientation.w = 1.0f; - pData[i].acceleration.x = 0.0f; - pData[i].acceleration.y = 0.0f; - pData[i].acceleration.z = 0.0f; - pData[i].angularVelocity.x = 0.0f; - pData[i].angularVelocity.y = 0.0f; - pData[i].angularVelocity.z = 0.0f; - pData[i].touchData.touchNum = - (states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0); - pData[i].touchData.touch[0].x = states[i].touchpad[0].x; - pData[i].touchData.touch[0].y = states[i].touchpad[0].y; - pData[i].touchData.touch[0].id = 1; - pData[i].touchData.touch[1].x = states[i].touchpad[1].x; - pData[i].touchData.touch[1].y = states[i].touchpad[1].y; - pData[i].touchData.touch[1].id = 2; - pData[i].connected = connected; - pData[i].timestamp = states[i].time; - pData[i].connectedCount = connected_count; - pData[i].deviceUniqueDataLen = 0; + if (num < 1 || num > 64) { + return ORBIS_PAD_ERROR_INVALID_ARG; } - return ret_num; + // Hack to copy state between pads + static bool connected = false; + static std::array states; + static int state_count = 0; + static bool has_std_data = false; + static bool has_special_data = false; + + if (handle == PAD_STANDARD_HANDLER) { + if (!g_pad_standard_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + + if (!has_special_data) { + int connected_count = 0; + auto* controller = Common::Singleton::Instance(); + state_count = controller->ReadStates(states.data(), num, &connected, &connected_count); + has_std_data = true; + } else { + has_special_data = false; + } + + if (!connected) { + pData[0] = OrbisPadData{ + .connected = false, + }; + return 1; + } + + for (int i = 0; i < state_count; i++) { + pData[i].CopyFromState(states[i]); + } + + return state_count; + } + + if (handle == PAD_SPECIAL_HANDLER) { + if (!g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + + if (!has_std_data) { + int connected_count = 0; + auto* controller = Common::Singleton::Instance(); + state_count = controller->ReadStates(states.data(), num, &connected, &connected_count); + has_special_data = true; + } else { + has_std_data = false; + } + + if (!connected) { + pData[0] = OrbisPadData{ + .connected = false, + }; + return 1; + } + + for (int i = 0; i < state_count; i++) { + pData[i].CopyFromState(states[i]); + } + + return state_count; + } + + return ORBIS_PAD_ERROR_INVALID_HANDLE; } int PS4_SYSV_ABI scePadReadBlasterForTracker() { @@ -346,42 +570,36 @@ int PS4_SYSV_ABI scePadReadHistory() { } int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) { - auto* controller = Common::Singleton::Instance(); - int connectedCount = 0; - bool isConnected = false; - Input::State state; - controller->ReadState(&state, &isConnected, &connectedCount); - pData->buttons = state.buttonsState; - pData->leftStick.x = state.axes[static_cast(Input::Axis::LeftX)]; - pData->leftStick.y = state.axes[static_cast(Input::Axis::LeftY)]; - pData->rightStick.x = state.axes[static_cast(Input::Axis::RightX)]; - pData->rightStick.y = state.axes[static_cast(Input::Axis::RightY)]; - pData->analogButtons.l2 = state.axes[static_cast(Input::Axis::TriggerLeft)]; - pData->analogButtons.r2 = state.axes[static_cast(Input::Axis::TriggerRight)]; - pData->orientation.x = 0; - pData->orientation.y = 0; - pData->orientation.z = 0; - pData->orientation.w = 1; - pData->acceleration.x = 0.0f; - pData->acceleration.y = 0.0f; - pData->acceleration.z = 0.0f; - pData->angularVelocity.x = 0.0f; - pData->angularVelocity.y = 0.0f; - pData->angularVelocity.z = 0.0f; - pData->touchData.touchNum = - (state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0); - pData->touchData.touch[0].x = state.touchpad[0].x; - pData->touchData.touch[0].y = state.touchpad[0].y; - pData->touchData.touch[0].id = 1; - pData->touchData.touch[1].x = state.touchpad[1].x; - pData->touchData.touch[1].y = state.touchpad[1].y; - pData->touchData.touch[1].id = 2; - pData->timestamp = state.time; - pData->connected = true; // isConnected; //TODO fix me proper - pData->connectedCount = 1; // connectedCount; - pData->deviceUniqueDataLen = 0; - - return SCE_OK; + LOG_TRACE(Lib_Pad, "called handle = {}", handle); + + if (!g_initialized) { + return ORBIS_PAD_ERROR_NOT_INITIALIZED; + } + + if (handle == PAD_STANDARD_HANDLER) { + if (!g_pad_standard_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + + standard_handler: + auto* controller = Common::Singleton::Instance(); + int connectedCount = 0; + bool isConnected = false; + Input::State state; + controller->ReadState(&state, &isConnected, &connectedCount); + + pData->CopyFromState(state); + + return ORBIS_OK; + } + if (handle == PAD_SPECIAL_HANDLER) { + if (!g_pad_standard_special_connected) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + // TODO implement special pad + goto standard_handler; + } + return ORBIS_PAD_ERROR_INVALID_HANDLE; } int PS4_SYSV_ABI scePadReadStateExt() { diff --git a/src/core/libraries/pad/pad.h b/src/core/libraries/pad/pad.h index f94a642cfb..4b851cd18f 100644 --- a/src/core/libraries/pad/pad.h +++ b/src/core/libraries/pad/pad.h @@ -9,6 +9,10 @@ namespace Core::Loader { class SymbolsResolver; } +namespace Input { +struct State; +} + namespace Libraries::Pad { constexpr int ORBIS_PAD_MAX_TOUCH_NUM = 2; @@ -188,6 +192,8 @@ struct OrbisPadData { u8 reserve[2]; u8 deviceUniqueDataLen; u8 deviceUniqueData[ORBIS_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE]; + + void CopyFromState(const Input::State& state); }; struct OrbisPadTouchPadInformation { diff --git a/src/core/libraries/system/msgdialog_ui.cpp b/src/core/libraries/system/msgdialog_ui.cpp index 862f5a569f..305263047b 100644 --- a/src/core/libraries/system/msgdialog_ui.cpp +++ b/src/core/libraries/system/msgdialog_ui.cpp @@ -238,11 +238,21 @@ void MsgDialogUi::Finish(ButtonId buttonId, Result r) { } if (status) { *status = Status::FINISHED; + if (callback.has_value()) { + callback.value()(DialogResult{ + .result = r, + .buttonId = buttonId, + }); + } } state = nullptr; status = nullptr; result = nullptr; RemoveLayer(this); + if (self_destruct) { + self_destruct = false; + delete this; + } } void MsgDialogUi::Draw() { @@ -282,19 +292,24 @@ void MsgDialogUi::Draw() { first_render = false; } -DialogResult Libraries::MsgDialog::ShowMsgDialog(MsgDialogState p_state, bool block) { - static DialogResult result{}; - static Status status; - static MsgDialogUi dialog; - static MsgDialogState state; - dialog = MsgDialogUi{}; - status = Status::RUNNING; - state = std::move(p_state); - dialog = MsgDialogUi(&state, &status, &result); +void Libraries::MsgDialog::ShowMsgDialog( + MsgDialogState p_state, bool block, std::optional> callback) { + auto status = new Status{Status::RUNNING}; + auto state = new MsgDialogState{std::move(p_state)}; + auto dialog = new MsgDialogUi(state, status, nullptr); + bool running = true; + dialog->SetSelfDestruct(); + dialog->SetCallback([&, status, state, callback = std::move(callback)](auto result) { + running = false; + delete status; + delete state; + if (callback.has_value()) { + callback.value()(result); + } + }); if (block) { - while (status == Status::RUNNING) { + while (running) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } - return result; } diff --git a/src/core/libraries/system/msgdialog_ui.h b/src/core/libraries/system/msgdialog_ui.h index d24ec067c5..c56d6faa1a 100644 --- a/src/core/libraries/system/msgdialog_ui.h +++ b/src/core/libraries/system/msgdialog_ui.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -11,6 +12,8 @@ #include "core/libraries/system/commondialog.h" #include "imgui/imgui_layer.h" +#include + namespace Libraries::MsgDialog { using OrbisUserServiceUserId = s32; @@ -157,6 +160,10 @@ class MsgDialogUi final : public ImGui::Layer { CommonDialog::Status* status{}; DialogResult* result{}; + // HOST ONLY + bool self_destruct{false}; + std::optional> callback; + void DrawUser(); void DrawProgressBar(); void DrawSystemMessage(); @@ -169,13 +176,22 @@ class MsgDialogUi final : public ImGui::Layer { MsgDialogUi(MsgDialogUi&& other) noexcept; MsgDialogUi& operator=(MsgDialogUi other); + void SetSelfDestruct() { + self_destruct = true; + } + + void SetCallback(std::function callback) { + this->callback = std::move(callback); + } + void Finish(ButtonId buttonId, CommonDialog::Result r = CommonDialog::Result::OK); void Draw() override; }; -// Utility function to show a message dialog -// !!! This function can block !!! -DialogResult ShowMsgDialog(MsgDialogState state, bool block = true); +// Utility function to show a message dialog from host code +// callback is called from the present thread +void ShowMsgDialog(MsgDialogState state, bool block = false, + std::optional> callback = std::nullopt); }; // namespace Libraries::MsgDialog \ No newline at end of file diff --git a/src/imgui/renderer/imgui_core.cpp b/src/imgui/renderer/imgui_core.cpp index 311e86a3c7..5bf8d56e90 100644 --- a/src/imgui/renderer/imgui_core.cpp +++ b/src/imgui/renderer/imgui_core.cpp @@ -83,7 +83,7 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w StyleColorsDark(); ::Core::Devtools::Layer::SetupSettings(); - Sdl::Init(window.GetSdlWindow()); + Sdl::Init(&window); const Vulkan::InitInfo vk_info{ .instance = instance.GetInstance(), diff --git a/src/imgui/renderer/imgui_impl_sdl3.cpp b/src/imgui/renderer/imgui_impl_sdl3.cpp index 230d396f01..a97c2dbb9c 100644 --- a/src/imgui/renderer/imgui_impl_sdl3.cpp +++ b/src/imgui/renderer/imgui_impl_sdl3.cpp @@ -9,6 +9,9 @@ // SDL #include + +#include "sdl_window.h" +#include "video_core/renderer_vulkan/vk_instance.h" #if defined(__APPLE__) #include #endif @@ -23,6 +26,9 @@ namespace ImGui::Sdl { // SDL Data struct SdlData { + // SDL Wrapper + const Frontend::WindowSDL* wrapper{}; + SDL_Window* window{}; SDL_WindowID window_id{}; Uint64 time{}; @@ -501,7 +507,7 @@ static void SetupPlatformHandles(ImGuiViewport* viewport, SDL_Window* window) { #endif } -bool Init(SDL_Window* window) { +bool Init(const Frontend::WindowSDL* wrapper) { ImGuiIO& io = ImGui::GetIO(); IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); @@ -514,8 +520,9 @@ bool Init(SDL_Window* window) { io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests // (optional, rarely used) - bd->window = window; - bd->window_id = SDL_GetWindowID(window); + bd->wrapper = wrapper; + bd->window = wrapper->GetSdlWindow(); + bd->window_id = SDL_GetWindowID(bd->window); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_SetClipboardTextFn = SetClipboardText; @@ -543,7 +550,7 @@ bool Init(SDL_Window* window) { // Set platform dependent data in viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - SetupPlatformHandles(main_viewport, window); + SetupPlatformHandles(main_viewport, bd->window); // From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't // emit the event. Without this, when clicking to gain focus, our widgets wouldn't activate even @@ -593,7 +600,6 @@ static void UpdateMouseData() { // (below) // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries // shouldn't e.g. trigger other operations outside - SDL_CaptureMouse((bd->mouse_buttons_down != 0) ? true : false); SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->window == focused_window); @@ -662,7 +668,9 @@ static void UpdateMouseCursor() { SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113) bd->mouse_last_cursor = expected_cursor; } - SDL_ShowCursor(); + if (!bd->wrapper->isCapturingMouse()) { + SDL_ShowCursor(); + } } } diff --git a/src/imgui/renderer/imgui_impl_sdl3.h b/src/imgui/renderer/imgui_impl_sdl3.h index 59b1a68567..a67cea65d7 100644 --- a/src/imgui/renderer/imgui_impl_sdl3.h +++ b/src/imgui/renderer/imgui_impl_sdl3.h @@ -10,9 +10,13 @@ struct SDL_Renderer; struct SDL_Gamepad; typedef union SDL_Event SDL_Event; +namespace Frontend { +class WindowSDL; +} + namespace ImGui::Sdl { -bool Init(SDL_Window* window); +bool Init(const Frontend::WindowSDL* window); void Shutdown(); void NewFrame(); bool ProcessEvent(const SDL_Event* event); diff --git a/src/input/mouse.cpp b/src/input/mouse.cpp index 6f6527ad76..afc2a87501 100644 --- a/src/input/mouse.cpp +++ b/src/input/mouse.cpp @@ -11,68 +11,69 @@ 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; - - 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]; - } - } - } + const u32 count = std::min(m_states_num, u32(states_num)); + + 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; + m_states_num -= count; + return static_cast(count); } -MouseState GameMouse::GetLastState() const { - if (m_states_num == 0) { - return m_last_state; +void GameMouse::AddState(const MouseState& state) { + std::scoped_lock lock{m_mutex}; + + m_index = (m_index + 1) % MAX_MOUSE_STATES; + if (m_states_num < MAX_MOUSE_STATES) { + ++m_states_num; } + m_states[m_index] = state; + m_last_state = MouseState{ + .button_state = state.button_state, + }; +} - auto last = (m_first_state + m_states_num - 1) % MAX_MOUSE_STATES; +void GameMouse::CheckButton(u32 button, bool isPressed) { + if (!m_connected) { + return; + } + MouseState state = m_last_state; + state.time = Libraries::Kernel::sceKernelGetProcessTime(); + if (isPressed) { + state.button_state |= button; + } else { + state.button_state &= ~button; + } - return m_states[last]; + AddState(state); } -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; +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; - 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++; + AddState(state); } -void GameMouse::CheckButton(int id, u32 button, bool isPressed) { - std::scoped_lock lock{m_mutex}; - auto state = GetLastState(); - state.time = Libraries::Kernel::sceKernelGetProcessTime(); - if (isPressed) { - state.buttonsState |= button; - } else { - state.buttonsState &= ~button; +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); } diff --git a/src/input/mouse.h b/src/input/mouse.h index e5a112cb33..66477b9904 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 @@ class GameMouse { 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 bd866037ab..d478fae1bd 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() { diff --git a/src/sdl_window.h b/src/sdl_window.h index 4bcaf46d12..ee7e23e02e 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -58,6 +58,10 @@ class WindowSDL { return is_open; } + bool isCapturingMouse() const { + return is_capturing_mouse; + } + [[nodiscard]] SDL_Window* GetSdlWindow() const { return window; } @@ -83,6 +87,8 @@ class WindowSDL { SDL_Window* window{}; bool is_shown{}; bool is_open{true}; + + bool is_capturing_mouse{false}; }; } // namespace Frontend