// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "core/libraries/move/move.h" #include "core/libraries/move/move_error.h" #include "input/controller.h" #include "move.h" auto controllers = *Common::Singleton::Instance(); namespace Libraries::Move { static bool g_library_initialized = false; s32 PS4_SYSV_ABI sceMoveInit() { if (g_library_initialized) { return ORBIS_MOVE_ERROR_ALREADY_INIT; } LOG_WARNING(Lib_Move, "Move controllers are not supported yet"); g_library_initialized = true; return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveOpen(Libraries::UserService::OrbisUserServiceUserId user_id, s32 type, s32 index) { LOG_DEBUG(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } // Even when no controllers are connected, this returns a proper handle. // Internal libSceVrTracker logic requires this handle to be different from other devices. static s32 handle = 0x30b0000; return handle += 0x100; } s32 PS4_SYSV_ABI sceMoveGetDeviceInfo(s32 handle, OrbisMoveDeviceInfo* info) { LOG_TRACE(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } if (info == nullptr) { return ORBIS_MOVE_ERROR_INVALID_ARG; } return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; } static OrbisMoveButtonDataOffset PadToMoveOffset(Libraries::Pad::OrbisPadButtonDataOffset p) { OrbisMoveButtonDataOffset m{}; using OPBDO = Libraries::Pad::OrbisPadButtonDataOffset; using OMBDO = OrbisMoveButtonDataOffset; #define CONVERT(_pad, _move) \ do { \ if (True(p & OPBDO::_pad)) \ m |= OMBDO::_move; \ } while (0) CONVERT(Circle, Circle); CONVERT(Cross, Cross); CONVERT(Square, Square); CONVERT(Triangle, Triangle); CONVERT(Options, Start); CONVERT(L2, T); CONVERT(L1, Move); #undef CONVERT return m; } s32 PS4_SYSV_ABI sceMoveReadStateLatest(s32 handle, OrbisMoveData* data) { if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } if (data == nullptr) { return ORBIS_MOVE_ERROR_INVALID_ARG; } if (!controllers.moves(0)->m_sdl_gamepad) { return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; } LOG_DEBUG(Lib_Move, "called"); auto m = controllers.moves(0); Input::State s{}; bool connected; int connected_count; m->ReadState(&s, &connected, &connected_count); data->button_data.trigger_data = u16(s.axes[std::to_underlying(Input::Axis::TriggerRight)]); data->button_data.button_data = std::to_underlying(PadToMoveOffset(s.buttonsState)); data->accelerometer[0] = s.acceleration.x; data->accelerometer[1] = s.acceleration.y; data->accelerometer[2] = s.acceleration.z; data->gyro[0] = s.angularVelocity.x; data->gyro[1] = s.angularVelocity.y; data->gyro[2] = s.angularVelocity.z; return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveReadStateRecent(s32 handle, s64 timestamp, OrbisMoveData* data, s32* out_count) { LOG_TRACE(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } if (timestamp < 0 || data == nullptr || out_count == nullptr) { return ORBIS_MOVE_ERROR_INVALID_ARG; } return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; } s32 PS4_SYSV_ABI sceMoveGetExtensionPortInfo(s32 handle, void* data) { LOG_TRACE(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } if (data == nullptr) { return ORBIS_MOVE_ERROR_INVALID_ARG; } return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; } s32 PS4_SYSV_ABI sceMoveSetVibration(s32 handle, u8 intensity) { LOG_TRACE(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } if (!controllers.moves(0)->m_sdl_gamepad) { return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; } controllers.moves(0)->SetVibration(0, intensity); return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveSetLightSphere(s32 handle, u8 red, u8 green, u8 blue) { LOG_DEBUG(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } if (!controllers.moves(0)->m_sdl_gamepad) { return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; } controllers.moves(0)->SetLightBarRGB(red, green, blue); return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveResetLightSphere(s32 handle) { LOG_TRACE(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } // Returns success, even if no controllers are connected. return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveClose(s32 handle) { LOG_DEBUG(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveTerm() { LOG_DEBUG(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } g_library_initialized = false; return ORBIS_OK; } void RegisterLib(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("j1ITE-EoJmE", "libSceMove", 1, "libSceMove", sceMoveInit); LIB_FUNCTION("HzC60MfjJxU", "libSceMove", 1, "libSceMove", sceMoveOpen); LIB_FUNCTION("GWXTyxs4QbE", "libSceMove", 1, "libSceMove", sceMoveGetDeviceInfo); LIB_FUNCTION("ttU+JOhShl4", "libSceMove", 1, "libSceMove", sceMoveReadStateLatest); LIB_FUNCTION("f2bcpK6kJfg", "libSceMove", 1, "libSceMove", sceMoveReadStateRecent); LIB_FUNCTION("y5h7f8H1Jnk", "libSceMove", 1, "libSceMove", sceMoveGetExtensionPortInfo); LIB_FUNCTION("IFQwtT2CeY0", "libSceMove", 1, "libSceMove", sceMoveSetVibration); LIB_FUNCTION("T8KYHPs1JE8", "libSceMove", 1, "libSceMove", sceMoveSetLightSphere); LIB_FUNCTION("zuxWAg3HAac", "libSceMove", 1, "libSceMove", sceMoveResetLightSphere); LIB_FUNCTION("XX6wlxpHyeo", "libSceMove", 1, "libSceMove", sceMoveClose); LIB_FUNCTION("tsZi60H4ypY", "libSceMove", 1, "libSceMove", sceMoveTerm); }; } // namespace Libraries::Move