From 66112bc90a2a9dc0f830ca497cb6ff22c4ca2e33 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 10 May 2026 10:04:20 +0200 Subject: [PATCH] Refactor pad handles (#4386) * Set up [userid, type, index] -> pad_handle mapping and hook up currently existing GameControllers backend to it * just use basic oop principles why are we even shoving callee responsibility in caller logic * support special pads * random edge case I thought of * return error if handle is already opened, redirect scePadOpenExt to scePadOpen * scePadClose * error out if trying to close an unopened handle * oof * logging --- src/core/libraries/pad/pad.cpp | 150 +++++++++++++++++++-------------- src/input/controller.cpp | 6 +- src/input/controller.h | 17 ++-- src/input/input_handler.cpp | 3 +- 4 files changed, 100 insertions(+), 76 deletions(-) diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index e9ab0b7b2..27dea2bd1 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -18,12 +18,38 @@ using Input::GameController; using Input::GameControllers; using namespace Libraries::UserService; +struct HandleKey { + OrbisUserServiceUserId id; + s32 device_class; + s32 index; + + bool operator==(const HandleKey&) const = default; +}; +struct HandleKeyHash { + std::size_t operator()(const HandleKey& k) const { + std::size_t h1 = std::hash{}(k.id); + std::size_t h2 = std::hash{}(k.device_class); + std::size_t h3 = std::hash{}(k.index); + return h1 ^ (h2 << 1) ^ (h3 << 2); + } +}; + static bool g_initialized = false; -static std::unordered_map user_id_pad_handle_map{}; -static constexpr s32 tv_remote_handle = 5; +static u64 pad_handle_counter = 1; +static std::unordered_map pad_handle_map{}; +static std::unordered_map handle_to_controller_map{}; int PS4_SYSV_ABI scePadClose(s32 handle) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); + LOG_WARNING(Lib_Pad, "called, handle: {}", handle); + if (handle_to_controller_map.erase(handle) == 0) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } + for (auto& it : pad_handle_map) { + if (it.second == handle) { + pad_handle_map.erase(it.first); + break; + } + } return ORBIS_OK; } @@ -34,6 +60,10 @@ int PS4_SYSV_ABI scePadConnectPort() { int PS4_SYSV_ABI scePadDeviceClassGetExtendedInformation( s32 handle, OrbisPadDeviceClassExtendedInformation* pExtInfo) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } LOG_ERROR(Lib_Pad, "(STUBBED) called"); std::memset(pExtInfo, 0, sizeof(OrbisPadDeviceClassExtendedInformation)); if (EmulatorSettings.IsUsingSpecialPad()) { @@ -100,6 +130,10 @@ int PS4_SYSV_ABI scePadGetCapability() { int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerInformation* pInfo) { LOG_DEBUG(Lib_Pad, "called handle = {}", handle); + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { + return ORBIS_PAD_ERROR_INVALID_HANDLE; + } pInfo->touchPadInfo.pixelDensity = 1; pInfo->touchPadInfo.resolution.x = 1920; pInfo->touchPadInfo.resolution.y = 950; @@ -108,10 +142,6 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD; pInfo->connectedCount = 1; pInfo->deviceClass = OrbisPadDeviceClass::Standard; - if (handle < 0) { - pInfo->connected = false; - return ORBIS_OK; - } pInfo->connected = true; if (EmulatorSettings.IsUsingSpecialPad()) { pInfo->connectionType = ORBIS_PAD_PORT_TYPE_SPECIAL; @@ -168,8 +198,8 @@ int PS4_SYSV_ABI scePadGetHandle(Libraries::UserService::OrbisUserServiceUserId if (userId == -1) { return ORBIS_PAD_ERROR_DEVICE_NO_HANDLE; } - auto it = user_id_pad_handle_map.find(userId); - if (it == user_id_pad_handle_map.end()) { + auto it = pad_handle_map.find({userId, type, index}); + if (it == pad_handle_map.end()) { return ORBIS_PAD_ERROR_DEVICE_NO_HANDLE; } s32 pad_handle = it->second; @@ -281,11 +311,17 @@ int PS4_SYSV_ABI scePadOpen(Libraries::UserService::OrbisUserServiceUserId userI if (userId < 0) { return ORBIS_DEVICE_SERVICE_ERROR_INVALID_USER; } + if (pad_handle_map.find({userId, type, index}) != pad_handle_map.end()) { + return ORBIS_PAD_ERROR_ALREADY_OPENED; + } + auto& controllers = *Common::Singleton::Instance(); if (userId == ORBIS_USER_SERVICE_USER_ID_SYSTEM) { if (type == ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL) { - LOG_INFO(Lib_Pad, "Opened a TV remote device"); - user_id_pad_handle_map[ORBIS_USER_SERVICE_USER_ID_SYSTEM] = tv_remote_handle; - return tv_remote_handle; + s32 new_handle = pad_handle_counter++; + pad_handle_map[{userId, type, index}] = new_handle; + handle_to_controller_map[new_handle] = controllers[4]; + LOG_INFO(Lib_Pad, "Opened a TV remote device, out handle: {}", new_handle); + return new_handle; } return ORBIS_DEVICE_SERVICE_ERROR_INVALID_USER; } @@ -297,28 +333,25 @@ int PS4_SYSV_ABI scePadOpen(Libraries::UserService::OrbisUserServiceUserId userI return ORBIS_DEVICE_SERVICE_ERROR_USER_NOT_LOGIN; } s32 pad_handle = u->player_index; - LOG_INFO(Lib_Pad, "called user_id = {} type = {} index = {}, pad_handle = {}", userId, type, + LOG_INFO(Lib_Pad, "called user_id = {} type = {} index = {}, player_index = {}", userId, type, index, pad_handle); scePadResetLightBar(pad_handle); scePadResetOrientation(pad_handle); - user_id_pad_handle_map[userId] = pad_handle; - return pad_handle; + s32 new_handle = pad_handle_counter++; + pad_handle_map[{userId, type, index}] = new_handle; + + handle_to_controller_map[new_handle] = + controllers[type == (EmulatorSettings.IsUsingSpecialPad() ? 2 : 0) + ? UserManagement.GetUserByID(userId)->player_index - 1 + : 4]; + LOG_INFO(Lib_Pad, "Out handle: {}", new_handle); + return new_handle; } int PS4_SYSV_ABI scePadOpenExt(Libraries::UserService::OrbisUserServiceUserId userId, s32 type, s32 index, const OrbisPadOpenExtParam* pParam) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); - auto u = UserManagement.GetUserByID(userId); - if (!u) { - return ORBIS_DEVICE_SERVICE_ERROR_USER_NOT_LOGIN; - } - s32 pad_handle = u->player_index; - LOG_INFO(Lib_Pad, "called user_id = {} type = {} index = {}, pad_handle = {}", userId, type, - index, pad_handle); - scePadResetLightBar(pad_handle); - scePadResetOrientation(pad_handle); - user_id_pad_handle_map[userId] = pad_handle; - return pad_handle; + LOG_WARNING(Lib_Pad, "Redirect to scePadOpen"); + return scePadOpen(userId, type, index, nullptr); } int PS4_SYSV_ABI scePadOpenExt2() { @@ -459,12 +492,11 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) { int connected_count = 0; bool connected = false; std::vector states(64); - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } - auto& controllers = *Common::Singleton::Instance(); - auto& controller = *controllers[*controller_id]; + auto& controller = *it->second; int ret_num = controller.ReadStates(states.data(), num, &connected, &connected_count); return ProcessStates(handle, pData, controller, states.data(), ret_num, connected, connected_count); @@ -492,12 +524,11 @@ int PS4_SYSV_ABI scePadReadHistory() { int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) { LOG_TRACE(Lib_Pad, "handle: {}", handle); - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } - auto& controllers = *Common::Singleton::Instance(); - auto& controller = *controllers[*controller_id]; + auto& controller = *it->second; int connected_count = 0; bool connected = false; Input::State state; @@ -513,12 +544,12 @@ int PS4_SYSV_ABI scePadReadStateExt() { int PS4_SYSV_ABI scePadResetLightBar(s32 handle) { LOG_DEBUG(Lib_Pad, "called, handle: {}", handle); - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } - auto& controllers = *Common::Singleton::Instance(); - auto u = UserManagement.GetUserByPlayerIndex(handle); + auto& controller = *it->second; + auto u = UserManagement.GetUserByPlayerIndex(controller.user_id); s32 colour_index = u ? u->user_color - 1 : 0; Input::Colour colour{255, 0, 0}; if (colour_index >= 0 && colour_index <= 3) { @@ -533,10 +564,7 @@ int PS4_SYSV_ABI scePadResetLightBar(s32 handle) { LOG_ERROR(Lib_Pad, "Invalid user colour value {} for controller {}, falling back to blue", colour_index, handle); } - if (auto oc = GameControllers::GetControllerCustomColor(*controller_id)) { - colour = *oc; - } - controllers[*controller_id]->SetLightBarRGB(colour.r, colour.g, colour.b); + controller.SetLightBarRGB(colour.r, colour.g, colour.b); return ORBIS_OK; } @@ -553,15 +581,14 @@ int PS4_SYSV_ABI scePadResetLightBarAllByPortType() { int PS4_SYSV_ABI scePadResetOrientation(s32 handle) { LOG_INFO(Lib_Pad, "scePadResetOrientation called handle = {}", handle); - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } - - auto& controllers = *Common::Singleton::Instance(); + auto& controller = *it->second; Libraries::Pad::OrbisFQuaternion defaultOrientation = {0.0f, 0.0f, 0.0f, 1.0f}; - controllers[*controller_id]->SetLastOrientation(defaultOrientation); - controllers[*controller_id]->SetLastUpdate(std::chrono::steady_clock::now()); + controller.SetLastOrientation(defaultOrientation); + controller.SetLastUpdate(std::chrono::steady_clock::now()); return ORBIS_OK; } @@ -612,13 +639,11 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() { } int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) { - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } - if (GameControllers::GetControllerCustomColor(*controller_id)) { - return ORBIS_OK; - } + auto& controller = *it->second; if (pParam != nullptr) { LOG_DEBUG(Lib_Pad, "called handle = {} rgb = {} {} {}", handle, pParam->r, pParam->g, pParam->b); @@ -629,7 +654,7 @@ int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pPar } auto& controllers = *Common::Singleton::Instance(); - controllers[*controller_id]->SetLightBarRGB(pParam->r, pParam->g, pParam->b); + controller.SetLightBarRGB(pParam->r, pParam->g, pParam->b); return ORBIS_OK; } return ORBIS_PAD_ERROR_INVALID_ARG; @@ -647,12 +672,12 @@ int PS4_SYSV_ABI scePadSetLightBarBlinking() { int PS4_SYSV_ABI scePadSetLightBarForTracker(s32 handle, const OrbisPadLightBarParam* pParam) { LOG_INFO(Lib_Pad, "called, r: {} g: {} b: {}", pParam->r, pParam->g, pParam->b); - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } - auto& controllers = *Common::Singleton::Instance(); - controllers[*controller_id]->SetLightBarRGB(pParam->r, pParam->g, pParam->b); + auto& controller = *it->second; + controller.SetLightBarRGB(pParam->r, pParam->g, pParam->b); return ORBIS_OK; } @@ -699,15 +724,16 @@ int PS4_SYSV_ABI scePadSetUserColor() { } int PS4_SYSV_ABI scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pParam) { - auto controller_id = GameControllers::GetControllerIndexFromControllerID(handle); - if (!controller_id) { + auto it = handle_to_controller_map.find(handle); + if (it == handle_to_controller_map.end()) { return ORBIS_PAD_ERROR_INVALID_HANDLE; } + auto& controller = *it->second; if (pParam != nullptr) { LOG_DEBUG(Lib_Pad, "scePadSetVibration called handle = {} data = {} , {}", handle, pParam->smallMotor, pParam->largeMotor); auto& controllers = *Common::Singleton::Instance(); - controllers[*controller_id]->SetVibration(pParam->smallMotor, pParam->largeMotor); + controller.SetVibration(pParam->smallMotor, pParam->largeMotor); return ORBIS_OK; } return ORBIS_PAD_ERROR_INVALID_ARG; diff --git a/src/input/controller.cpp b/src/input/controller.cpp index d699b035b..45462ffc5 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -151,6 +151,9 @@ void GameController::UpdateAxisSmoothing() { } void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) { + if (override_colour.has_value()) { + return; + } colour = {r, g, b}; if (m_sdl_gamepad != nullptr) { SDL_SetGamepadLED(m_sdl_gamepad, r, g, b); @@ -188,9 +191,6 @@ void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, f } } -std::array, 4> GameControllers::controller_override_colors{ - std::nullopt, std::nullopt, std::nullopt, std::nullopt}; - void GameControllers::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration, Libraries::Pad::OrbisFVector3& angularVelocity, float deltaTime, diff --git a/src/input/controller.h b/src/input/controller.h index 9089fcfe2..a9ad7635c 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -164,6 +164,7 @@ private: std::chrono::steady_clock::time_point m_last_update = {}; Libraries::Pad::OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f}; Colour colour; + std::optional override_colour{}; State m_state; @@ -174,8 +175,6 @@ private: class GameControllers { std::array controllers; - static std::array, 4> controller_override_colors; - public: GameControllers() : controllers({new GameController(), new GameController(), new GameController(), @@ -197,14 +196,12 @@ public: float deltaTime, Libraries::Pad::OrbisFQuaternion& lastOrientation, Libraries::Pad::OrbisFQuaternion& orientation); - static void SetControllerCustomColor(s32 i, u8 r, u8 g, u8 b) { - controller_override_colors[i] = {r, g, b}; - } - static std::optional GetControllerCustomColor(s32 i) { - if (i >= controller_override_colors.size()) { - return {}; - } - return controller_override_colors[i]; + void SetControllerCustomColor(s32 i, u8 r, u8 g, u8 b) { + // reset to ensure the next function always runs, even if there already was a preexisting + // override colour before + controllers[i]->override_colour = std::nullopt; + controllers[i]->SetLightBarRGB(r, g, b); + controllers[i]->override_colour = {r, g, b}; } }; diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index bdd7d008a..dc457cc2a 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -544,7 +544,8 @@ void ParseInputConfig(const std::string game_id = "") { } output_gamepad_id = output_gamepad_id == -1 ? 1 : output_gamepad_id; if (enable == "true") { - GameControllers::SetControllerCustomColor(output_gamepad_id - 1, *r, *g, *b); + ControllerOutput::controllers.SetControllerCustomColor(output_gamepad_id - 1, *r, + *g, *b); } LOG_DEBUG(Input, "Parsed color settings: {} {} - {} {} {}", enable == "true" ? "override" : "no override", output_gamepad_id, *r, *b, *g);