diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c7e03e3..89cb833e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,6 +231,8 @@ 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/mouse/mouse.cpp + src/core/libraries/mouse/mouse.h ) set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h @@ -549,6 +551,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp 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/common/logging/filter.cpp b/src/common/logging/filter.cpp index ab3468ca..4910e622 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -113,6 +113,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, ImeDialog) \ SUB(Lib, AvPlayer) \ SUB(Lib, Ngs2) \ + SUB(Lib, Mouse) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index dd2376ea..461195b5 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -80,6 +80,7 @@ enum class Class : u8 { Lib_ImeDialog, ///< The LibSceImeDialog implementation. Lib_AvPlayer, ///< The LibSceAvPlayer implementation. Lib_Ngs2, ///< The LibSceNgs2 implementation. + Lib_Mouse, ///< The LibSceMouse implementation Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index f0171199..da9e2c8d 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -37,6 +37,7 @@ #include "src/core/libraries/dialogs/error_dialog.h" #include "src/core/libraries/dialogs/ime_dialog.h" #include "src/core/libraries/libpng/pngdec.h" +#include "src/core/libraries/mouse/mouse.h" namespace Libraries { @@ -75,6 +76,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::ErrorDialog::RegisterlibSceErrorDialog(sym); Libraries::ImeDialog::RegisterlibSceImeDialog(sym); Libraries::AvPlayer::RegisterlibSceAvPlayer(sym); + Libraries::Mouse::RegisterlibSceMouse(sym); } } // namespace Libraries diff --git a/src/core/libraries/mouse/mouse.cpp b/src/core/libraries/mouse/mouse.cpp new file mode 100644 index 00000000..b4581831 --- /dev/null +++ b/src/core/libraries/mouse/mouse.cpp @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// 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" +#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_INFO(Lib_Mouse, "called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceMouseMbusInit() { + 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(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 = connected; + 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() { + 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 00000000..a0d276af --- /dev/null +++ b/src/core/libraries/mouse/mouse.h @@ -0,0 +1,50 @@ +// 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 { + +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(); +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(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(); + +void RegisterlibSceMouse(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Mouse \ No newline at end of file diff --git a/src/input/mouse.cpp b/src/input/mouse.cpp new file mode 100644 index 00000000..6f6527ad --- /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 00000000..e5a112cb --- /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 b83afd29..c2c24f80 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -16,6 +16,9 @@ #ifdef __APPLE__ #include #endif +#include +#include +#include namespace Frontend { @@ -108,11 +111,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); } diff --git a/src/sdl_window.h b/src/sdl_window.h index 11ee9289..e382ac94 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -68,7 +68,7 @@ private: 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: