diff --git a/src/core/libraries/move/move.cpp b/src/core/libraries/move/move.cpp index b7e86a2d7..1ab206f17 100644 --- a/src/core/libraries/move/move.cpp +++ b/src/core/libraries/move/move.cpp @@ -1,13 +1,17 @@ // 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; @@ -44,15 +48,47 @@ s32 PS4_SYSV_ABI sceMoveGetDeviceInfo(s32 handle, OrbisMoveDeviceInfo* info) { 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) { - 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; + if (!controllers.moves(0)->m_sdl_gamepad) { + return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; + } + LOG_INFO(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[1] = m->accel_buf[1]; + data->accelerometer[2] = m->accel_buf[2]; + return ORBIS_OK; } s32 PS4_SYSV_ABI sceMoveReadStateRecent(s32 handle, s64 timestamp, OrbisMoveData* data, diff --git a/src/core/user_manager.cpp b/src/core/user_manager.cpp index cb5a5f343..3c1850689 100644 --- a/src/core/user_manager.cpp +++ b/src/core/user_manager.cpp @@ -141,7 +141,7 @@ bool UserManager::SetDefaultUser(u32 user_id) { } User UserManager::GetDefaultUser() { - return *GetUserByID(m_users.default_user_id); + return *GetUserByPlayerIndex(1); } void UserManager::SetControllerPort(u32 user_id, int port) { diff --git a/src/input/controller.cpp b/src/input/controller.cpp index 4087d3a0a..42223ac3d 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -171,8 +171,6 @@ void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, f } } -MoveController::MoveController() : m_states_queue(64) {} - bool GameControllers::override_controller_color = false; Colour GameControllers::controller_override_color{}; @@ -219,9 +217,10 @@ void GameControllers::CalculateOrientation(Libraries::Pad::OrbisFVector3& accele bool is_first_check = true; -void GameControllers::TryOpenSDLControllers(GameControllers& controllers) { +void GameControllers::TryOpenSDLControllers() { using namespace Libraries::UserService; int controller_count; + s32 move_count = 0; SDL_JoystickID* new_joysticks = SDL_GetGamepads(&controller_count); LOG_INFO(Input, "{} controllers are currently connected", controller_count); @@ -233,18 +232,8 @@ void GameControllers::TryOpenSDLControllers(GameControllers& controllers) { if (pad) { SDL_JoystickID id = SDL_GetGamepadID(pad); bool still_connected = false; + ControllerType type = ControllerType::Standard; for (int j = 0; j < controller_count; j++) { - ControllerType type = ControllerType::Standard; - SDL_GUID guid = SDL_GetJoystickGUID(SDL_GetJoystickFromID(new_joysticks[j])); - Uint16 vendor = 0, product = 0; - SDL_GetJoystickGUIDInfo(guid, &vendor, &product, nullptr, nullptr); - if (vendor == 0x054C && // Sony - (product == 0x03D5 || // PSMove ZCM1 - product == 0x0C5E)) { // PSMove ZCM2 - LOG_INFO(Input, "PS Move controller found at slot {}!", j); - type = ControllerType::Move; - LOG_CRITICAL(Input, "todo refactor this entire function"); - } if (new_joysticks[j] == id) { still_connected = true; assigned_ids.insert(id); @@ -259,8 +248,6 @@ void GameControllers::TryOpenSDLControllers(GameControllers& controllers) { controllers[i]->m_sdl_gamepad = nullptr; controllers[i]->user_id = -1; slot_taken[i] = false; - } else { - controllers[i]->player_index = i; } } } @@ -274,6 +261,23 @@ void GameControllers::TryOpenSDLControllers(GameControllers& controllers) { if (!pad) { continue; } + SDL_GUID guid = SDL_GetJoystickGUID(SDL_GetJoystickFromID(new_joysticks[j])); + Uint16 vendor = 0, product = 0; + SDL_GetJoystickGUIDInfo(guid, &vendor, &product, nullptr, nullptr); + if (vendor == 0x054C && // Sony + (product == 0x03D5 || // PSMove ZCM1 + product == 0x0C5E)) { // PSMove ZCM2 + LOG_INFO(Input, "PS Move controller found at slot {}!", j); + if (is_first_check) { // ABSOLUTELY HORRIBLE HACK but I just want it hooked up + // quickly + move_controllers[move_count]->m_sdl_gamepad = pad; + auto u = UserManagement.GetDefaultUser(); + move_controllers[move_count]->user_id = u.user_id; + move_controllers[move_count]->m_connected = true; + move_count++; + } + continue; + } for (int i = 0; i < 4; i++) { if (!slot_taken[i]) { @@ -314,7 +318,7 @@ void GameControllers::TryOpenSDLControllers(GameControllers& controllers) { } if (is_first_check) [[unlikely]] { is_first_check = false; - if (controller_count == 0) { + if (controller_count - move_count == 0) { auto u = UserManagement.GetUserByPlayerIndex(1); controllers[0]->user_id = u->user_id; UserManagement.LoginUser(u, 1); @@ -380,9 +384,26 @@ void GameController::PushState() { } u8 GameControllers::GetGamepadIndexFromJoystickId(SDL_JoystickID id) { - s32 index = SDL_GetGamepadPlayerIndex(SDL_GetGamepadFromID(id)); + auto g = SDL_GetGamepadFromID(id); + ASSERT(g != nullptr); + for (int i = 0; i < 4; i++) { + if (controllers[i]->m_sdl_gamepad == g) { + return i; + } + } LOG_TRACE(Input, "Gamepad index: {}", index); - return index; + return -1; +} + +u8 GameControllers::GetMoveIndexFromJoystickId(SDL_JoystickID id) { + auto g = SDL_GetGamepadFromID(id); + for (int i = 0; i < 4; i++) { + if (move_controllers[i]->m_sdl_gamepad == g) { + return i; + } + } + LOG_TRACE(Input, "Move index: {}", index); + return -1; } std::optional GameControllers::GetControllerIndexFromUserID(s32 user_id) { diff --git a/src/input/controller.h b/src/input/controller.h index 8346840b0..1afeb1c93 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -163,72 +163,6 @@ private: std::chrono::steady_clock::time_point m_last_update = {}; Libraries::Pad::OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f}; - u8 player_index = -1; - State m_state; - - std::mutex m_states_queue_mutex; - RingBufferQueue m_states_queue; -}; - -class MoveController { - friend class GameControllers; - -public: - MoveController(); - virtual ~MoveController() = default; - - void ReadState(State* state, bool* isConnected, int* connectedCount); - int ReadStates(State* states, int states_num, bool* isConnected, int* connectedCount); - - void Button(Libraries::Move::OrbisMoveButtonDataOffset button, bool isPressed); - void Axis(Input::Axis axis, int value, bool smooth = true); - void Gyro(int id); - void Acceleration(int id); - void UpdateGyro(const float gyro[3]); - void UpdateAcceleration(const float acceleration[3]); - void UpdateAxisSmoothing(); - void SetLightBarRGB(u8 r, u8 g, u8 b); - bool SetVibration(u8 smallMotor, u8 largeMotor); - void SetTouchpadState(int touchIndex, bool touchDown, float x, float y); - - u8 GetTouchCount(); - void SetTouchCount(u8 touchCount); - u8 GetSecondaryTouchCount(); - void SetSecondaryTouchCount(u8 touchCount); - u8 GetPreviousTouchNum(); - void SetPreviousTouchNum(u8 touchNum); - bool WasSecondaryTouchReset(); - void UnsetSecondaryTouchResetBool(); - - void SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation); - Libraries::Pad::OrbisFQuaternion GetLastOrientation(); - std::chrono::steady_clock::time_point GetLastUpdate(); - void SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate); - static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration, - Libraries::Pad::OrbisFVector3& angularVelocity, - float deltaTime, - Libraries::Pad::OrbisFQuaternion& lastOrientation, - Libraries::Pad::OrbisFQuaternion& orientation); - - float gyro_poll_rate; - float accel_poll_rate; - float gyro_buf[3] = {0.0f, 0.0f, 0.0f}, accel_buf[3] = {0.0f, 9.81f, 0.0f}; - u32 user_id = Libraries::UserService::ORBIS_USER_SERVICE_USER_ID_INVALID; - SDL_Gamepad* m_sdl_gamepad = nullptr; - -private: - void PushState(); - - bool m_connected = true; - int m_connected_count = 1; - u8 m_touch_count = 0; - u8 m_secondary_touch_count = 0; - u8 m_previous_touchnum = 0; - bool m_was_secondary_reset = false; - std::chrono::steady_clock::time_point m_last_update = {}; - Libraries::Pad::OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f}; - - u8 player_index = -1; State m_state; std::mutex m_states_queue_mutex; @@ -237,7 +171,7 @@ private: class GameControllers { std::array controllers; - std::array move_controllers; + std::array move_controllers; static bool override_controller_color; static Colour controller_override_color; @@ -246,8 +180,8 @@ public: GameControllers() : controllers({new GameController(), new GameController(), new GameController(), new GameController()}), - move_controllers({new MoveController(), new MoveController(), new MoveController(), - new MoveController()}) {}; + move_controllers({new GameController(), new GameController(), new GameController(), + new GameController()}) {}; virtual ~GameControllers() = default; GameController* operator[](const size_t& i) const { if (i > 3) { @@ -255,8 +189,15 @@ public: } return controllers[i]; } - static void TryOpenSDLControllers(GameControllers& controllers); - static u8 GetGamepadIndexFromJoystickId(SDL_JoystickID id); + GameController* moves(const size_t& i) const { + if (i > 3) { + UNREACHABLE_MSG("Index {} is out of bounds for GameControllers!", i); + } + return move_controllers[i]; + } + void TryOpenSDLControllers(); + u8 GetGamepadIndexFromJoystickId(SDL_JoystickID id); + u8 GetMoveIndexFromJoystickId(SDL_JoystickID id); static std::optional GetControllerIndexFromUserID(s32 user_id); static std::optional GetControllerIndexFromControllerID(s32 controller_id); diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 689d3db53..577a00834 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -215,11 +215,13 @@ std::list> pressed_keys; std::list toggled_keys; static std::vector connections; -std::array output_arrays = { - ControllerAllOutputs(0), - ControllerAllOutputs(1), - ControllerAllOutputs(2), - ControllerAllOutputs(3), +GameControllers ControllerOutput::controllers = + *Common::Singleton::Instance(); + +std::array output_arrays = { + ControllerAllOutputs(0), ControllerAllOutputs(1), ControllerAllOutputs(2), + ControllerAllOutputs(3), ControllerAllOutputs(4), ControllerAllOutputs(5), + ControllerAllOutputs(6), ControllerAllOutputs(7), }; void ControllerOutput::LinkJoystickAxes() { @@ -263,6 +265,8 @@ static OrbisPadButtonDataOffset SDLGamepadToOrbisButton(u8 button) { return OPBDO::TouchPad; case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER: return OPBDO::L1; + case SDL_GAMEPAD_BUTTON_MISC1: // Move + return OPBDO::L1; case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER: return OPBDO::R1; case SDL_GAMEPAD_BUTTON_LEFT_STICK: @@ -570,7 +574,7 @@ void ParseInputConfig(const std::string game_id = "") { // isn't specified for either inputs or output (both are -1), then multiply the binding and // add it to all 4 controllers if (connection.HasGamepadInput() && input_gamepad_id == -1 && output_gamepad_id == -1) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < output_arrays.size(); i++) { BindingConnection copy = connection.CopyWithChangedGamepadId(i + 1); copy.output = &*std::ranges::find(output_arrays[i].data, *connection.output); connections.push_back(copy); @@ -640,20 +644,29 @@ InputEvent InputBinding::GetInputEventFromSDLEvent(const SDL_Event& e) { e.type == SDL_EVENT_MOUSE_WHEEL, 0); case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: - gamepad = GameControllers::GetGamepadIndexFromJoystickId(e.gbutton.which) + 1; + gamepad = ControllerOutput::controllers.GetGamepadIndexFromJoystickId(e.gbutton.which) + 1; + if (gamepad < 1) { + gamepad = ControllerOutput::controllers.GetMoveIndexFromJoystickId(e.gbutton.which) + 5; + if (gamepad < 5) { + return InputEvent(); + } + } return InputEvent({InputType::Controller, (u32)e.gbutton.button, gamepad}, e.gbutton.down, 0); case SDL_EVENT_GAMEPAD_AXIS_MOTION: - gamepad = GameControllers::GetGamepadIndexFromJoystickId(e.gaxis.which) + 1; + gamepad = ControllerOutput::controllers.GetGamepadIndexFromJoystickId(e.gaxis.which) + 1; + if (gamepad < 1) { + gamepad = ControllerOutput::controllers.GetMoveIndexFromJoystickId(e.gaxis.which) + 5; + if (gamepad < 5) { + return InputEvent(); + } + } return InputEvent({InputType::Axis, (u32)e.gaxis.axis, gamepad}, true, e.gaxis.value / 256); default: return InputEvent(); } } -GameControllers ControllerOutput::controllers = - *Common::Singleton::Instance(); - void ToggleKeyInList(InputID input) { if (input.type == InputType::Axis) { LOG_ERROR(Input, "Toggling analog inputs is not supported!"); @@ -714,9 +727,14 @@ void ControllerOutput::FinalizeUpdate(u8 gamepad_index) { } old_button_state = new_button_state; old_param = *new_param; - bool is_game_specific = EmulatorState::GetInstance()->IsGameSpecifigConfigUsed(); + GameController* controller; + if (gamepad_index < 4) + controller = controllers[gamepad_index]; + else if (gamepad_index < 8) + controller = controllers.moves(gamepad_index - 4); // magic number :( + else + UNREACHABLE(); if (button != SDL_GAMEPAD_BUTTON_INVALID) { - auto controller = controllers[gamepad_index]; switch (button) { case SDL_GAMEPAD_BUTTON_TOUCHPAD_LEFT: controller->SetTouchpadState(0, new_button_state, 0.25f, 0.5f); @@ -816,18 +834,18 @@ void ControllerOutput::FinalizeUpdate(u8 gamepad_index) { break; case Axis::TriggerLeft: ApplyDeadzone(new_param, lefttrigger_deadzone); - controllers[gamepad_index]->Axis(c_axis, GetAxis(0x0, 0x7f, *new_param)); - controllers[gamepad_index]->Button(OrbisPadButtonDataOffset::L2, *new_param > 0x20); + controller->Axis(c_axis, GetAxis(0x0, 0x7f, *new_param)); + controller->Button(OrbisPadButtonDataOffset::L2, *new_param > 0x20); return; case Axis::TriggerRight: ApplyDeadzone(new_param, righttrigger_deadzone); - controllers[gamepad_index]->Axis(c_axis, GetAxis(0x0, 0x7f, *new_param)); - controllers[gamepad_index]->Button(OrbisPadButtonDataOffset::R2, *new_param > 0x20); + controller->Axis(c_axis, GetAxis(0x0, 0x7f, *new_param)); + controller->Button(OrbisPadButtonDataOffset::R2, *new_param > 0x20); return; default: break; } - controllers[gamepad_index]->Axis(c_axis, GetAxis(-0x80, 0x7f, *new_param * multiplier)); + controller->Axis(c_axis, GetAxis(-0x80, 0x7f, *new_param * multiplier)); } } @@ -959,7 +977,7 @@ InputEvent BindingConnection::ProcessBinding() { void ActivateOutputsFromInputs() { // todo find a better solution - for (int i = 0; i < 4; i++) { + for (int i = 0; i < output_arrays.size(); i++) { // Reset values and flags for (auto& it : pressed_keys) { diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 27548cfe3..8baab9fd6 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -432,9 +432,8 @@ public: }; class ControllerOutput { - static GameControllers controllers; - public: + static GameControllers controllers; static void GetGetGamepadIndexFromSDLJoystickID(const SDL_JoystickID id) {} static void LinkJoystickAxes(); @@ -529,7 +528,7 @@ public: class ControllerAllOutputs { public: - static constexpr u64 output_count = 40; + static constexpr u64 output_count = 41; std::array data = { // Important: these have to be the first, or else they will update in the wrong order ControllerOutput(LEFTJOYSTICK_HALFMODE), @@ -554,6 +553,7 @@ public: ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_DOWN), // Down ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_LEFT), // Left ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_RIGHT), // Right + ControllerOutput(SDL_GAMEPAD_BUTTON_MISC1), // Move // Axis mappings // ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFTX, false), @@ -566,7 +566,7 @@ public: ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHTY), ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFT_TRIGGER), - ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER), + ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER), // R2 / Move T ControllerOutput(HOTKEY_FULLSCREEN), ControllerOutput(HOTKEY_PAUSE), diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 853447e30..dfa90ea5a 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -153,7 +153,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameControllers* controller // input handler init-s Input::ControllerOutput::LinkJoystickAxes(); Input::ParseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); - Input::GameControllers::TryOpenSDLControllers(controllers); + controllers.TryOpenSDLControllers(); if (EmulatorSettings.IsBackgroundControllerInput()) { SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); @@ -195,7 +195,7 @@ void WindowSDL::WaitEvent() { break; case SDL_EVENT_GAMEPAD_ADDED: case SDL_EVENT_GAMEPAD_REMOVED: - Input::GameControllers::TryOpenSDLControllers(controllers); + controllers.TryOpenSDLControllers(); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: @@ -354,21 +354,37 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) { // as it would break the entire touchpad handling // You can still bind other things to it though if (event->gbutton.button == SDL_GAMEPAD_BUTTON_TOUCHPAD) { - controllers[Input::GameControllers::GetGamepadIndexFromJoystickId(event->gbutton.which)] - ->Button(OrbisPadButtonDataOffset::TouchPad, input_down); + controllers[controllers.GetGamepadIndexFromJoystickId(event->gbutton.which)]->Button( + OrbisPadButtonDataOffset::TouchPad, input_down); return; } + u8 gamepad; + switch (event->type) { case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: switch ((SDL_SensorType)event->gsensor.sensor) { case SDL_SENSOR_GYRO: - controllers[Input::GameControllers::GetGamepadIndexFromJoystickId(event->gsensor.which)] - ->UpdateGyro(event->gsensor.data); + gamepad = controllers.GetGamepadIndexFromJoystickId(event->gsensor.which); + if (gamepad >= 0) { + controllers[gamepad]->UpdateGyro(event->gsensor.data); + } else { + gamepad = controllers.GetMoveIndexFromJoystickId(event->gsensor.which); + if (gamepad >= 0) { + controllers.moves(gamepad)->UpdateGyro(event->gsensor.data); + } + } break; case SDL_SENSOR_ACCEL: - controllers[Input::GameControllers::GetGamepadIndexFromJoystickId(event->gsensor.which)] - ->UpdateAcceleration(event->gsensor.data); + gamepad = controllers.GetGamepadIndexFromJoystickId(event->gsensor.which); + if (gamepad >= 0) { + controllers[gamepad]->UpdateAcceleration(event->gsensor.data); + } else { + gamepad = controllers.GetMoveIndexFromJoystickId(event->gsensor.which); + if (gamepad >= 0) { + controllers.moves(gamepad)->UpdateAcceleration(event->gsensor.data); + } + } break; default: break; @@ -377,7 +393,7 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) { case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: - controllers[Input::GameControllers::GetGamepadIndexFromJoystickId(event->gtouchpad.which)] + controllers[controllers.GetGamepadIndexFromJoystickId(event->gtouchpad.which)] ->SetTouchpadState(event->gtouchpad.finger, event->type != SDL_EVENT_GAMEPAD_TOUCHPAD_UP, event->gtouchpad.x, event->gtouchpad.y);