diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index d39935503..c9e332d21 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -419,8 +419,14 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() { } int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) { - LOG_ERROR(Lib_Pad, "(STUBBED) called"); - return ORBIS_OK; + if (pParam != nullptr) { + LOG_INFO(Lib_Pad, "scePadSetLightBar called handle = {} rgb = {} {} {}", handle, pParam->r, + pParam->g, pParam->b); + auto* controller = Common::Singleton::Instance(); + controller->SetLightBarRGB(pParam->r, pParam->g, pParam->b); + return ORBIS_OK; + } + return ORBIS_PAD_ERROR_INVALID_ARG; } int PS4_SYSV_ABI scePadSetLightBarBaseBrightness() { @@ -479,8 +485,14 @@ int PS4_SYSV_ABI scePadSetUserColor() { } int PS4_SYSV_ABI scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pParam) { - LOG_DEBUG(Lib_Pad, "(STUBBED) called"); - return ORBIS_OK; + if (pParam != nullptr) { + LOG_INFO(Lib_Pad, "scePadSetVibration called handle = {} data = {} , {}", handle, + pParam->smallMotor, pParam->largeMotor); + auto* controller = Common::Singleton::Instance(); + controller->SetVibration(pParam->smallMotor, pParam->largeMotor); + return ORBIS_OK; + } + return ORBIS_PAD_ERROR_INVALID_ARG; } int PS4_SYSV_ABI scePadSetVibrationForce() { diff --git a/src/input/controller.cpp b/src/input/controller.cpp index 247e08ce8..8c37b01a1 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -4,6 +4,7 @@ #include "core/libraries/kernel/time_management.h" #include "core/libraries/pad/pad.h" #include "input/controller.h" +#include namespace Input { @@ -117,4 +118,28 @@ void GameController::Axis(int id, Input::Axis axis, int value) { AddState(state); } +void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) { + if (m_sdl_gamepad != nullptr) { + SDL_SetGamepadLED(m_sdl_gamepad, r, g, b); + } +} + +bool GameController::SetVibration(u8 smallMotor, u8 largeMotor) { + if (m_sdl_gamepad != nullptr) { + return SDL_RumbleGamepad(m_sdl_gamepad, (smallMotor / 255.0f) * 0xFFFF, (largeMotor / 255.0f) * 0xFFFF, -1) == 0; + } + return true; +} + +void GameController::TryOpenSDLController() { + if (m_sdl_gamepad == nullptr || !SDL_GamepadConnected(m_sdl_gamepad)) { + int gamepad_count; + SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count); + m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr; + SDL_free(gamepads); + } + + SetLightBarRGB(0, 0, 255); +} + } // namespace Input diff --git a/src/input/controller.h b/src/input/controller.h index a16f7dd06..ef0991568 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -6,6 +6,8 @@ #include #include "common/types.h" +struct SDL_Gamepad; + namespace Input { enum class Axis { @@ -43,6 +45,9 @@ public: void CheckButton(int id, u32 button, bool isPressed); void AddState(const State& state); void Axis(int id, Input::Axis axis, int value); + void SetLightBarRGB(u8 r, u8 g, u8 b); + bool SetVibration(u8 smallMotor, u8 largeMotor); + void TryOpenSDLController(); private: struct StateInternal { @@ -57,6 +62,8 @@ private: u32 m_first_state = 0; std::array m_states; std::array m_private; + + SDL_Gamepad* m_sdl_gamepad = nullptr; }; } // namespace Input diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 92d1b7fa8..1a1016763 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -44,17 +44,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ SDL_SetWindowFullscreen(window, Config::isFullscreenMode()); SDL_InitSubSystem(SDL_INIT_GAMEPAD); - - int gamepad_count; - SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count); - if (gamepad_count > 0) { - gamepad = SDL_OpenGamepad(gamepads[0]); - } - SDL_free(gamepads); - - if (gamepad != nullptr) { - SDL_SetGamepadLED(gamepad, 0, 0, 255); - } + controller->TryOpenSDLController(); #if defined(SDL_PLATFORM_WIN32) window_info.type = WindowSystemType::Windows; @@ -302,36 +292,19 @@ void WindowSDL::onGamepadEvent(const SDL_Event* event) { switch (event->type) { case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: - button = - event->gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_DOWN ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN - : event->gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_UP ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP - : event->gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_LEFT ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT - : event->gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT - : event->gbutton.button == SDL_GAMEPAD_BUTTON_SOUTH ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS - : event->gbutton.button == SDL_GAMEPAD_BUTTON_NORTH ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE - : event->gbutton.button == SDL_GAMEPAD_BUTTON_WEST ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE - : event->gbutton.button == SDL_GAMEPAD_BUTTON_EAST ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE - : event->gbutton.button == SDL_GAMEPAD_BUTTON_START ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS - : event->gbutton.button == SDL_GAMEPAD_BUTTON_LEFT_SHOULDER ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1 - : event->gbutton.button == SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1 - : event->gbutton.button == SDL_GAMEPAD_BUTTON_LEFT_STICK ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3 - : event->gbutton.button == SDL_GAMEPAD_BUTTON_RIGHT_STICK ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3 - : event->gbutton.button == SDL_GAMEPAD_BUTTON_TOUCHPAD ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD - : event->gbutton.button == SDL_GAMEPAD_BUTTON_BACK ? OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD - : 0; + button = sdlGamepadToOrbisButton(event->gbutton.button); if (button != 0) { controller->CheckButton(0, button, event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN); } break; case SDL_EVENT_GAMEPAD_AXIS_MOTION: - axis = - event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX ? Input::Axis::LeftX - : event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTY ? Input::Axis::LeftY - : event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX ? Input::Axis::RightX - : event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTY ? Input::Axis::RightY - : event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER ? Input::Axis::TriggerLeft - : event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER ? Input::Axis::TriggerRight - : Input::Axis::AxisMax; + axis = event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX ? Input::Axis::LeftX + : event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTY ? Input::Axis::LeftY + : event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX ? Input::Axis::RightX + : event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTY ? Input::Axis::RightY + : event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER ? Input::Axis::TriggerLeft + : event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER ? Input::Axis::TriggerRight + : Input::Axis::AxisMax; if (axis != Input::Axis::AxisMax) { controller->Axis(0, axis, Input::GetAxis(-0x8000, 0x8000, event->gaxis.value)); } @@ -339,4 +312,43 @@ void WindowSDL::onGamepadEvent(const SDL_Event* event) { } } +int WindowSDL::sdlGamepadToOrbisButton(u8 button) { + using Libraries::Pad::OrbisPadButtonDataOffset; + + switch (button) { + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN; + case SDL_GAMEPAD_BUTTON_DPAD_UP: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP; + case SDL_GAMEPAD_BUTTON_DPAD_LEFT: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT; + case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT; + case SDL_GAMEPAD_BUTTON_SOUTH: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS; + case SDL_GAMEPAD_BUTTON_NORTH: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE; + case SDL_GAMEPAD_BUTTON_WEST: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE; + case SDL_GAMEPAD_BUTTON_EAST: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE; + case SDL_GAMEPAD_BUTTON_START: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS; + case SDL_GAMEPAD_BUTTON_TOUCHPAD: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; + case SDL_GAMEPAD_BUTTON_BACK: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; + case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1; + case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1; + case SDL_GAMEPAD_BUTTON_LEFT_STICK: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3; + case SDL_GAMEPAD_BUTTON_RIGHT_STICK: + return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3; + default: + return 0; + } +} + } // namespace Frontend diff --git a/src/sdl_window.h b/src/sdl_window.h index 2d75a86a6..cf6c37116 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -69,6 +69,8 @@ private: void onKeyPress(const SDL_Event* event); void onGamepadEvent(const SDL_Event* event); + int sdlGamepadToOrbisButton(u8 button); + private: s32 width; s32 height; @@ -77,7 +79,6 @@ private: SDL_Window* window{}; bool is_shown{}; bool is_open{true}; - SDL_Gamepad* gamepad{nullptr}; }; } // namespace Frontend