diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d874b74c..d29c3380ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,6 +549,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/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index f0171199bf..da9e2c8dbd 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 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 b83afd299c..c2c24f8092 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 11ee92896c..e382ac94b9 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -68,7 +68,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: