i like to move it move it

This commit is contained in:
kalaposfos13 2026-03-28 16:53:02 +01:00
parent df32a2076b
commit 85dbe352e9
9 changed files with 166 additions and 18 deletions

View File

@ -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)

2
externals/sdl3 vendored

@ -1 +1 @@
Subproject commit 4e2fd57e77fb4a28c0eeef0670fc4121cc2cf1f9
Subproject commit 9c51f451c67653fc2e73ed734213308ee7db0707

View File

@ -1,13 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/singleton.h>
#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<Input::GameControllers>::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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -20,6 +20,7 @@ namespace Input {
enum class ControllerType {
Standard,
Move,
};
enum class Axis {
@ -171,13 +172,16 @@ private:
class GameControllers {
std::array<GameController*, 5> controllers;
std::array<GameController*, 4> move_controllers;
static std::array<std::optional<Colour>, 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<u8> GetControllerIndexFromUserID(s32 user_id);
static std::optional<u8> GetControllerIndexFromControllerID(s32 controller_id);

View File

@ -208,7 +208,7 @@ std::filesystem::path GetInputConfigFile(const std::string& game_id) {
}
bool leftjoystick_halfmode = false, rightjoystick_halfmode = false;
std::array<std::pair<int, int>, 4> leftjoystick_deadzone, rightjoystick_deadzone,
std::array<std::pair<int, int>, 9> leftjoystick_deadzone, rightjoystick_deadzone,
lefttrigger_deadzone, righttrigger_deadzone;
std::list<std::pair<InputEvent, bool>> 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<std::pair<int, int>, 4> default_deadzone = {
std::pair{1, 127}, {1, 127}, {1, 127}, {1, 127}};
constexpr std::array<std::pair<int, int>, 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<int, int> deadzone = {*inner_deadzone, *outer_deadzone};
static std::unordered_map<std::string, std::array<std::pair<int, int>, 4>&>
static std::unordered_map<std::string, std::array<std::pair<int, int>, 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) {

View File

@ -130,6 +130,7 @@ const std::map<std::string, u32> 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<std::string, AxisMapping> 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<ControllerOutput, output_count> 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),

View File

@ -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: