Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Games: Fix crash on game close after controller disconnects #14676

Merged
merged 1 commit into from
Oct 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion xbmc/games/addons/input/GameClientInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,10 +549,30 @@ void CGameClientInput::ProcessJoysticks()
PERIPHERALS::PeripheralVector joysticks;
CServiceBroker::GetPeripherals().GetPeripheralsWithFeature(joysticks, PERIPHERALS::FEATURE_JOYSTICK);

// Update expired joysticks
PortMap portMapCopy = m_portMap;
for (auto& it : portMapCopy)
{
JOYSTICK::IInputProvider* inputProvider = it.first;
CGameClientJoystick* gameJoystick = it.second;

const bool bExpired = std::find_if(joysticks.begin(), joysticks.end(),
[inputProvider](const PERIPHERALS::PeripheralPtr &joystick)
{
return inputProvider == static_cast<JOYSTICK::IInputProvider*>(joystick.get());
}) == joysticks.end();

if (bExpired)
{
gameJoystick->UnregisterInput(nullptr);
m_portMap.erase(inputProvider);
}
}

// Perform the port mapping
PortMap newPortMap = MapJoysticks(joysticks, m_joysticks);

// Update each joystick
// Update connected joysticks
for (auto& peripheralJoystick : joysticks)
{
// Upcast to input interface
Expand Down
10 changes: 8 additions & 2 deletions xbmc/games/ports/Port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ void CPort::RegisterInput(JOYSTICK::IInputProvider *provider)
void CPort::UnregisterInput(JOYSTICK::IInputProvider *provider)
{
// Unregister in reverse order
if (provider == nullptr)
m_appInput->UnregisterInputProvider();
m_appInput.reset();
provider->UnregisterInputHandler(this);
provider->UnregisterInputHandler(m_inputSink.get());

if (provider != nullptr)
{
provider->UnregisterInputHandler(this);
provider->UnregisterInputHandler(m_inputSink.get());
}
}

std::string CPort::ControllerID() const
Expand Down
8 changes: 5 additions & 3 deletions xbmc/input/joysticks/keymaps/KeymapHandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ void CKeymapHandling::LoadKeymaps()

void CKeymapHandling::UnloadKeymaps()
{
for (auto it = m_inputHandlers.rbegin(); it != m_inputHandlers.rend(); ++it)
m_inputProvider->UnregisterInputHandler(it->get());

if (m_inputProvider != nullptr)
{
for (auto it = m_inputHandlers.rbegin(); it != m_inputHandlers.rend(); ++it)
m_inputProvider->UnregisterInputHandler(it->get());
}
m_inputHandlers.clear();
m_keymaps.clear();
}
11 changes: 10 additions & 1 deletion xbmc/input/joysticks/keymaps/KeymapHandling.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ namespace JOYSTICK

virtual ~CKeymapHandling();

/*!
* \brief Unregister the input provider
*
* Call this if the input provider is invalidated, such as if a user
* disconnects a controller. This prevents accessing the invalidated
* input provider when keymaps are unloaded upon destruction.
*/
void UnregisterInputProvider() { m_inputProvider = nullptr; }

/*!
* \brief
*/
Expand All @@ -54,7 +63,7 @@ namespace JOYSTICK
void UnloadKeymaps();

// Construction parameter
IInputProvider *const m_inputProvider;
IInputProvider *m_inputProvider;
const bool m_pPromiscuous;
const IKeymapEnvironment *const m_environment;

Expand Down