diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index 6c8dad665a..7bd1c63783 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -167,6 +167,31 @@ InputKeyCode SDLJoystick::getKeycodeForButton(SDL_GamepadButton button) { } } +// Called when a pad is disconnected - we won't be getting any more up events from it. +void SDLJoystick::releaseAllKeys() { + for (int i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; i++) { + const InputKeyCode code = getKeycodeForButton((SDL_GamepadButton)i); + if (code == NKCODE_UNKNOWN) { + continue; + } + KeyInput key{}; + key.deviceId = DEVICE_ID_PAD_0; + key.keyCode = code; + key.flags = KeyInputFlags::UP; + NativeKey(key); + } + + // Zero every axis we've actually sent a value for, so sticks and triggers recenter. + for (auto &[key, value] : prevAxisValue_) { + AxisInput axis{}; + axis.deviceId = key.first; + axis.axisId = key.second; + axis.value = 0.0f; + NativeAxis(&axis, 1); + } + prevAxisValue_.clear(); +} + void SDLJoystick::ProcessInput(const SDL_Event &event){ switch (event.type) { case SDL_EVENT_GAMEPAD_BUTTON_DOWN: @@ -211,6 +236,11 @@ void SDLJoystick::ProcessInput(const SDL_Event &event){ SDL_CloseGamepad(*it); controllerDeviceMap.erase(event.gdevice.which); controllers.erase(it); + // Otherwise whatever was held when the pad vanished stays held forever, which + // tends to walk the player off a cliff. Note that we map every pad to pad 0, + // so we can't release just the one that went away. + releaseAllKeys(); + KeyMap::NotifyPadDisconnected(DEVICE_ID_PAD_0); break; } } diff --git a/SDL/SDLJoystick.h b/SDL/SDLJoystick.h index b70669db2b..4fd715b482 100644 --- a/SDL/SDLJoystick.h +++ b/SDL/SDLJoystick.h @@ -20,6 +20,7 @@ private: void setUpControllers(); InputKeyCode getKeycodeForButton(SDL_GamepadButton button); int getDeviceIndex(int instanceId); + void releaseAllKeys(); bool registeredAsEventHandler; std::vector controllers;