as they say, 25th time's the charm

This commit is contained in:
kalaposfos13 2026-03-14 13:49:32 +01:00
parent 5099a17519
commit 92f4b885b1
7 changed files with 157 additions and 125 deletions

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,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,

View File

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

View File

@ -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<u8> GameControllers::GetControllerIndexFromUserID(s32 user_id) {

View File

@ -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<State> 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<GameController*, 4> controllers;
std::array<MoveController*, 4> move_controllers;
std::array<GameController*, 4> 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<u8> GetControllerIndexFromUserID(s32 user_id);
static std::optional<u8> GetControllerIndexFromControllerID(s32 controller_id);

View File

@ -215,11 +215,13 @@ std::list<std::pair<InputEvent, bool>> pressed_keys;
std::list<InputID> toggled_keys;
static std::vector<BindingConnection> connections;
std::array<ControllerAllOutputs, 4> output_arrays = {
ControllerAllOutputs(0),
ControllerAllOutputs(1),
ControllerAllOutputs(2),
ControllerAllOutputs(3),
GameControllers ControllerOutput::controllers =
*Common::Singleton<Input::GameControllers>::Instance();
std::array<ControllerAllOutputs, 8> 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<Input::GameControllers>::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) {

View File

@ -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<ControllerOutput, output_count> 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),

View File

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