mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-08 16:01:19 +12:00
SDL_GameControllerFromInstanceID does not increase internal ref counter. Fixes a crash when removing an SDL controller that is in use by another profile
167 lines
4.3 KiB
C++
167 lines
4.3 KiB
C++
#include "input/api/SDL/SDLController.h"
|
|
|
|
#include "input/api/SDL/SDLControllerProvider.h"
|
|
|
|
SDLController::SDLController(const SDL_JoystickGUID& guid, size_t guid_index)
|
|
: base_type(fmt::format("{}_", guid_index), fmt::format("Controller {}", guid_index + 1)), m_guid_index(guid_index),
|
|
m_guid(guid)
|
|
{
|
|
char tmp[64];
|
|
SDL_JoystickGetGUIDString(m_guid, tmp, std::size(tmp));
|
|
m_uuid += tmp;
|
|
}
|
|
|
|
SDLController::SDLController(const SDL_JoystickGUID& guid, size_t guid_index, std::string_view display_name)
|
|
: base_type(fmt::format("{}_", guid_index), display_name), m_guid_index(guid_index), m_guid(guid)
|
|
{
|
|
char tmp[64];
|
|
SDL_JoystickGetGUIDString(m_guid, tmp, std::size(tmp));
|
|
m_uuid += tmp;
|
|
}
|
|
|
|
SDLController::~SDLController()
|
|
{
|
|
if (m_controller)
|
|
SDL_GameControllerClose(m_controller);
|
|
}
|
|
|
|
bool SDLController::is_connected()
|
|
{
|
|
std::scoped_lock lock(m_controller_mutex);
|
|
if (!m_controller)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!SDL_GameControllerGetAttached(m_controller))
|
|
{
|
|
m_controller = nullptr;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDLController::connect()
|
|
{
|
|
if (is_connected())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
m_has_rumble = false;
|
|
|
|
const auto index = m_provider->get_index(m_guid_index, m_guid);
|
|
|
|
std::scoped_lock lock(m_controller_mutex);
|
|
m_diid = SDL_JoystickGetDeviceInstanceID(index);
|
|
if (m_diid == -1)
|
|
return false;
|
|
|
|
m_controller = SDL_GameControllerOpen(index);
|
|
if (!m_controller)
|
|
return false;
|
|
|
|
if (const char* name = SDL_GameControllerName(m_controller))
|
|
m_display_name = name;
|
|
|
|
for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i)
|
|
{
|
|
m_buttons[i] = SDL_GameControllerHasButton(m_controller, (SDL_GameControllerButton)i);
|
|
}
|
|
|
|
for (int i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i)
|
|
{
|
|
m_axis[i] = SDL_GameControllerHasAxis(m_controller, (SDL_GameControllerAxis)i);
|
|
}
|
|
|
|
if (SDL_GameControllerHasSensor(m_controller, SDL_SENSOR_ACCEL))
|
|
{
|
|
m_has_accel = true;
|
|
SDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_ACCEL, SDL_TRUE);
|
|
}
|
|
|
|
if (SDL_GameControllerHasSensor(m_controller, SDL_SENSOR_GYRO))
|
|
{
|
|
m_has_gyro = true;
|
|
SDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_GYRO, SDL_TRUE);
|
|
}
|
|
|
|
m_has_rumble = SDL_GameControllerRumble(m_controller, 0, 0, 0) == 0;
|
|
return true;
|
|
}
|
|
|
|
void SDLController::start_rumble()
|
|
{
|
|
std::scoped_lock lock(m_controller_mutex);
|
|
if (is_connected() && !m_has_rumble)
|
|
return;
|
|
|
|
if (m_settings.rumble <= 0)
|
|
return;
|
|
|
|
SDL_GameControllerRumble(m_controller, (Uint16)(m_settings.rumble * 0xFFFF), (Uint16)(m_settings.rumble * 0xFFFF),
|
|
5 * 1000);
|
|
}
|
|
|
|
void SDLController::stop_rumble()
|
|
{
|
|
std::scoped_lock lock(m_controller_mutex);
|
|
if (is_connected() && !m_has_rumble)
|
|
return;
|
|
|
|
SDL_GameControllerRumble(m_controller, 0, 0, 0);
|
|
}
|
|
|
|
MotionSample SDLController::get_motion_sample()
|
|
{
|
|
if (is_connected() && has_motion())
|
|
{
|
|
return m_provider->motion_sample(m_diid);
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
std::string SDLController::get_button_name(uint64 button) const
|
|
{
|
|
if (const char* name = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)button))
|
|
return name;
|
|
|
|
return base_type::get_button_name(button);
|
|
}
|
|
|
|
ControllerState SDLController::raw_state()
|
|
{
|
|
ControllerState result{};
|
|
|
|
std::scoped_lock lock(m_controller_mutex);
|
|
if (!is_connected())
|
|
return result;
|
|
|
|
for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i)
|
|
{
|
|
if (m_buttons[i] && SDL_GameControllerGetButton(m_controller, (SDL_GameControllerButton)i))
|
|
result.buttons.SetButtonState(i, true);
|
|
}
|
|
|
|
if (m_axis[SDL_CONTROLLER_AXIS_LEFTX])
|
|
result.axis.x = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTX) / 32767.0f;
|
|
|
|
if (m_axis[SDL_CONTROLLER_AXIS_LEFTY])
|
|
result.axis.y = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTY) / 32767.0f;
|
|
|
|
if (m_axis[SDL_CONTROLLER_AXIS_RIGHTX])
|
|
result.rotation.x = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTX) / 32767.0f;
|
|
|
|
if (m_axis[SDL_CONTROLLER_AXIS_RIGHTY])
|
|
result.rotation.y = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTY) / 32767.0f;
|
|
|
|
if (m_axis[SDL_CONTROLLER_AXIS_TRIGGERLEFT])
|
|
result.trigger.x = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32767.0f;
|
|
|
|
if (m_axis[SDL_CONTROLLER_AXIS_TRIGGERRIGHT])
|
|
result.trigger.y = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32767.0f;
|
|
|
|
return result;
|
|
}
|