diff --git a/rts/Game/UI/KeyBindings.cpp b/rts/Game/UI/KeyBindings.cpp index 9bafd6ca54..b9f89bba16 100644 --- a/rts/Game/UI/KeyBindings.cpp +++ b/rts/Game/UI/KeyBindings.cpp @@ -269,6 +269,7 @@ void CKeyBindings::Init() keyChainTimeout = 750; buildHotkeyMap = true; + hotkeysDirty = false; debugEnabled = false; codeBindings.reserve(32); @@ -611,6 +612,7 @@ void CKeyBindings::AddActionToKeyMap(KeyMap& bindings, Action& action) ActionList& al = bindings[ks]; action.bindingIndex = ++bindingsCount; al.push_back(action); + hotkeysDirty = true; } else { ActionList& al = it->second; assert(it->first == ks); @@ -624,6 +626,7 @@ void CKeyBindings::AddActionToKeyMap(KeyMap& bindings, Action& action) // not yet bound, push it action.bindingIndex = ++bindingsCount; al.push_back(action); + hotkeysDirty = true; } } } @@ -683,6 +686,9 @@ bool CKeyBindings::UnBind(const std::string& keystr, const std::string& command) if (al.empty()) bindings.erase(it); + if (success) + hotkeysDirty = true; + return success; } @@ -707,6 +713,7 @@ bool CKeyBindings::UnBindKeyset(const std::string& keystr) return false; bindings.erase(it); + hotkeysDirty = true; return true; } @@ -740,7 +747,12 @@ bool CKeyBindings::UnBindAction(const std::string& command) RECOIL_DETAILED_TRACY_ZONE; if (debugEnabled) LOG("[CKeyBindings::%s] command=%s", __func__, command.c_str()); - return RemoveActionFromKeyMap(command, codeBindings) || RemoveActionFromKeyMap(command, scanBindings); + const bool changed = RemoveActionFromKeyMap(command, codeBindings) || RemoveActionFromKeyMap(command, scanBindings); + + if (changed) + hotkeysDirty = true; + + return changed; } @@ -824,6 +836,7 @@ void CKeyBindings::LoadDefaults() } buildHotkeyMap = tmpBuildHotkeyMap; + MaybeRebuildHotkeyMap(); } @@ -930,6 +943,7 @@ bool CKeyBindings::ExecuteCommand(const std::string& line) keyCodes.Reset(); scanCodes.Reset(); bindingsCount = 0; + hotkeysDirty = true; Bind("enter", "chat"); // bare minimum if (debugEnabled) @@ -939,8 +953,7 @@ bool CKeyBindings::ExecuteCommand(const std::string& line) return false; } - if (buildHotkeyMap) - BuildHotkeyMap(); + MaybeRebuildHotkeyMap(); return false; } @@ -979,11 +992,25 @@ bool CKeyBindings::Load(const std::string& filename) loadStack.pop_back(); buildHotkeyMap = tmpBuildHotkeyMap; + MaybeRebuildHotkeyMap(); return true; } +void CKeyBindings::MaybeRebuildHotkeyMap() +{ + RECOIL_DETAILED_TRACY_ZONE; + // buildHotkeyMap is false only while suppressed inside a batch load, so the + // outermost op rebuilds once; hotkeysDirty skips ops that changed nothing. + if (!buildHotkeyMap || !hotkeysDirty) + return; + + BuildHotkeyMap(); + hotkeysDirty = false; +} + + void CKeyBindings::BuildHotkeyMap() { RECOIL_DETAILED_TRACY_ZONE; diff --git a/rts/Game/UI/KeyBindings.h b/rts/Game/UI/KeyBindings.h index 04260a7993..24eb62ca5f 100644 --- a/rts/Game/UI/KeyBindings.h +++ b/rts/Game/UI/KeyBindings.h @@ -58,6 +58,9 @@ class CKeyBindings : public CommandReceiver protected: void BuildHotkeyMap(); + // Rebuilds the reverse cache once per outermost op, and only if bindings + // actually changed (buildHotkeyMap gates batch nesting, hotkeysDirty the change). + void MaybeRebuildHotkeyMap(); void DebugActionList(const ActionList& actionList) const; void AddActionToKeyMap(KeyMap& bindings, Action& action); @@ -91,6 +94,7 @@ class CKeyBindings : public CommandReceiver int keyChainTimeout = 750; bool buildHotkeyMap = true; + bool hotkeysDirty = false; bool debugEnabled = false; };