Recover gamepad reconnect by forcing SDL re-enumeration
This commit is contained in:
parent
6742e9153c
commit
5f41d9a4c3
3 changed files with 100 additions and 11 deletions
|
|
@ -24,6 +24,8 @@ static bool isKeyboardMouseInputAllowed()
|
||||||
// How long between polling the gamepad to send virtual mouse input
|
// How long between polling the gamepad to send virtual mouse input
|
||||||
#define MOUSE_EMULATION_POLLING_INTERVAL 50
|
#define MOUSE_EMULATION_POLLING_INTERVAL 50
|
||||||
|
|
||||||
|
#define HOTPLUG_REENUMERATION_INTERVAL_MS 2000
|
||||||
|
|
||||||
// Determines how fast the mouse will move each interval
|
// Determines how fast the mouse will move each interval
|
||||||
#define MOUSE_EMULATION_MOTION_MULTIPLIER 4
|
#define MOUSE_EMULATION_MOTION_MULTIPLIER 4
|
||||||
|
|
||||||
|
|
@ -99,32 +101,117 @@ SdlInputHandler::ensureStateForGamepad(SDL_JoystickID id)
|
||||||
|
|
||||||
void SdlInputHandler::pollForMissingGamepads()
|
void SdlInputHandler::pollForMissingGamepads()
|
||||||
{
|
{
|
||||||
|
static uint32_t s_LastForcedReenumerationTick = 0;
|
||||||
|
|
||||||
SDL_JoystickUpdate();
|
SDL_JoystickUpdate();
|
||||||
SDL_GameControllerUpdate();
|
SDL_GameControllerUpdate();
|
||||||
|
|
||||||
cleanupDetachedGamepads();
|
auto recoverUntrackedGamepads = [this](int joystickCount) {
|
||||||
|
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
||||||
|
if (!SDL_IsGameController(deviceIndex)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const int joystickCount = SDL_NumJoysticks();
|
SDL_JoystickID jsId = SDL_JoystickGetDeviceInstanceID(deviceIndex);
|
||||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
if (jsId < 0 || findStateForGamepad(jsId) != nullptr) {
|
||||||
if (!SDL_IsGameController(deviceIndex)) {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Polling recovered missing gamepad add event (device index: %d, instance ID: %d)",
|
||||||
|
deviceIndex,
|
||||||
|
jsId);
|
||||||
|
|
||||||
|
SDL_ControllerDeviceEvent controllerEvent = {};
|
||||||
|
controllerEvent.type = SDL_CONTROLLERDEVICEADDED;
|
||||||
|
controllerEvent.which = deviceIndex;
|
||||||
|
handleControllerDeviceEvent(&controllerEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int joystickCount = SDL_NumJoysticks();
|
||||||
|
if (joystickCount != m_LastJoystickCount) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Detected joystick count change: %d -> %d",
|
||||||
|
m_LastJoystickCount,
|
||||||
|
joystickCount);
|
||||||
|
m_LastJoystickCount = joystickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_GAMEPADS; i++) {
|
||||||
|
GamepadState* state = &m_GamepadState[i];
|
||||||
|
if (state->controller == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_JoystickID jsId = SDL_JoystickGetDeviceInstanceID(deviceIndex);
|
bool presentInDeviceList = false;
|
||||||
if (jsId < 0 || findStateForGamepad(jsId) != nullptr) {
|
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
||||||
|
if (SDL_JoystickGetDeviceInstanceID(deviceIndex) == state->jsId) {
|
||||||
|
presentInDeviceList = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presentInDeviceList) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Polling recovered missing gamepad add event (device index: %d, instance ID: %d)",
|
"Polling detected disconnected gamepad instance %d in slot %d; cleaning up",
|
||||||
deviceIndex,
|
state->jsId,
|
||||||
jsId);
|
i);
|
||||||
|
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
SDL_ControllerDeviceEvent controllerEvent = {};
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEADDED;
|
controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED;
|
||||||
controllerEvent.which = deviceIndex;
|
controllerEvent.which = state->jsId;
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
handleControllerDeviceEvent(&controllerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recoverUntrackedGamepads(joystickCount);
|
||||||
|
|
||||||
|
if (joystickCount == 0) {
|
||||||
|
uint32_t now = SDL_GetTicks();
|
||||||
|
if (SDL_TICKS_PASSED(now, s_LastForcedReenumerationTick + HOTPLUG_REENUMERATION_INTERVAL_MS)) {
|
||||||
|
s_LastForcedReenumerationTick = now;
|
||||||
|
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"No joysticks visible; forcing SDL joystick/gamecontroller re-enumeration");
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
joystickCount = SDL_NumJoysticks();
|
||||||
|
if (joystickCount != m_LastJoystickCount) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Detected joystick count change after re-enumeration: %d -> %d",
|
||||||
|
m_LastJoystickCount,
|
||||||
|
joystickCount);
|
||||||
|
m_LastJoystickCount = joystickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
recoverUntrackedGamepads(joystickCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlInputHandler::cleanupDetachedGamepads()
|
void SdlInputHandler::cleanupDetachedGamepads()
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
||||||
m_PendingMouseButtonsAllUpOnVideoRegionLeave(false),
|
m_PendingMouseButtonsAllUpOnVideoRegionLeave(false),
|
||||||
m_PointerRegionLockActive(false),
|
m_PointerRegionLockActive(false),
|
||||||
m_PointerRegionLockToggledByUser(false),
|
m_PointerRegionLockToggledByUser(false),
|
||||||
|
m_LastJoystickCount(-1),
|
||||||
m_FakeCaptureActive(false),
|
m_FakeCaptureActive(false),
|
||||||
m_CaptureSystemKeysMode(prefs.captureSysKeysMode),
|
m_CaptureSystemKeysMode(prefs.captureSysKeysMode),
|
||||||
m_MouseCursorCapturedVisibilityState(SDL_DISABLE),
|
m_MouseCursorCapturedVisibilityState(SDL_DISABLE),
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,7 @@ private:
|
||||||
bool m_PointerRegionLockToggledByUser;
|
bool m_PointerRegionLockToggledByUser;
|
||||||
|
|
||||||
int m_GamepadMask;
|
int m_GamepadMask;
|
||||||
|
int m_LastJoystickCount;
|
||||||
GamepadState m_GamepadState[MAX_GAMEPADS];
|
GamepadState m_GamepadState[MAX_GAMEPADS];
|
||||||
QSet<short> m_KeysDown;
|
QSet<short> m_KeysDown;
|
||||||
bool m_FakeCaptureActive;
|
bool m_FakeCaptureActive;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue