From 0d93b1add7abfe877f1d221961402afc125be250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 11 Aug 2024 12:07:24 +0200 Subject: [PATCH] Fix composite binds that open chat, console or menus Events with flag `FLAG_RELEASE` must always be forwarded to all components so keys being released can be handled in all components also after some components have been disabled. Closes #8901. --- src/game/client/components/binds.cpp | 37 ++++++++++++++++++---------- src/game/client/gameclient.cpp | 4 ++- src/game/editor/editor.cpp | 4 ++- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index c3fc409cc..3e7ca824d 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include static const ColorRGBA gs_BindPrintColor{1.0f, 1.0f, 0.8f, 1.0f}; @@ -126,7 +128,7 @@ bool CBinds::OnInput(const IInput::CEvent &Event) }); if(ActiveBind == m_vActiveBinds.end()) { - const auto &&OnPress = [&](int Mask) { + const auto &&OnKeyPress = [&](int Mask) { const char *pBind = m_aapKeyBindings[Mask][Event.m_Key]; if(g_Config.m_ClSubTickAiming) { @@ -141,14 +143,14 @@ bool CBinds::OnInput(const IInput::CEvent &Event) if(m_aapKeyBindings[ModifierMask][Event.m_Key]) { - OnPress(ModifierMask); + OnKeyPress(ModifierMask); Handled = true; } else if(m_aapKeyBindings[MODIFIER_NONE][Event.m_Key] && ModifierMask != ((1 << MODIFIER_CTRL) | (1 << MODIFIER_SHIFT)) && ModifierMask != ((1 << MODIFIER_GUI) | (1 << MODIFIER_SHIFT))) { - OnPress(MODIFIER_NONE); + OnKeyPress(MODIFIER_NONE); Handled = true; } } @@ -166,17 +168,30 @@ bool CBinds::OnInput(const IInput::CEvent &Event) if(Event.m_Flags & IInput::FLAG_RELEASE) { + const auto &&OnKeyRelease = [&](const CBindSlot &Bind) { + // Prevent binds from being deactivated while chat, console and menus are open, as these components will + // still allow key release events to be forwarded to this component, so the active binds can be cleared. + if(GameClient()->m_Chat.IsActive() || + !GameClient()->m_GameConsole.IsClosed() || + GameClient()->m_Menus.IsActive()) + { + return; + } + // Have to check for nullptr again because the previous execute can unbind itself + if(!m_aapKeyBindings[Bind.m_ModifierMask][Bind.m_Key]) + { + return; + } + Console()->ExecuteLineStroked(0, m_aapKeyBindings[Bind.m_ModifierMask][Bind.m_Key]); + }; + // Release active bind that uses this primary key auto ActiveBind = std::find_if(m_vActiveBinds.begin(), m_vActiveBinds.end(), [&](const CBindSlot &Bind) { return Event.m_Key == Bind.m_Key; }); if(ActiveBind != m_vActiveBinds.end()) { - // Have to check for nullptr again because the previous execute can unbind itself - if(m_aapKeyBindings[ActiveBind->m_ModifierMask][ActiveBind->m_Key]) - { - Console()->ExecuteLineStroked(0, m_aapKeyBindings[ActiveBind->m_ModifierMask][ActiveBind->m_Key]); - } + OnKeyRelease(*ActiveBind); m_vActiveBinds.erase(ActiveBind); Handled = true; } @@ -191,11 +206,7 @@ bool CBinds::OnInput(const IInput::CEvent &Event) }); if(ActiveModifierBind == m_vActiveBinds.end()) break; - // Have to check for nullptr again because the previous execute can unbind itself - if(m_aapKeyBindings[ActiveModifierBind->m_ModifierMask][ActiveModifierBind->m_Key]) - { - Console()->ExecuteLineStroked(0, m_aapKeyBindings[ActiveModifierBind->m_ModifierMask][ActiveModifierBind->m_Key]); - } + OnKeyRelease(*ActiveModifierBind); m_vActiveBinds.erase(ActiveModifierBind); Handled = true; } diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 1a736508a..b47921ccb 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -447,7 +447,9 @@ void CGameClient::OnUpdate() Input()->ConsumeEvents([&](const IInput::CEvent &Event) { for(auto &pComponent : m_vpInput) { - if(pComponent->OnInput(Event)) + // Events with flag `FLAG_RELEASE` must always be forwarded to all components so keys being + // released can be handled in all components also after some components have been disabled. + if(pComponent->OnInput(Event) && (Event.m_Flags & ~IInput::FLAG_RELEASE) != 0) break; } }); diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 78538e45b..90f36db0b 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -8667,7 +8667,9 @@ void CEditor::OnUpdate() Input()->ConsumeEvents([&](const IInput::CEvent &Event) { for(CEditorComponent &Component : m_vComponents) { - if(Component.OnInput(Event)) + // Events with flag `FLAG_RELEASE` must always be forwarded to all components so keys being + // released can be handled in all components also after some components have been disabled. + if(Component.OnInput(Event) && (Event.m_Flags & ~IInput::FLAG_RELEASE) != 0) return; } Ui()->OnInput(Event);