diff --git a/src/core/commands/HotkeySystem.cpp b/src/core/commands/HotkeySystem.cpp index 4bd36aa..61dbf24 100644 --- a/src/core/commands/HotkeySystem.cpp +++ b/src/core/commands/HotkeySystem.cpp @@ -94,11 +94,11 @@ namespace YimMenu { while (g_Running) { - if (GetForegroundWindow() == *Pointers.Hwnd && !HUD::IS_PAUSE_MENU_ACTIVE() && !HUD::IS_SOCIAL_CLUB_ACTIVE()) + if (GetForegroundWindow() == *Pointers.Hwnd && !HUD::IS_PAUSE_MENU_ACTIVE() && !HUD::IS_SOCIAL_CLUB_ACTIVE() && !m_BeingModified) { for (auto& [hash, link] : m_CommandHotkeys) { - if (link.m_Chain.empty() || link.m_BeingModified) + if (link.m_Chain.empty()) continue; bool all_keys_pressed = true; @@ -158,4 +158,9 @@ namespace YimMenu m_CommandHotkeys[std::atoi(key.data())].m_Chain = value.get>(); } } + + void HotkeySystem::SetBeingModifed(bool being_modified) + { + g_HotkeySystem.m_BeingModified = being_modified; + } } diff --git a/src/core/commands/HotkeySystem.hpp b/src/core/commands/HotkeySystem.hpp index b8c4a10..f9fa5a8 100644 --- a/src/core/commands/HotkeySystem.hpp +++ b/src/core/commands/HotkeySystem.hpp @@ -3,11 +3,11 @@ namespace YimMenu { + // TODO: this should be called something else struct CommandLink { public: std::vector m_Chain{}; - bool m_BeingModified = false; CommandLink() {}; }; @@ -16,6 +16,7 @@ namespace YimMenu private IStateSerializer { std::chrono::system_clock::time_point m_LastHotkeyTriggerTime; + bool m_BeingModified; public: HotkeySystem(); @@ -31,6 +32,8 @@ namespace YimMenu virtual void SaveStateImpl(nlohmann::json& state) override; virtual void LoadStateImpl(nlohmann::json& state) override; + + static void SetBeingModifed(bool being_modified); }; inline HotkeySystem g_HotkeySystem; diff --git a/src/game/frontend/items/CommandItem.cpp b/src/game/frontend/items/CommandItem.cpp index d7f8ae3..59644dc 100644 --- a/src/game/frontend/items/CommandItem.cpp +++ b/src/game/frontend/items/CommandItem.cpp @@ -1,6 +1,7 @@ #include "Items.hpp" #include "core/commands/Commands.hpp" #include "core/commands/Command.hpp" +#include "core/commands/HotkeySystem.hpp" #include "core/backend/FiberPool.hpp" namespace YimMenu @@ -40,16 +41,21 @@ namespace YimMenu ImGui::SetNextWindowSize(ImVec2(500, 120)); if (ImGui::BeginPopupModal(windowLabel.data(), nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar)) { - ImGui::BulletText("Hold the command name clicked to change its hotkey"); - ImGui::BulletText("Press any registered key to remove"); + ImGui::BulletText("Enter a keystroke"); + ImGui::Separator(); - HotkeySetter(m_Command->GetHash()).Draw(); + HotkeySystem::SetBeingModifed(true); + if (auto it = g_HotkeySystem.m_CommandHotkeys.find(m_Command->GetHash()); it != g_HotkeySystem.m_CommandHotkeys.end()) + g_HotkeySystem.CreateHotkey(it->second.m_Chain); ImGui::Spacing(); if (ImGui::Button("Close") || ((!ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered()) && ImGui::IsMouseClicked(ImGuiMouseButton_Left))) + { + HotkeySystem::SetBeingModifed(false); ImGui::CloseCurrentPopup(); + } ImGui::EndPopup(); } diff --git a/src/game/frontend/items/HotkeySetter.cpp b/src/game/frontend/items/HotkeySetter.cpp deleted file mode 100644 index a666395..0000000 --- a/src/game/frontend/items/HotkeySetter.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "Items.hpp" -#include "core/commands/Command.hpp" -#include "core/commands/Commands.hpp" -#include "core/commands/HotkeySystem.hpp" - -namespace YimMenu -{ - HotkeySetter::HotkeySetter(joaat_t command_id) : - m_Id(command_id) - { - } - - void HotkeySetter::Draw() - { - auto Command = Commands::GetCommand(m_Id); - - if (!Command) - ImGui::Text("Unkown Command"); - else - { - CommandLink* CommandHotkeyLink = &g_HotkeySystem.m_CommandHotkeys.at(Command->GetHash()); - - if (!CommandHotkeyLink) - { - ImGui::Text("Unkown CommandLink"); - } - else - { - ImGui::Button(Command->GetLabel().data()); - CommandHotkeyLink->m_BeingModified = ImGui::IsItemActive(); - - if (CommandHotkeyLink->m_BeingModified) - { - g_HotkeySystem.CreateHotkey(CommandHotkeyLink->m_Chain); - } - - ImGui::SameLine(200); - ImGui::BeginGroup(); - - if (CommandHotkeyLink->m_Chain.empty()) - { - if (CommandHotkeyLink->m_BeingModified) - ImGui::Text("Press any button..."); - else - ImGui::Text("No Hotkey Assigned"); - } - else - { - ImGui::PushItemWidth(35); - for (auto HotkeyModifier : CommandHotkeyLink->m_Chain) - { - char KeyLabel[32]; - strcpy(KeyLabel, g_HotkeySystem.GetHotkeyLabel(HotkeyModifier).data()); - ImGui::InputText("##keylabel", KeyLabel, 32, ImGuiInputTextFlags_ReadOnly); - if (ImGui::IsItemClicked()) - std::erase_if(CommandHotkeyLink->m_Chain, [HotkeyModifier](int i) { - return i == HotkeyModifier; - }); - - ImGui::SameLine(); - } - ImGui::PopItemWidth(); - - ImGui::SameLine(); - if (ImGui::Button("Clear")) - { - CommandHotkeyLink->m_Chain.clear(); - } - } - - ImGui::EndGroup(); - } - } - } -} \ No newline at end of file diff --git a/src/game/frontend/items/Items.hpp b/src/game/frontend/items/Items.hpp index 5a294b2..07ebebd 100644 --- a/src/game/frontend/items/Items.hpp +++ b/src/game/frontend/items/Items.hpp @@ -14,6 +14,7 @@ namespace YimMenu class Command; class ColorCommand; class StringCommand; + class CommandLink; class Button : public UIItem { @@ -134,16 +135,6 @@ namespace YimMenu std::function m_Callback; }; - class HotkeySetter : public UIItem - { - public: - explicit HotkeySetter(joaat_t); - void Draw() override; - - private: - joaat_t m_Id; - }; - class Group : public UIItem { public: diff --git a/src/game/frontend/submenus/Settings.cpp b/src/game/frontend/submenus/Settings.cpp index c73afd0..40f8ea5 100644 --- a/src/game/frontend/submenus/Settings.cpp +++ b/src/game/frontend/submenus/Settings.cpp @@ -11,19 +11,80 @@ namespace YimMenu::Submenus // TODO: refactor this static void Hotkeys() { - ImGui::BulletText("Hold the command name clicked to change its hotkey"); - ImGui::BulletText("Press any registered key to remove"); + ImGui::BulletText("Hold the button with the command name and enter a keystroke to change its hotkey"); + ImGui::BulletText("If a command has an existing hotkey, clicking the button will remove it"); ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); + + // this assumes we can't add new commands in runtime, but a lot of other subsystems assume that too + static std::map sortedCommands; + static bool commandsSorted = []() { + for (auto& [hash, command] : Commands::GetCommands()) + { + if (auto it = g_HotkeySystem.m_CommandHotkeys.find(hash); it != g_HotkeySystem.m_CommandHotkeys.end()) + sortedCommands.emplace(command->GetLabel(), it->second); + } + return true; + }(); - for (auto& [Hash, Command] : Commands::GetCommands()) + HotkeySystem::SetBeingModifed(false); + + for (auto& [name, link] : sortedCommands) { - ImGui::PushID(Hash); + ImGui::PushID(link); - if (g_HotkeySystem.m_CommandHotkeys.find(Hash) != g_HotkeySystem.m_CommandHotkeys.end()) - HotkeySetter(Hash).Draw(); + ImGui::Button(name.data()); + + bool active = ImGui::IsItemActive(); + + if (active) + { + HotkeySystem::SetBeingModifed(true); + g_HotkeySystem.CreateHotkey(link->m_Chain); + } + + ImGui::SameLine(250); + ImGui::BeginGroup(); + + if (link->m_Chain.empty()) + { + if (active) + ImGui::Text("Press any button..."); + else + ImGui::Text("No hotkey assigned"); + } + else + { + ImGui::PushItemWidth(35); + int i = 0; + for (auto key : link->m_Chain) + { + char key_label[32]; + strcpy(key_label, g_HotkeySystem.GetHotkeyLabel(key).data()); + + ImGui::PushID(i); + ImGui::InputText("##keylabel", key_label, 32, ImGuiInputTextFlags_ReadOnly); + if (ImGui::IsItemClicked()) + std::erase_if(link->m_Chain, [key](int j) { + return j == key; + }); + ImGui::PopID(); + + i++; + ImGui::SameLine(); + } + ImGui::PopItemWidth(); + + ImGui::SameLine(); + if (ImGui::Button("Clear")) + { + link->m_Chain.clear(); + } + } + + ImGui::EndGroup(); ImGui::Spacing();