From 85dbe352e999d488bf9956c2e151ebbd487bf970 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 28 Mar 2026 16:53:02 +0100 Subject: [PATCH 1/2] i like to move it move it --- CMakeLists.txt | 9 ++--- externals/sdl3 | 2 +- src/core/libraries/move/move.cpp | 58 +++++++++++++++++++++++++++++--- src/core/libraries/move/move.h | 14 ++++++++ src/input/controller.cpp | 46 ++++++++++++++++++++++++- src/input/controller.h | 13 ++++++- src/input/input_handler.cpp | 22 +++++++++--- src/input/input_handler.h | 7 ++-- src/sdl_window.cpp | 13 +++++++ 9 files changed, 166 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbf373e57..b844ea3f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,10 +233,11 @@ find_package(nlohmann_json 3.12 CONFIG) find_package(PNG 1.6 MODULE) find_package(OpenAL CONFIG) find_package(RenderDoc 1.6.0 MODULE) -find_package(SDL3_mixer 2.8.1 CONFIG) -if (SDL3_mixer_FOUND) - find_package(SDL3 3.1.2 CONFIG) -endif() + +# find_package(SDL3_mixer 2.8.1 CONFIG) +# if (SDL3_mixer_FOUND) +# find_package(SDL3 3.1.2 CONFIG) +# endif() find_package(stb MODULE) find_package(toml11 4.2.0 CONFIG) find_package(tsl-robin-map 1.3.0 CONFIG) diff --git a/externals/sdl3 b/externals/sdl3 index 4e2fd57e7..9c51f451c 160000 --- a/externals/sdl3 +++ b/externals/sdl3 @@ -1 +1 @@ -Subproject commit 4e2fd57e77fb4a28c0eeef0670fc4121cc2cf1f9 +Subproject commit 9c51f451c67653fc2e73ed734213308ee7db0707 diff --git a/src/core/libraries/move/move.cpp b/src/core/libraries/move/move.cpp index b7e86a2d7..6e460c737 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,51 @@ 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(R2, 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_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, @@ -83,15 +123,23 @@ s32 PS4_SYSV_ABI sceMoveSetVibration(s32 handle, u8 intensity) { if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } - return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; + 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_TRACE(Lib_Move, "called"); + LOG_DEBUG(Lib_Move, "called"); if (!g_library_initialized) { return ORBIS_MOVE_ERROR_NOT_INIT; } - return ORBIS_MOVE_ERROR_NO_CONTROLLER_CONNECTED; + 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) { diff --git a/src/core/libraries/move/move.h b/src/core/libraries/move/move.h index 7300226e3..e868f9072 100644 --- a/src/core/libraries/move/move.h +++ b/src/core/libraries/move/move.h @@ -3,6 +3,7 @@ #pragma once +#include "common/enum.h" #include "common/types.h" #include "core/libraries/system/userservice.h" @@ -17,6 +18,19 @@ struct OrbisMoveDeviceInfo { float accelerometer_offset[3]; }; +enum class OrbisMoveButtonDataOffset : u16 { + Select = (1 << 0), + T = (1 << 1), + Move = (1 << 2), + Start = (1 << 3), + Triangle = (1 << 4), + Circle = (1 << 5), + Cross = (1 << 6), + Square = (1 << 7), + Intercepted = (1 << 15), +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisMoveButtonDataOffset) + struct OrbisMoveButtonData { u16 button_data; u16 trigger_data; diff --git a/src/input/controller.cpp b/src/input/controller.cpp index c1ba584e3..48d7602f1 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -269,6 +269,41 @@ void GameControllers::TryOpenSDLControllers() { 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 + auto c = move_controllers[move_count]; + c->m_sdl_gamepad = pad; + auto u = UserManagement.GetDefaultUser(); + c->user_id = u.user_id; + c->m_connected = true; + move_count++; + if (SDL_SetGamepadSensorEnabled(c->m_sdl_gamepad, SDL_SENSOR_GYRO, true)) { + c->gyro_poll_rate = + SDL_GetGamepadSensorDataRate(c->m_sdl_gamepad, SDL_SENSOR_GYRO); + LOG_INFO(Input, "Gyro initialized, poll rate: {}", c->gyro_poll_rate); + } else { + LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad {}", + c->user_id); + } + if (SDL_SetGamepadSensorEnabled(c->m_sdl_gamepad, SDL_SENSOR_ACCEL, true)) { + c->accel_poll_rate = + SDL_GetGamepadSensorDataRate(c->m_sdl_gamepad, SDL_SENSOR_ACCEL); + LOG_INFO(Input, "Accel initialized, poll rate: {}", c->accel_poll_rate); + } else { + LOG_ERROR(Input, "Failed to initialize accel controls for gamepad {}", + c->user_id); + } + } + continue; + } + for (int i = 0; i < 4; i++) { if (!slot_taken[i]) { auto u = UserManagement.GetUserByPlayerIndex(i + 1); @@ -381,7 +416,16 @@ u8 GameControllers::GetGamepadIndexFromJoystickId(SDL_JoystickID id) { return i; } } - // LOG_TRACE(Input, "Gamepad index: {}", 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; + } + } return -1; } diff --git a/src/input/controller.h b/src/input/controller.h index 1c711c488..4cf9969fa 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -20,6 +20,7 @@ namespace Input { enum class ControllerType { Standard, + Move, }; enum class Axis { @@ -171,13 +172,16 @@ private: class GameControllers { std::array controllers; + std::array move_controllers; static std::array, 4> controller_override_colors; public: GameControllers() : controllers({new GameController(), new GameController(), new GameController(), - new GameController(), new GameController()}) {}; + new GameController(), new GameController()}), + move_controllers({new GameController(), new GameController(), new GameController(), + new GameController()}) {}; virtual ~GameControllers() = default; GameController* operator[](const size_t& i) const { if (i > 4) { @@ -185,8 +189,15 @@ public: } return controllers[i]; } + 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 cf258235d..67d5ba02f 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -208,7 +208,7 @@ std::filesystem::path GetInputConfigFile(const std::string& game_id) { } bool leftjoystick_halfmode = false, rightjoystick_halfmode = false; -std::array, 4> leftjoystick_deadzone, rightjoystick_deadzone, +std::array, 9> leftjoystick_deadzone, rightjoystick_deadzone, lefttrigger_deadzone, righttrigger_deadzone; std::list> pressed_keys; @@ -354,8 +354,8 @@ void ParseInputConfig(const std::string game_id = "") { float mouse_speed_offset = 0.125; // me when I'm in a type deduction tournament and my opponent is clang - constexpr std::array, 4> default_deadzone = { - std::pair{1, 127}, {1, 127}, {1, 127}, {1, 127}}; + constexpr std::array, 9> default_deadzone = { + std::pair{1, 127}, {1, 127}, {1, 127}, {1, 127}, {1, 127}, {1, 127}, {1, 127}, {1, 127}}; leftjoystick_deadzone = default_deadzone; rightjoystick_deadzone = default_deadzone; @@ -491,7 +491,7 @@ void ParseInputConfig(const std::string game_id = "") { std::pair deadzone = {*inner_deadzone, *outer_deadzone}; - static std::unordered_map, 4>&> + static std::unordered_map, 9>&> deadzone_map = { {"leftjoystick", leftjoystick_deadzone}, {"rightjoystick", rightjoystick_deadzone}, @@ -644,10 +644,22 @@ InputEvent InputBinding::GetInputEventFromSDLEvent(const SDL_Event& e) { case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: gamepad = ControllerOutput::controllers.GetGamepadIndexFromJoystickId(e.gbutton.which) + 1; + if (gamepad == 0) { + gamepad = ControllerOutput::controllers.GetMoveIndexFromJoystickId(e.gbutton.which) + 6; + if (gamepad < 6) { + return InputEvent(); + } + } return InputEvent({InputType::Controller, (u32)e.gbutton.button, gamepad}, e.gbutton.down, 0); case SDL_EVENT_GAMEPAD_AXIS_MOTION: gamepad = ControllerOutput::controllers.GetGamepadIndexFromJoystickId(e.gaxis.which) + 1; + if (gamepad < 1) { + gamepad = ControllerOutput::controllers.GetMoveIndexFromJoystickId(e.gaxis.which) + 6; + if (gamepad < 6) { + return InputEvent(); + } + } return InputEvent({InputType::Axis, (u32)e.gaxis.axis, gamepad}, true, e.gaxis.value / 256); default: return InputEvent(); @@ -717,6 +729,8 @@ void ControllerOutput::FinalizeUpdate(u8 gamepad_index) { GameController* controller; if (gamepad_index < 5) controller = controllers[gamepad_index]; + else if (gamepad_index < 9) + controller = controllers.moves(gamepad_index - 5); // magic number :( else UNREACHABLE(); if (button != SDL_GAMEPAD_BUTTON_INVALID) { diff --git a/src/input/input_handler.h b/src/input/input_handler.h index ee286aea9..e002e2fdc 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -130,6 +130,7 @@ const std::map string_to_cbutton_map = { {"pad_left", SDL_GAMEPAD_BUTTON_DPAD_LEFT}, {"pad_right", SDL_GAMEPAD_BUTTON_DPAD_RIGHT}, {"options", SDL_GAMEPAD_BUTTON_START}, + {"move", SDL_GAMEPAD_BUTTON_MISC1}, // these are outputs only (touchpad can only be bound to itself) {"touchpad_left", SDL_GAMEPAD_BUTTON_TOUCHPAD_LEFT}, @@ -175,6 +176,7 @@ const std::map string_to_axis_map = { {"l2", {SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 127}}, {"r2", {SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 127}}, + {"move_t", {SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 127}}, // should only use these to bind analog inputs to analog outputs {"axis_left_x", {SDL_GAMEPAD_AXIS_LEFTX, 127}}, @@ -526,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), @@ -551,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), @@ -563,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 766a336c2..98f702e6f 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -294,6 +294,9 @@ void WindowSDL::WaitEvent() { void WindowSDL::InitTimers() { for (int i = 0; i < 4; ++i) { SDL_AddTimer(4, &PollController, controllers[i]); + SDL_AddTimer(13, &PollController, controllers.moves(i)); + // the move ball resets every 5 seconds, however, for some reason this flickers + SDL_AddTimer(500, &PollControllerLightColour, controllers.moves(i)); } SDL_AddTimer(33, Input::MousePolling, (void*)controllers[0]); } @@ -377,12 +380,22 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) { gamepad = controllers.GetGamepadIndexFromJoystickId(event->gsensor.which); if (gamepad < 5) { controllers[gamepad]->UpdateGyro(event->gsensor.data); + } else { + gamepad = controllers.GetMoveIndexFromJoystickId(event->gsensor.which); + if (gamepad < 4) { + controllers.moves(gamepad)->UpdateGyro(event->gsensor.data); + } } break; case SDL_SENSOR_ACCEL: gamepad = controllers.GetGamepadIndexFromJoystickId(event->gsensor.which); if (gamepad < 5) { controllers[gamepad]->UpdateAcceleration(event->gsensor.data); + } else { + gamepad = controllers.GetMoveIndexFromJoystickId(event->gsensor.which); + if (gamepad < 4) { + controllers.moves(gamepad)->UpdateAcceleration(event->gsensor.data); + } } break; default: From 67a0f1c52fd6e285392fac989aba8929ce6ae23f Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:00:42 +0100 Subject: [PATCH 2/2] ??? --- src/emulator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/emulator.cpp b/src/emulator.cpp index 034d30ed8..7e62680f6 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -322,6 +322,8 @@ void Emulator::Run(std::filesystem::path file, std::vector args, Common::FS::GetUserPath(Common::FS::PathType::HomeDir) / std::to_string(user.user_id) / "trophy" / (npCommId + ".xml"); if (!std::filesystem::exists(user_trophy_file)) { + auto temp = user_trophy_file.parent_path(); + std::filesystem::create_directories(temp); std::error_code discard; std::filesystem::copy_file(trophyDir / "Xml" / "TROPCONF.XML", user_trophy_file, discard);