Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion externals/sdl3
Submodule sdl3 updated 1343 files
58 changes: 53 additions & 5 deletions src/core/libraries/move/move.cpp
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
14 changes: 14 additions & 0 deletions src/core/libraries/move/move.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/system/userservice.h"

Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> 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);
Expand Down
46 changes: 45 additions & 1 deletion src/input/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
13 changes: 12 additions & 1 deletion src/input/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace Input {

enum class ControllerType {
Standard,
Move,
};

enum class Axis {
Expand Down Expand Up @@ -171,22 +172,32 @@ class GameController {

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) {
UNREACHABLE_MSG("Index {} is out of bounds for GameControllers!", i);
}
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);

Expand Down
22 changes: 18 additions & 4 deletions src/input/input_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions src/input/input_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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}},
Expand Down Expand Up @@ -526,7 +528,7 @@ class BindingConnection {

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),
Expand All @@ -551,6 +553,7 @@ class ControllerAllOutputs {
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),
Expand All @@ -563,7 +566,7 @@ class ControllerAllOutputs {
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),
Expand Down
13 changes: 13 additions & 0 deletions src/sdl_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
Expand Down Expand Up @@ -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:
Expand Down
Loading