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
|
||||
#define MOUSE_EMULATION_POLLING_INTERVAL 50
|
||||
|
||||
#define HOTPLUG_REENUMERATION_INTERVAL_MS 2000
|
||||
|
||||
// Determines how fast the mouse will move each interval
|
||||
#define MOUSE_EMULATION_MOTION_MULTIPLIER 4
|
||||
|
||||
|
|
@ -99,32 +101,117 @@ SdlInputHandler::ensureStateForGamepad(SDL_JoystickID id)
|
|||
|
||||
void SdlInputHandler::pollForMissingGamepads()
|
||||
{
|
||||
static uint32_t s_LastForcedReenumerationTick = 0;
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
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();
|
||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
||||
if (!SDL_IsGameController(deviceIndex)) {
|
||||
SDL_JoystickID jsId = SDL_JoystickGetDeviceInstanceID(deviceIndex);
|
||||
if (jsId < 0 || findStateForGamepad(jsId) != nullptr) {
|
||||
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;
|
||||
}
|
||||
|
||||
SDL_JoystickID jsId = SDL_JoystickGetDeviceInstanceID(deviceIndex);
|
||||
if (jsId < 0 || findStateForGamepad(jsId) != nullptr) {
|
||||
bool presentInDeviceList = false;
|
||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
||||
if (SDL_JoystickGetDeviceInstanceID(deviceIndex) == state->jsId) {
|
||||
presentInDeviceList = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (presentInDeviceList) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Polling recovered missing gamepad add event (device index: %d, instance ID: %d)",
|
||||
deviceIndex,
|
||||
jsId);
|
||||
"Polling detected disconnected gamepad instance %d in slot %d; cleaning up",
|
||||
state->jsId,
|
||||
i);
|
||||
|
||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
||||
controllerEvent.type = SDL_CONTROLLERDEVICEADDED;
|
||||
controllerEvent.which = deviceIndex;
|
||||
controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED;
|
||||
controllerEvent.which = state->jsId;
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
|||
m_PendingMouseButtonsAllUpOnVideoRegionLeave(false),
|
||||
m_PointerRegionLockActive(false),
|
||||
m_PointerRegionLockToggledByUser(false),
|
||||
m_LastJoystickCount(-1),
|
||||
m_FakeCaptureActive(false),
|
||||
m_CaptureSystemKeysMode(prefs.captureSysKeysMode),
|
||||
m_MouseCursorCapturedVisibilityState(SDL_DISABLE),
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ private:
|
|||
bool m_PointerRegionLockToggledByUser;
|
||||
|
||||
int m_GamepadMask;
|
||||
int m_LastJoystickCount;
|
||||
GamepadState m_GamepadState[MAX_GAMEPADS];
|
||||
QSet<short> m_KeysDown;
|
||||
bool m_FakeCaptureActive;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue