Centralize SDL input subsystem ownership for hotplug recovery
This commit is contained in:
parent
e94f0c5990
commit
d174341b6d
7 changed files with 315 additions and 117 deletions
|
|
@ -179,6 +179,7 @@ SOURCES += \
|
|||
settings/streamingpreferences.cpp \
|
||||
streaming/input/abstouch.cpp \
|
||||
streaming/input/gamepad.cpp \
|
||||
streaming/input/sdlinputsubsystems.cpp \
|
||||
streaming/input/input.cpp \
|
||||
streaming/input/keyboard.cpp \
|
||||
streaming/input/mouse.cpp \
|
||||
|
|
@ -219,6 +220,7 @@ HEADERS += \
|
|||
cli/quitstream.h \
|
||||
cli/startstream.h \
|
||||
settings/streamingpreferences.h \
|
||||
streaming/input/sdlinputsubsystems.h \
|
||||
streaming/input/input.h \
|
||||
streaming/session.h \
|
||||
streaming/audio/renderers/renderer.h \
|
||||
|
|
|
|||
|
|
@ -4,10 +4,27 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QWindow>
|
||||
|
||||
#include "settings/mappingmanager.h"
|
||||
#include "streaming/input/sdlinputsubsystems.h"
|
||||
|
||||
#define AXIS_NAVIGATION_REPEAT_DELAY 150
|
||||
|
||||
namespace {
|
||||
|
||||
SdlInputSubsystems::LeaseOptions guiNavSubsystemLeaseOptions()
|
||||
{
|
||||
SdlInputSubsystems::LeaseOptions options = {};
|
||||
options.joystick = true;
|
||||
options.gameController = true;
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
options.haptic = false;
|
||||
#endif
|
||||
options.applyMappings = true;
|
||||
options.flushControllerDeviceEvents = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SdlGamepadKeyNavigation::SdlGamepadKeyNavigation(StreamingPreferences* prefs)
|
||||
: m_Prefs(prefs),
|
||||
m_Enabled(false),
|
||||
|
|
@ -31,32 +48,13 @@ void SdlGamepadKeyNavigation::enable()
|
|||
return;
|
||||
}
|
||||
|
||||
// We have to initialize and uninitialize this in enable()/disable()
|
||||
// because we need to get out of the way of the Session class. If it
|
||||
// doesn't get to reinitialize the GC subsystem, it won't get initial
|
||||
// arrival events. Additionally, there's a race condition between
|
||||
// our QML objects being destroyed and SDL being deinitialized that
|
||||
// this solves too.
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
if (!SdlInputSubsystems::acquire("GuiGamepadNavigation", guiNavSubsystemLeaseOptions())) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
|
||||
SDL_GetError());
|
||||
"Failed to acquire SDL input subsystems for GUI gamepad navigation");
|
||||
return;
|
||||
}
|
||||
|
||||
MappingManager mappingManager;
|
||||
mappingManager.applyMappings();
|
||||
|
||||
// Drop all pending gamepad add events. SDL will generate these for us
|
||||
// on first init of the GC subsystem. We can't depend on them due to
|
||||
// overlapping lifetimes of SdlGamepadKeyNavigation instances, so we
|
||||
// will attach ourselves.
|
||||
//
|
||||
// NB: We use SDL_JoystickUpdate() instead of SDL_PumpEvents() because
|
||||
// the latter can do a bit more work that we want (like handling video
|
||||
// events that we intentionally do not want to process yet).
|
||||
SDL_JoystickUpdate();
|
||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
|
||||
|
||||
// Open all currently attached game controllers
|
||||
int numJoysticks = SDL_NumJoysticks();
|
||||
|
|
@ -90,7 +88,7 @@ void SdlGamepadKeyNavigation::disable()
|
|||
m_Gamepads.removeAt(0);
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
SdlInputSubsystems::release("GuiGamepadNavigation", guiNavSubsystemLeaseOptions());
|
||||
}
|
||||
|
||||
void SdlGamepadKeyNavigation::notifyWindowFocus(bool hasFocus)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <Limelight.h>
|
||||
#include "SDL_compat.h"
|
||||
#include "settings/mappingmanager.h"
|
||||
#include "streaming/input/sdlinputsubsystems.h"
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
|
|
@ -26,6 +26,8 @@ static bool isKeyboardMouseInputAllowed()
|
|||
|
||||
#define HOTPLUG_REENUMERATION_INTERVAL_MS 2000
|
||||
#define HOTPLUG_REENUMERATION_MAX_INTERVAL_MS 8000
|
||||
#define HOTPLUG_REENUMERATION_MIN_ZERO_POLLS 4
|
||||
#define HOTPLUG_REENUMERATION_MIN_LAST_SEEN_MS 500
|
||||
|
||||
// Determines how fast the mouse will move each interval
|
||||
#define MOUSE_EMULATION_MOTION_MULTIPLIER 4
|
||||
|
|
@ -105,10 +107,13 @@ void SdlInputHandler::pollForMissingGamepads()
|
|||
static uint32_t s_LastForcedReenumerationTick = 0;
|
||||
static uint32_t s_ReenumerationIntervalMs = HOTPLUG_REENUMERATION_INTERVAL_MS;
|
||||
static uint32_t s_ReenumerationAttempts = 0;
|
||||
static uint32_t s_ConsecutiveZeroPolls = 0;
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
uint32_t now = SDL_GetTicks();
|
||||
|
||||
auto recoverUntrackedGamepads = [this](int joystickCount) {
|
||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
||||
if (!SDL_IsGameController(deviceIndex)) {
|
||||
|
|
@ -142,9 +147,14 @@ void SdlInputHandler::pollForMissingGamepads()
|
|||
}
|
||||
|
||||
if (joystickCount > 0) {
|
||||
m_LastNonZeroJoystickTick = now;
|
||||
s_ConsecutiveZeroPolls = 0;
|
||||
s_ReenumerationAttempts = 0;
|
||||
s_ReenumerationIntervalMs = HOTPLUG_REENUMERATION_INTERVAL_MS;
|
||||
}
|
||||
else {
|
||||
s_ConsecutiveZeroPolls++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++) {
|
||||
GamepadState* state = &m_GamepadState[i];
|
||||
|
|
@ -177,40 +187,23 @@ void SdlInputHandler::pollForMissingGamepads()
|
|||
|
||||
recoverUntrackedGamepads(joystickCount);
|
||||
|
||||
if (joystickCount == 0) {
|
||||
uint32_t now = SDL_GetTicks();
|
||||
bool shouldAttemptReenumeration =
|
||||
joystickCount == 0 &&
|
||||
m_LastNonZeroJoystickTick != 0 &&
|
||||
s_ConsecutiveZeroPolls >= HOTPLUG_REENUMERATION_MIN_ZERO_POLLS &&
|
||||
SDL_TICKS_PASSED(now, m_LastNonZeroJoystickTick + HOTPLUG_REENUMERATION_MIN_LAST_SEEN_MS);
|
||||
|
||||
if (shouldAttemptReenumeration) {
|
||||
if (SDL_TICKS_PASSED(now, s_LastForcedReenumerationTick + s_ReenumerationIntervalMs)) {
|
||||
s_LastForcedReenumerationTick = now;
|
||||
s_ReenumerationAttempts++;
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"No joysticks visible; forcing SDL joystick/gamecontroller re-enumeration (attempt %u, interval %u ms)",
|
||||
"No joysticks visible after reconciliation; forcing last-resort SDL re-enumeration (attempt %u, interval %u ms)",
|
||||
s_ReenumerationAttempts,
|
||||
s_ReenumerationIntervalMs);
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_JOYSTICK) failed during re-enumeration: %s",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed during re-enumeration: %s",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
MappingManager mappingManager;
|
||||
mappingManager.applyMappings();
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
if (SdlInputSubsystems::reenumerateGamepadSubsystems("StreamInputHotplug")) {
|
||||
joystickCount = SDL_NumJoysticks();
|
||||
if (joystickCount != m_LastJoystickCount) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
|
|
@ -223,6 +216,8 @@ void SdlInputHandler::pollForMissingGamepads()
|
|||
recoverUntrackedGamepads(joystickCount);
|
||||
|
||||
if (joystickCount > 0) {
|
||||
m_LastNonZeroJoystickTick = now;
|
||||
s_ConsecutiveZeroPolls = 0;
|
||||
s_ReenumerationAttempts = 0;
|
||||
s_ReenumerationIntervalMs = HOTPLUG_REENUMERATION_INTERVAL_MS;
|
||||
}
|
||||
|
|
@ -231,6 +226,11 @@ void SdlInputHandler::pollForMissingGamepads()
|
|||
static_cast<uint32_t>(HOTPLUG_REENUMERATION_MAX_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
else {
|
||||
s_ReenumerationIntervalMs = qMin(s_ReenumerationIntervalMs * 2,
|
||||
static_cast<uint32_t>(HOTPLUG_REENUMERATION_MAX_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1236,14 +1236,20 @@ QString SdlInputHandler::getUnmappedGamepads()
|
|||
{
|
||||
QString ret;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
SdlInputSubsystems::LeaseOptions options = {};
|
||||
options.joystick = true;
|
||||
options.gameController = true;
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
options.haptic = false;
|
||||
#endif
|
||||
options.applyMappings = true;
|
||||
options.flushControllerDeviceEvents = false;
|
||||
|
||||
MappingManager mappingManager;
|
||||
mappingManager.applyMappings();
|
||||
if (!SdlInputSubsystems::acquire("UnmappedGamepadProbe", options)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to acquire SDL input subsystems for unmapped gamepad probe");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int numJoysticks = SDL_NumJoysticks();
|
||||
for (int i = 0; i < numJoysticks; i++) {
|
||||
|
|
@ -1286,7 +1292,7 @@ QString SdlInputHandler::getUnmappedGamepads()
|
|||
}
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
SdlInputSubsystems::release("UnmappedGamepadProbe", options);
|
||||
|
||||
// Flush stale events so they aren't processed by the main session event loop
|
||||
SDL_FlushEvents(SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <Limelight.h>
|
||||
#include "SDL_compat.h"
|
||||
#include "streaming/session.h"
|
||||
#include "settings/mappingmanager.h"
|
||||
#include "streaming/input/sdlinputsubsystems.h"
|
||||
#include "path.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
@ -9,6 +9,23 @@
|
|||
#include <QDir>
|
||||
#include <QGuiApplication>
|
||||
|
||||
namespace {
|
||||
|
||||
SdlInputSubsystems::LeaseOptions streamInputSubsystemLeaseOptions()
|
||||
{
|
||||
SdlInputSubsystems::LeaseOptions options = {};
|
||||
options.joystick = true;
|
||||
options.gameController = true;
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
options.haptic = true;
|
||||
#endif
|
||||
options.applyMappings = true;
|
||||
options.flushControllerDeviceEvents = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, int streamHeight)
|
||||
: m_MultiController(prefs.multiController),
|
||||
m_GamepadMouse(prefs.gamepadMouse),
|
||||
|
|
@ -20,6 +37,7 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
|||
m_PointerRegionLockActive(false),
|
||||
m_PointerRegionLockToggledByUser(false),
|
||||
m_LastJoystickCount(-1),
|
||||
m_LastNonZeroJoystickTick(0),
|
||||
m_FakeCaptureActive(false),
|
||||
m_CaptureSystemKeysMode(prefs.captureSysKeysMode),
|
||||
m_MouseCursorCapturedVisibilityState(SDL_DISABLE),
|
||||
|
|
@ -178,45 +196,11 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
|||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, streamIgnoreDevices.toUtf8());
|
||||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, streamIgnoreDevicesExcept.toUtf8());
|
||||
|
||||
// We must initialize joystick explicitly before gamecontroller in order
|
||||
// to ensure we receive gamecontroller attach events for gamepads where
|
||||
// SDL doesn't have a built-in mapping. By starting joystick first, we
|
||||
// can allow mapping manager to update the mappings before GC attach
|
||||
// events are generated.
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_JOYSTICK));
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
|
||||
if (!SdlInputSubsystems::acquire("StreamInput", streamInputSubsystemLeaseOptions())) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_JOYSTICK) failed: %s",
|
||||
SDL_GetError());
|
||||
"Failed to acquire SDL input subsystems for streaming input");
|
||||
}
|
||||
|
||||
MappingManager mappingManager;
|
||||
mappingManager.applyMappings();
|
||||
|
||||
// Flush gamepad arrival and departure events which may be queued before
|
||||
// starting the gamecontroller subsystem again. This prevents us from
|
||||
// receiving duplicate arrival and departure events for the same gamepad.
|
||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
|
||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEREMOVED);
|
||||
|
||||
// We need to reinit this each time, since you only get
|
||||
// an initial set of gamepad arrival events once per init.
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_GAMECONTROLLER));
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_HAPTIC));
|
||||
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_HAPTIC) failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize the gamepad mask with currently attached gamepads to avoid
|
||||
// causing gamepads to unexpectedly disappear and reappear on the host
|
||||
// during stream startup as we detect currently attached gamepads one at a time.
|
||||
|
|
@ -250,16 +234,7 @@ SdlInputHandler::~SdlInputHandler()
|
|||
SDL_RemoveTimer(m_RightButtonReleaseTimer);
|
||||
SDL_RemoveTimer(m_DragTimer);
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_HAPTIC));
|
||||
#endif
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_GAMECONTROLLER));
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_JOYSTICK));
|
||||
SdlInputSubsystems::release("StreamInput", streamInputSubsystemLeaseOptions());
|
||||
|
||||
// Return background event handling to off
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "0");
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ private:
|
|||
|
||||
int m_GamepadMask;
|
||||
int m_LastJoystickCount;
|
||||
uint32_t m_LastNonZeroJoystickTick;
|
||||
GamepadState m_GamepadState[MAX_GAMEPADS];
|
||||
QSet<short> m_KeysDown;
|
||||
bool m_FakeCaptureActive;
|
||||
|
|
|
|||
191
app/streaming/input/sdlinputsubsystems.cpp
Normal file
191
app/streaming/input/sdlinputsubsystems.cpp
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
#include "streaming/input/sdlinputsubsystems.h"
|
||||
|
||||
#include "settings/mappingmanager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
int s_JoystickRefs = 0;
|
||||
int s_GameControllerRefs = 0;
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
int s_HapticRefs = 0;
|
||||
#endif
|
||||
|
||||
bool retainSubsystem(Uint32 subsystem, int& refs, const char* subsystemName, const char* ownerTag)
|
||||
{
|
||||
if (refs == 0 && SDL_InitSubSystem(subsystem) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to initialize %s subsystem for %s: %s",
|
||||
subsystemName,
|
||||
ownerTag,
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
refs++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void releaseSubsystem(Uint32 subsystem, int& refs, const char* subsystemName, const char* ownerTag)
|
||||
{
|
||||
if (refs <= 0) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Ignoring unbalanced release of %s subsystem for %s",
|
||||
subsystemName,
|
||||
ownerTag);
|
||||
refs = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
refs--;
|
||||
if (refs == 0) {
|
||||
SDL_QuitSubSystem(subsystem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace SdlInputSubsystems {
|
||||
|
||||
bool acquire(const char* ownerTag, const LeaseOptions& options)
|
||||
{
|
||||
bool acquiredJoystick = false;
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
bool acquiredGameController = false;
|
||||
bool acquiredHaptic = false;
|
||||
#endif
|
||||
|
||||
if (options.joystick) {
|
||||
if (!retainSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag)) {
|
||||
return false;
|
||||
}
|
||||
acquiredJoystick = true;
|
||||
}
|
||||
|
||||
if (options.gameController) {
|
||||
if (!retainSubsystem(SDL_INIT_GAMECONTROLLER, s_GameControllerRefs, "gamecontroller", ownerTag)) {
|
||||
if (acquiredJoystick) {
|
||||
releaseSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
acquiredGameController = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
if (options.haptic) {
|
||||
if (!retainSubsystem(SDL_INIT_HAPTIC, s_HapticRefs, "haptic", ownerTag)) {
|
||||
if (acquiredGameController) {
|
||||
releaseSubsystem(SDL_INIT_GAMECONTROLLER, s_GameControllerRefs, "gamecontroller", ownerTag);
|
||||
}
|
||||
if (acquiredJoystick) {
|
||||
releaseSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
acquiredHaptic = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (options.applyMappings) {
|
||||
MappingManager mappingManager;
|
||||
mappingManager.applyMappings();
|
||||
}
|
||||
|
||||
if (options.flushControllerDeviceEvents) {
|
||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
|
||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEREMOVED);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void release(const char* ownerTag, const LeaseOptions& options)
|
||||
{
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
if (options.haptic) {
|
||||
releaseSubsystem(SDL_INIT_HAPTIC, s_HapticRefs, "haptic", ownerTag);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (options.gameController) {
|
||||
releaseSubsystem(SDL_INIT_GAMECONTROLLER, s_GameControllerRefs, "gamecontroller", ownerTag);
|
||||
}
|
||||
|
||||
if (options.joystick) {
|
||||
releaseSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag);
|
||||
}
|
||||
}
|
||||
|
||||
bool hasExclusiveGamepadOwnership()
|
||||
{
|
||||
if (s_JoystickRefs != 1 || s_GameControllerRefs != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
if (s_HapticRefs != 1) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reenumerateGamepadSubsystems(const char* ownerTag)
|
||||
{
|
||||
if (!hasExclusiveGamepadOwnership()) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Skipping subsystem re-enumeration for %s due to shared ownership (joystick=%d gamecontroller=%d)",
|
||||
ownerTag,
|
||||
s_JoystickRefs,
|
||||
s_GameControllerRefs);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
|
||||
#endif
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to reinitialize joystick subsystem for %s: %s",
|
||||
ownerTag,
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to reinitialize gamecontroller subsystem for %s: %s",
|
||||
ownerTag,
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to reinitialize haptic subsystem for %s: %s",
|
||||
ownerTag,
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
MappingManager mappingManager;
|
||||
mappingManager.applyMappings();
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
SDL_FlushEvents(SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED);
|
||||
SDL_FlushEvents(SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMAPPED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
25
app/streaming/input/sdlinputsubsystems.h
Normal file
25
app/streaming/input/sdlinputsubsystems.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "SDL_compat.h"
|
||||
|
||||
namespace SdlInputSubsystems {
|
||||
|
||||
struct LeaseOptions {
|
||||
bool joystick;
|
||||
bool gameController;
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
bool haptic;
|
||||
#endif
|
||||
bool applyMappings;
|
||||
bool flushControllerDeviceEvents;
|
||||
};
|
||||
|
||||
bool acquire(const char* ownerTag, const LeaseOptions& options);
|
||||
|
||||
void release(const char* ownerTag, const LeaseOptions& options);
|
||||
|
||||
bool hasExclusiveGamepadOwnership();
|
||||
|
||||
bool reenumerateGamepadSubsystems(const char* ownerTag);
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue