InputManager: Clear bindings when input is lost

Cancel active bindings for a disconnected device and when background input is
disabled. Match source cleanup by source type and device index so buttons,
axes, and hats are all reset together.
pull/3800/head
Stenzek 1 week ago
parent 396dae9233
commit 3d16465175
No known key found for this signature in database

@ -169,6 +169,8 @@ static bool ShouldMaskBackgroundInput(InputBindingKey key);
static bool DoEventHook(InputBindingKey key, float value); static bool DoEventHook(InputBindingKey key, float value);
static bool PreprocessEvent(InputBindingKey key, float value, GenericInputBinding generic_key); static bool PreprocessEvent(InputBindingKey key, float value, GenericInputBinding generic_key);
static bool ProcessEvent(InputBindingKey key, float value, bool skip_button_handlers); static bool ProcessEvent(InputBindingKey key, float value, bool skip_button_handlers);
template<typename Predicate>
static void ClearBindState(Predicate&& matches);
static void LoadMacroButtonConfig(const SettingsInterface& si, const std::string& section, u32 pad, static void LoadMacroButtonConfig(const SettingsInterface& si, const std::string& section, u32 pad,
const Controller::ControllerInfo& cinfo); const Controller::ControllerInfo& cinfo);
@ -1309,14 +1311,14 @@ bool InputManager::ProcessEvent(InputBindingKey key, float value, bool skip_butt
return true; return true;
} }
void InputManager::ClearBindStateFromSource(InputBindingKey key) template<typename Predicate>
void InputManager::ClearBindState(Predicate&& matches)
{ {
// Why are we doing it this way? Because any of the bindings could cause a reload and invalidate our iterators :(. // Why are we doing it this way? Because any of the bindings could cause a reload and invalidate our iterators :(.
// Axis handlers should be fine, so we'll do those as a first pass. // Axis handlers should be fine, so we'll do those as a first pass.
for (const auto& [match_key, binding] : s_state.binding_map) for (const auto& [match_key, binding] : s_state.binding_map)
{ {
if (key.source_type != match_key.source_type || key.source_subtype != match_key.source_subtype || if (!matches(match_key) || !IsAxisHandler(binding->handler))
key.source_index != match_key.source_index || !IsAxisHandler(binding->handler))
{ {
continue; continue;
} }
@ -1339,8 +1341,7 @@ void InputManager::ClearBindStateFromSource(InputBindingKey key)
for (const auto& [match_key, binding] : s_state.binding_map) for (const auto& [match_key, binding] : s_state.binding_map)
{ {
if (key.source_type != match_key.source_type || key.source_subtype != match_key.source_subtype || if (!matches(match_key) || IsAxisHandler(binding->handler))
key.source_index != match_key.source_index || IsAxisHandler(binding->handler))
{ {
continue; continue;
} }
@ -1374,6 +1375,13 @@ void InputManager::ClearBindStateFromSource(InputBindingKey key)
} while (matched); } while (matched);
} }
void InputManager::ClearBindStateFromSource(InputBindingKey key)
{
ClearBindState([key](const InputBindingKey& match_key) {
return (key.source_type == match_key.source_type && key.source_index == match_key.source_index);
});
}
void InputManager::SynchronizeBindingHandlerState() void InputManager::SynchronizeBindingHandlerState()
{ {
// should be called on the main thread, so no need to lock // should be called on the main thread, so no need to lock
@ -1652,6 +1660,7 @@ void InputManager::UpdateInputIgnoreState()
if (s_state.ignore_input_events) if (s_state.ignore_input_events)
{ {
VERBOSE_COLOR_LOG(StrongOrange, "Application in background, ignoring input events"); VERBOSE_COLOR_LOG(StrongOrange, "Application in background, ignoring input events");
ClearBindState([](const InputBindingKey& key) { return (key.source_type > InputSourceType::Pointer); });
} }
else else
{ {
@ -1938,6 +1947,7 @@ void InputManager::OnInputDeviceConnected(InputBindingKey key, std::string_view
void InputManager::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier) void InputManager::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier)
{ {
INFO_LOG("Device '{}' disconnected", identifier); INFO_LOG("Device '{}' disconnected", identifier);
ClearBindStateFromSource(key);
Host::OnInputDeviceDisconnected(key, identifier); Host::OnInputDeviceDisconnected(key, identifier);
if (System::IsValid() || VideoThread::IsFullscreenUIRequested()) if (System::IsValid() || VideoThread::IsFullscreenUIRequested())

Loading…
Cancel
Save