// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "mouse.h" #include #include #include #include "common/elf_info.h" #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include using Common::ElfInfo; namespace Libraries::Mouse { static std::mutex g_mtx; static bool g_initialized = false; static bool g_mouse1_open = false; static bool g_mouse2_open = false; constexpr int32_t MOUSE1_HANDLE = 0x72617431; // rat1 constexpr int32_t MOUSE2_HANDLE = 0x72617432; // rat2 static_assert(MOUSE1_HANDLE > 0); static_assert(MOUSE2_HANDLE > 0); 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; } std::lock_guard lck{g_mtx}; 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() { 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"); std::lock_guard lck{g_mtx}; g_initialized = true; 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, "called"); if (!g_initialized) { return ORBIS_MOUSE_ERROR_NOT_INITIALIZED; } if (type != 0) { return ORBIS_MOUSE_ERROR_INVALID_ARG; } std::lock_guard lck{g_mtx}; bool merge = ElfInfo::Instance().FirmwareVer() >= ElfInfo::FW_20 && 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) { 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; } std::lock_guard lck{g_mtx}; 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++) { 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; } 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