From 4f8d969ce5da42c5c4f3d2697aa2c80f9710d7d8 Mon Sep 17 00:00:00 2001 From: Arnaud Jamin Date: Fri, 24 Jan 2025 01:19:18 -0500 Subject: [PATCH] CogWindow: Change the way Cog shortcuts are treated Shortcuts to enable imgui (F1), enable actor selection (F5), loading and saving layouts, used to be handled by registering console commands with shortcuts. Now console commands can still be executed, but the shortcuts are handled by directly checking if the corresponding key is pressed from the UPlayerInput when imgui do not need Text input. This should fix cases where the console shortcuts were not executed (typically with CommonUI menus) --- .../CogEngineWindow_CommandBindings.cpp | 13 +- .../Private/CogEngineWindow_Selection.cpp | 57 +----- .../Public/CogEngineWindow_Selection.h | 10 - .../CogImgui/Private/CogImguiInputHelper.cpp | 87 ++++++++- .../CogImgui/Public/CogImguiInputHelper.h | 8 + .../CogWindow/Private/CogWindowManager.cpp | 177 +++++++++++------- .../CogWindow/Private/CogWindowWidgets.cpp | 57 +++++- .../CogWindow/Private/CogWindow_Layouts.cpp | 29 ++- .../CogWindow/Private/CogWindow_Settings.cpp | 54 +++++- .../CogWindow/Public/CogWindowManager.h | 25 ++- .../CogWindow/Public/CogWindow_Settings.h | 24 +++ 11 files changed, 365 insertions(+), 176 deletions(-) diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp index b194c7b..b14f885 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp @@ -50,17 +50,11 @@ void FCogEngineWindow_CommandBindings::RenderContent() ImGui::SameLine(); if (FCogWindowWidgets::ButtonWithTooltip( - "Register Default Commands", - "Register the default commands used to control Cog:\n\n" - "[Tab] Cog.ToggleInput\n" - "[F1] Cog.LoadLayout 1\n" - "[F2] Cog.LoadLayout 2\n" - "[F3] Cog.LoadLayout 3\n" - "[F4] Cog.LoadLayout 4\n" - "[F5] Cog.ToggleSelectionMode\n" + "Disable Conflicting Commands", + "Disable the existing Unreal command shortcuts mapped to same shortcuts Cog is using. Typically, if the F1 shortcut is used to toggle Inputs, the Unreal wireframe command will get disabled." )) { - GetOwner()->RegisterDefaultCommandBindings(); + GetOwner()->DisableConflictingCommands(); } for (FKeyBind& KeyBind : PlayerInput->DebugExecBindings) @@ -79,7 +73,6 @@ void FCogEngineWindow_CommandBindings::RenderContent() PlayerInput->SaveConfig(); } - ImGui::PopID(); Index++; } diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp index 710ede4..fe34328 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp @@ -9,6 +9,7 @@ #include "CogWindowConsoleCommandManager.h" #include "CogWindowManager.h" #include "CogWindowWidgets.h" +#include "CogWindow_Settings.h" #include "Components/PrimitiveComponent.h" #include "EngineUtils.h" #include "GameFramework/Character.h" @@ -35,7 +36,7 @@ void FCogEngineWindow_Selection::Initialize() GetWorld(), FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) { - ToggleSelectionMode(); + GetOwner()->SetActivateSelectionMode(!GetOwner()->GetActivateSelectionMode()); })); TryReapplySelection(); @@ -122,49 +123,11 @@ TSubclassOf FCogEngineWindow_Selection::GetSelectedActorClass() const } //-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Selection::ToggleSelectionMode() -{ - if (bSelectionModeActive) - { - DeactivateSelectionMode(); - } - else - { - ActivateSelectionMode(); - } -} - -//-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Selection::ActivateSelectionMode() -{ - bSelectionModeActive = true; - bIsInputEnabledBeforeEnteringSelectionMode = GetOwner()->GetContext().GetEnableInput(); - GetOwner()->GetContext().SetEnableInput(true); - GetOwner()->SetActivateSelectionMode(true); -} - -//-------------------------------------------------------------------------------------------------------------------------- - void FCogEngineWindow_Selection::HackWaitInputRelease() { WaitInputReleased = 1; } -//-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Selection::DeactivateSelectionMode() -{ - bSelectionModeActive = false; - - //-------------------------------------------------------------------------------------------- - // We can enter selection mode by a command, and ImGui might not have the input focus - // When in selection mode we need ImGui to have the input focus - // When leaving selection mode we want to leave it as it was before - //-------------------------------------------------------------------------------------------- - GetOwner()->GetContext().SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode); - - GetOwner()->SetActivateSelectionMode(false); -} - //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_Selection::RenderTick(float DeltaTime) { @@ -175,7 +138,7 @@ void FCogEngineWindow_Selection::RenderTick(float DeltaTime) SetGlobalSelection(GetLocalPlayerPawn()); } - if (bSelectionModeActive) + if (GetOwner()->GetActivateSelectionMode()) { TickSelectionMode(); } @@ -198,7 +161,7 @@ void FCogEngineWindow_Selection::RenderContent() { if (ImGui::MenuItem("Pick")) { - ActivateSelectionMode(); + GetOwner()->SetActivateSelectionMode(true); //HackWaitInputRelease(); } @@ -242,14 +205,14 @@ void FCogEngineWindow_Selection::TickSelectionMode() { if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { - DeactivateSelectionMode(); + GetOwner()->SetActivateSelectionMode(false); return; } APlayerController* PlayerController = GetLocalPlayerController(); if (PlayerController == nullptr) { - DeactivateSelectionMode(); + GetOwner()->SetActivateSelectionMode(false); return; } @@ -309,7 +272,7 @@ void FCogEngineWindow_Selection::TickSelectionMode() FCogWindowWidgets::ActorFrame(*HoveredActor); } - if (bSelectionModeActive) + if (GetOwner()->GetActivateSelectionMode()) { if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { @@ -320,7 +283,7 @@ void FCogEngineWindow_Selection::TickSelectionMode() SetGlobalSelection(HoveredActor); } - DeactivateSelectionMode(); + GetOwner()->SetActivateSelectionMode(false); } else { @@ -357,7 +320,7 @@ void FCogEngineWindow_Selection::RenderMainMenuWidget(int32 SubWidgetIndex, floa if (ImGui::Button("Pick", ImVec2(Width, 0))) { - ActivateSelectionMode(); + GetOwner()->SetActivateSelectionMode(true); HackWaitInputRelease(); } RenderPickButtonTooltip(); @@ -422,7 +385,7 @@ void FCogEngineWindow_Selection::RenderPickButtonTooltip() { if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) { - const FString Shortcut = FCogImguiInputHelper::CommandToString(*GetWorld(), ToggleSelectionModeCommand); + const FString Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->ToggleSelectionShortcut); ImGui::SetTooltip("Enter picking mode to pick an actor on screen. %s", TCHAR_TO_ANSI(*Shortcut)); } } \ No newline at end of file diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h index d40fc94..026b828 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h @@ -23,8 +23,6 @@ public: virtual void Shutdown() override; - bool GetIsSelecting() const { return bSelectionModeActive; } - const TArray>& GetActorClasses() const { return ActorClasses; } void SetActorClasses(const TArray>& Value) { ActorClasses = Value; } @@ -33,12 +31,6 @@ public: void SetTraceType(ETraceTypeQuery Value) { TraceType = Value; } - virtual void ActivateSelectionMode(); - - virtual void DeactivateSelectionMode(); - - virtual void ToggleSelectionMode(); - protected: virtual void TryReapplySelection() const; @@ -73,8 +65,6 @@ protected: FVector LastSelectedActorLocation = FVector::ZeroVector; - bool bSelectionModeActive = false; - bool bIsInputEnabledBeforeEnteringSelectionMode = false; int32 WaitInputReleased = 0; diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp index fd7e593..fc26e4e 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp @@ -95,6 +95,18 @@ bool FCogImguiInputHelper::IsCheckBoxStateMatchingValue(ECheckBoxState CheckBoxS const bool Result = (CheckBoxState == ECheckBoxState::Undetermined) || ((CheckBoxState == ECheckBoxState::Checked) == bValue); return Result; } + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogImguiInputHelper::IsCheckBoxStateMatchingKeybindModifier(ECheckBoxState InCheckBoxState, bool InRequireModifier, bool InIgnoreModifier) +{ + switch (InCheckBoxState) + { + case ECheckBoxState::Undetermined: return true; + case ECheckBoxState::Checked: return InRequireModifier && InIgnoreModifier == false; + case ECheckBoxState::Unchecked: return InRequireModifier == false && InIgnoreModifier; + } + return false; +} //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiInputHelper::IsKeyEventMatchingKeyInfo(const FKeyEvent& KeyEvent, const FCogImGuiKeyInfo& KeyInfo) @@ -166,6 +178,18 @@ void FCogImguiInputHelper::KeyInfoToKeyBind(const FCogImGuiKeyInfo& KeyInfo, FKe BREAK_CHECKBOX_STATE(KeyInfo.Cmd, KeyBind.Cmd, KeyBind.bIgnoreCmd); } +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogImguiInputHelper::IsKeyBindMatchingKeyInfo(const FKeyBind& InKeyBind, const FCogImGuiKeyInfo& InKeyInfo) +{ + const bool Result = (InKeyInfo.Key == InKeyBind.Key) + && IsCheckBoxStateMatchingKeybindModifier(InKeyInfo.Shift, InKeyBind.Shift, InKeyBind.bIgnoreShift) + && IsCheckBoxStateMatchingKeybindModifier(InKeyInfo.Ctrl, InKeyBind.Control, InKeyBind.bIgnoreCtrl) + && IsCheckBoxStateMatchingKeybindModifier(InKeyInfo.Alt, InKeyBind.Alt, InKeyBind.bIgnoreAlt) + && IsCheckBoxStateMatchingKeybindModifier(InKeyInfo.Cmd, InKeyBind.Cmd, InKeyBind.bIgnoreCmd); + + return Result; +} + //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiInputHelper::WasKeyInfoJustPressed(APlayerController& PlayerController, const FCogImGuiKeyInfo& KeyInfo) { @@ -304,32 +328,67 @@ FString FCogImguiInputHelper::CommandToString(const UPlayerInput* PlayerInput, c //-------------------------------------------------------------------------------------------------------------------------- FString FCogImguiInputHelper::KeyBindToString(const FKeyBind& KeyBind) { - FString Result; + FString Result = "["; if (KeyBind.Alt) { - Result = Result.Append("Alt "); + Result += FString("Alt "); } if (KeyBind.Shift) { - Result = Result.Append("Shift "); + Result += FString("Shift "); } if (KeyBind.Control) { - Result = Result.Append("Ctrl "); + Result += FString("Ctrl "); } if (KeyBind.Cmd) { - Result = Result.Append("Cmd "); + Result += FString("Cmd "); } - Result = Result.Printf(TEXT("[%s]"), *KeyBind.Key.ToString()); + Result += KeyBind.Key.ToString(); + Result += FString("]"); return Result; } +//-------------------------------------------------------------------------------------------------------------------------- +FString FCogImguiInputHelper::KeyInfoToString(const FCogImGuiKeyInfo& InKeyInfo) +{ + if (InKeyInfo == FKey()) + { + return FString(""); + } + + FString Result = "["; + if (InKeyInfo.Alt == ECheckBoxState::Checked) + { + Result += FString("Alt "); + } + + if (InKeyInfo.Shift == ECheckBoxState::Checked) + { + Result += FString("Shift "); + } + + if (InKeyInfo.Ctrl == ECheckBoxState::Checked) + { + Result += FString("Ctrl "); + } + + if (InKeyInfo.Cmd == ECheckBoxState::Checked) + { + Result += FString("Cmd "); + } + + Result += InKeyInfo.Key.ToString(); + Result += FString("]"); + + return Result; +} //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiInputHelper::IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent, const FKeyBind& KeyBind) @@ -364,6 +423,22 @@ bool FCogImguiInputHelper::IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent, return false; } +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogImguiInputHelper::IsKeyInfoPressed(const UPlayerInput* PlayerInput, const FCogImGuiKeyInfo& InKeyInfo) +{ + const bool bKeyPressed = PlayerInput->WasJustPressed(InKeyInfo.Key); + if (bKeyPressed == false) + { return false; } + + if (IsCheckBoxStateMatchingValue(InKeyInfo.Ctrl, PlayerInput->IsCtrlPressed()) + && IsCheckBoxStateMatchingValue(InKeyInfo.Shift, PlayerInput->IsShiftPressed()) + && IsCheckBoxStateMatchingValue(InKeyInfo.Alt, PlayerInput->IsAltPressed()) + && IsCheckBoxStateMatchingValue(InKeyInfo.Cmd, PlayerInput->IsCmdPressed())) + { return true; } + + return false; +} + //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiInputHelper::IsKeyBoundToCommand(const UPlayerInput* InPlayerInput, const FKeyEvent& KeyEvent) { diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h index 6fcb468..dd58c06 100644 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h +++ b/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h @@ -28,10 +28,16 @@ public: static bool IsCheckBoxStateMatchingValue(ECheckBoxState CheckBoxState, bool bValue); + static bool IsCheckBoxStateMatchingKeybindModifier(ECheckBoxState InCheckBoxState, bool InRequireModifier, bool InIgnoreModifier); + static bool IsKeyEventMatchingKeyInfo(const FKeyEvent& KeyEvent, const FCogImGuiKeyInfo& InputChord); + static bool IsKeyBindMatchingKeyInfo(const FKeyBind& InKeyBind, const FCogImGuiKeyInfo& InKeyInfo); + static bool IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent, const FKeyBind& KeyBind); + static bool IsKeyInfoPressed(const UPlayerInput* PlayerInput, const FCogImGuiKeyInfo& InKeyInfo); + static ECheckBoxState MakeCheckBoxState(uint8 RequireValue, uint8 IgnoreValue); static void KeyBindToKeyInfo(const FKeyBind& KeyBind, FCogImGuiKeyInfo& KeyInfo); @@ -56,6 +62,8 @@ public: static FString KeyBindToString(const FKeyBind& KeyBind); + static FString KeyInfoToString(const FCogImGuiKeyInfo& InKeyInfo); + static bool IsMouseInsideMainViewport(); static bool IsKeyBoundToCommand(const UPlayerInput* InPlayerInput, const FKeyEvent& KeyEvent); diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp index c7b7e54..20a51f6 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp @@ -27,28 +27,6 @@ UCogWindowManager::UCogWindowManager() { } -//-------------------------------------------------------------------------------------------------------------------------- -void UCogWindowManager::PostInitProperties() -{ - Super::PostInitProperties(); - - //if (bRegisterDefaultCommands) - //{ - // if (RegisterDefaultCommandBindings()) - // { - // bRegisterDefaultCommands = false; - // } - //} - - //------------------------------------------------------------------------------- - // Currently always register default commands. - // Since UE5.4, the ini files must have this to be saved: - // [SectionsToSave] - // bCanSaveAllSections = True - //------------------------------------------------------------------------------- - RegisterDefaultCommandBindings(); -} - //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::InitializeInternal() { @@ -72,6 +50,12 @@ void UCogWindowManager::InitializeInternal() SpaceWindows.Add(AddWindow("Spacing 3", false)); SpaceWindows.Add(AddWindow("Spacing 4", false)); + Settings = GetConfig(); + if (Settings->bResolveShortcutsConflicts) + { + DisableConflictingCommands(); + } + LayoutsWindow = AddWindow("Window.Layouts", false); SettingsWindow = AddWindow("Window.Settings", false); @@ -182,7 +166,7 @@ void UCogWindowManager::Tick(float DeltaTime) { return; } - + if (IsInitialized == false) { InitializeInternal(); @@ -205,6 +189,7 @@ void UCogWindowManager::Tick(float DeltaTime) if (Context.BeginFrame(DeltaTime)) { + HandleInputs(); Render(DeltaTime); Context.EndFrame(); } @@ -214,13 +199,12 @@ void UCogWindowManager::Tick(float DeltaTime) void UCogWindowManager::Render(float DeltaTime) { FCogImGuiContextScope ImGuiContextScope(Context); - + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode | ImGuiDockNodeFlags_AutoHideTabBar); ImGui::PopStyleColor(1); - - const bool bCompactSaved = SettingsWindow->GetSettingsConfig()->bCompactMode; + const bool bCompactSaved = Settings->bCompactMode; if (bCompactSaved) { FCogWindowWidgets::PushStyleCompact(); @@ -246,7 +230,7 @@ void UCogWindowManager::Render(float DeltaTime) if (Window->GetIsVisible() && bIsSelectionModeActive == false) { - if (SettingsWindow->GetSettingsConfig()->bTransparentMode) + if (Settings->bTransparentMode) { ImGui::SetNextWindowBgAlpha(0.35f); } @@ -268,8 +252,8 @@ void UCogWindowManager::AddWindow(FCogWindow* Window, const FString& Name, const { Window->SetFullName(Name); Window->SetOwner(this); - Window->Initialize(); Windows.Add(Window); + Window->Initialize(); if (Window->HasWidget()) { @@ -299,18 +283,6 @@ FCogWindow* UCogWindowManager::FindWindowByID(const ImGuiID ID) return nullptr; } -//-------------------------------------------------------------------------------------------------------------------------- -void UCogWindowManager::SetActivateSelectionMode(const bool Value) -{ - SelectionModeActiveCounter = FMath::Max(SelectionModeActiveCounter + (Value ? 1 : -1), 0); - bIsSelectionModeActive = SelectionModeActiveCounter > 0; - - if (bIsSelectionModeActive) - { - Context.SetEnableInput(true); - } -} - //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::ResetLayout() { @@ -414,9 +386,7 @@ void UCogWindowManager::RenderMainMenu() { CloseAllWindows(); } - - - + ImGui::Separator(); RenderMenuItem(*LayoutsWindow, "Layouts"); @@ -570,7 +540,7 @@ void UCogWindowManager::RenderOptionMenu(FMenu& Menu) //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::RenderMenuItem(FCogWindow& Window, const char* MenuItemName) { - if (SettingsWindow->GetSettingsConfig()->bShowWindowsInMainMenu) + if (Settings->bShowWindowsInMainMenu) { ImGui::SetNextWindowSizeConstraints( ImVec2(FCogWindowWidgets::GetFontWidth() * 40, ImGui::GetTextLineHeightWithSpacing() * 5), @@ -604,7 +574,7 @@ void UCogWindowManager::RenderMenuItem(FCogWindow& Window, const char* MenuItemN //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::RenderMenuItemHelp(FCogWindow& Window) { - if (SettingsWindow->GetSettingsConfig()->bShowHelp) + if (Settings->bShowHelp) { ImGui::SameLine(); ImGui::SetCursorPosX(ImGui::GetCursorPosX() - FCogWindowWidgets::GetFontWidth() * 3.0f); @@ -760,31 +730,6 @@ void UCogWindowManager::ResetAllWindowsConfig() } } -//-------------------------------------------------------------------------------------------------------------------------- -bool UCogWindowManager::RegisterDefaultCommandBindings() -{ - if (GetWorld() == nullptr) - { - return false; - } - - UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld()); - if (PlayerInput == nullptr) - { - return false; - } - - AddCommand(PlayerInput, "Cog.ToggleInput", EKeys::F1); - AddCommand(PlayerInput, "Cog.LoadLayout 1", EKeys::F2); - AddCommand(PlayerInput, "Cog.LoadLayout 2", EKeys::F3); - AddCommand(PlayerInput, "Cog.LoadLayout 3", EKeys::F4); - AddCommand(PlayerInput, "Cog.ToggleSelectionMode", EKeys::F5); - - SortCommands(PlayerInput); - PlayerInput->SaveConfig(); - return true; -} - //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::AddCommand(UPlayerInput* PlayerInput, const FString& Command, const FKey& Key) { @@ -890,3 +835,95 @@ void UCogWindowManager::DisableInputMode() UE_LOG(LogCogImGui, Verbose, TEXT("UCogWindowManager::DisableInputMode")); Context.SetEnableInput(false); } + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogWindowManager::HandleInputs() +{ + const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld()); + if (PlayerInput == nullptr) + { return; } + + if (ImGui::GetIO().WantTextInput) + { return; } + + if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->ToggleImguiInputShortcut)) + { + ToggleInputMode(); + } + else if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->ToggleSelectionShortcut)) + { + SetActivateSelectionMode(!GetActivateSelectionMode()); + } + for (int i = 0; i < Settings->LoadLayoutShortcuts.Num(); ++i) + { + if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->LoadLayoutShortcuts[i])) + { + LoadLayout(i); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogWindowManager::SetActivateSelectionMode(const bool Value) +{ + SelectionModeActiveCounter = FMath::Max(SelectionModeActiveCounter + (Value ? 1 : -1), 0); + bIsSelectionModeActive = SelectionModeActiveCounter > 0; + + if (bIsSelectionModeActive) + { + bIsInputEnabledBeforeEnteringSelectionMode = GetContext().GetEnableInput(); + + Context.SetEnableInput(true); + } + else + { + GetContext().SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool UCogWindowManager::GetActivateSelectionMode() const +{ + return SelectionModeActiveCounter > 0; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogWindowManager::DisableConflictingCommands() const +{ + if (GetWorld() == nullptr) + { return; } + + UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld()); + if (PlayerInput == nullptr) + { return; } + + DisableConflictingCommand(PlayerInput, Settings->ToggleImguiInputShortcut); + DisableConflictingCommand(PlayerInput, Settings->ToggleSelectionShortcut); + + for (int32 i = 0; i < Settings->LoadLayoutShortcuts.Num(); ++i) + { + DisableConflictingCommand(PlayerInput, Settings->LoadLayoutShortcuts[i]); + } + + for (int32 i = 0; i < Settings->SaveLayoutShortcuts.Num(); ++i) + { + DisableConflictingCommand(PlayerInput, Settings->SaveLayoutShortcuts[i]); + } + + PlayerInput->SaveConfig(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogWindowManager::DisableConflictingCommand(UPlayerInput* InPlayerInput, const FCogImGuiKeyInfo& InShortcut) +{ + if (InPlayerInput == nullptr) + { return; } + + for (FKeyBind& KeyBind :InPlayerInput->DebugExecBindings) + { + if (FCogImguiInputHelper::IsKeyBindMatchingKeyInfo(KeyBind, InShortcut)) + { + KeyBind.bDisabled = true; + } + } +} diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp index 991df58..e7fdac9 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp @@ -459,8 +459,12 @@ bool FCogWindowWidgets::InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo) ImGui::PushID(Label); ImGui::AlignTextToFramePadding(); - ImGui::TextUnformatted(Label); + ImGui::BeginDisabled(); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10); + ImGui::InputText("##Shortcut", const_cast(Label), IM_ARRAYSIZE(Label)); + ImGui::EndDisabled(); + ImGui::SameLine(); const bool HasChanged = InputKey(KeyInfo); ImGui::PopID(); @@ -471,17 +475,28 @@ bool FCogWindowWidgets::InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo) //-------------------------------------------------------------------------------------------------------------------------- bool FCogWindowWidgets::InputKey(FCogImGuiKeyInfo& KeyInfo) { - static TArray AllKeys; - if (AllKeys.IsEmpty()) - { - EKeys::GetAllKeys(AllKeys); - } - bool HasKeyChanged = false; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 6); if (ImGui::BeginCombo("##Key", TCHAR_TO_ANSI(*KeyInfo.Key.ToString()), ImGuiComboFlags_HeightLarge)) { + { + bool IsSelected = KeyInfo.Key == FKey(); + if (ImGui::Selectable("None", IsSelected)) + { + KeyInfo.Key = FKey(); + HasKeyChanged = true; + } + } + + ImGui::Separator(); + + static TArray AllKeys; + if (AllKeys.IsEmpty()) + { + EKeys::GetAllKeys(AllKeys); + } + for (int32 i = 0; i < AllKeys.Num(); ++i) { const FKey Key = AllKeys[i]; @@ -523,6 +538,27 @@ bool FCogWindowWidgets::KeyBind(FKeyBind& KeyBind) const auto Str = StringCast(*KeyBind.Command); ImStrncpy(Buffer, Str.Get(), IM_ARRAYSIZE(Buffer)); + bool Disable = !KeyBind.bDisabled; + if (ImGui::Checkbox("##Disable", &Disable)) + { + KeyBind.bDisabled = !Disable; + } + if (KeyBind.bDisabled) + { + ImGui::SetItemTooltip("Enable command"); + } + else + { + ImGui::SetItemTooltip("Disable command"); + } + + if (KeyBind.bDisabled) + { + ImGui::BeginDisabled(); + } + + ImGui::SameLine(); + bool HasChanged = false; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); if (ImGui::InputText("##Command", Buffer, IM_ARRAYSIZE(Buffer))) @@ -533,7 +569,7 @@ bool FCogWindowWidgets::KeyBind(FKeyBind& KeyBind) FCogImGuiKeyInfo KeyInfo; FCogImguiInputHelper::KeyBindToKeyInfo(KeyBind, KeyInfo); - + ImGui::SameLine(); if (InputKey(KeyInfo)) { @@ -541,6 +577,11 @@ bool FCogWindowWidgets::KeyBind(FKeyBind& KeyBind) FCogImguiInputHelper::KeyInfoToKeyBind(KeyInfo, KeyBind); } + if (KeyBind.bDisabled) + { + ImGui::EndDisabled(); + } + return HasChanged; } diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindow_Layouts.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindow_Layouts.cpp index e1bbdc6..26bb072 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindow_Layouts.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindow_Layouts.cpp @@ -2,6 +2,7 @@ #include "CogImguiInputHelper.h" #include "CogWindowManager.h" +#include "CogWindow_Settings.h" #include "InputCoreTypes.h" //-------------------------------------------------------------------------------------------------------------------------- @@ -27,13 +28,13 @@ void FCogWindow_Layouts::RenderContent() } ImGui::Separator(); - for (int32 i = 1; i <= 4; ++i) + for (int32 i = 0; i < 4; ++i) { RenderLoadLayoutMenuItem(PlayerInput, i); } ImGui::Separator(); - for (int32 i = 1; i <= 4; ++i) + for (int32 i = 0; i < 4; ++i) { RenderSaveLayoutMenuItem(PlayerInput, i); } @@ -43,21 +44,29 @@ void FCogWindow_Layouts::RenderContent() //-------------------------------------------------------------------------------------------------------------------------- void FCogWindow_Layouts::RenderLoadLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex) { - const FString Command = FString::Printf(TEXT("%s %d"), *UCogWindowManager::LoadLayoutCommand, LayoutIndex); - const FString Shortcut = FCogImguiInputHelper::CommandToString(PlayerInput, Command); - if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Load Layout %d"), LayoutIndex)), TCHAR_TO_ANSI(*Shortcut))) + FString Shortcut; + if (GetOwner()->GetSettings()->LoadLayoutShortcuts.IsValidIndex(LayoutIndex)) { - GetOwner()->LoadLayout(LayoutIndex); + Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->LoadLayoutShortcuts[LayoutIndex]); + } + + if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Load Layout %d"), LayoutIndex + 1)), TCHAR_TO_ANSI(*Shortcut))) + { + GetOwner()->LoadLayout(LayoutIndex + 1); } } //-------------------------------------------------------------------------------------------------------------------------- void FCogWindow_Layouts::RenderSaveLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex) { - const FString Command = FString::Printf(TEXT("%s %d"), *UCogWindowManager::SaveLayoutCommand, LayoutIndex); - const FString Shortcut = FCogImguiInputHelper::CommandToString(PlayerInput, Command); - if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Save Layout %d"), LayoutIndex)), TCHAR_TO_ANSI(*Shortcut))) + FString Shortcut; + if (GetOwner()->GetSettings()->LoadLayoutShortcuts.IsValidIndex(LayoutIndex)) { - GetOwner()->SaveLayout(LayoutIndex); + Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->SaveLayoutShortcuts[LayoutIndex]); + } + + if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Save Layout %d"), LayoutIndex + 1)), TCHAR_TO_ANSI(*Shortcut))) + { + GetOwner()->SaveLayout(LayoutIndex + 1); } } \ No newline at end of file diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp index 10ee950..7a28d47 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp @@ -5,7 +5,7 @@ #include "CogWindowManager.h" #include "CogWindowWidgets.h" #include "imgui.h" -#include "imgui.h" +#include "imgui_internal.h" #include "InputCoreTypes.h" //-------------------------------------------------------------------------------------------------------------------------- @@ -78,7 +78,7 @@ void FCogWindow_Settings::RenderContent() Context.SetEnableInput(bEnableInput); } ImGui::SetItemTooltip("Enable ImGui inputs. When enabled the ImGui menu is shown and inputs are forwarded to ImGui."); - FCogWindowWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::CommandToString(PlayerInput, UCogWindowManager::ToggleInputCommand)); + FCogWindowWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::KeyInfoToString(Config->ToggleImguiInputShortcut)); //------------------------------------------------------------------------------------------- bool bShareKeyboard = Context.GetShareKeyboard(); @@ -121,12 +121,16 @@ void FCogWindow_Settings::RenderContent() //------------------------------------------------------------------------------------------- ImGui::CheckboxFlags("Keyboard Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); ImGui::SetItemTooltip("Use the keyboard to navigate in ImGui windows with the following keys : Tab, Directional Arrows, Space, Enter."); + + //------------------------------------------------------------------------------------------- + //ImGui::CheckboxFlags("Gamepad Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + //ImGui::SetItemTooltip("Use the gamepad to navigate in ImGui windows."); + + //------------------------------------------------------------------------------------------- + ImGui::Checkbox("Disable Conflicting Commands", &Config->bResolveShortcutsConflicts); + ImGui::SetItemTooltip("Disable the existing Unreal command shortcuts mapped to same shortcuts Cog is using. Typically, if the F1 shortcut is used to toggle Inputs, the Unreal wireframe command will get disabled."); } - - //------------------------------------------------------------------------------------------- - //ImGui::CheckboxFlags("Gamepad Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); - //ImGui::SetItemTooltip("Use the gamepad to navigate in ImGui windows."); - + //------------------------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Window", ImGuiTreeNodeFlags_DefaultOpen)) { @@ -163,6 +167,30 @@ void FCogWindow_Settings::RenderContent() } } + //------------------------------------------------------------------------------------------- + if (ImGui::CollapsingHeader("Shortcuts", ImGuiTreeNodeFlags_DefaultOpen)) + { + RenderShortcut("Toggle ImGui Input", Config->ToggleImguiInputShortcut); + RenderShortcut("Toggle Selection", Config->ToggleSelectionShortcut); + + ImGui::Separator(); + + char Buffer[32]; + + for (int32 i = 0; i < Config->LoadLayoutShortcuts.Num(); ++i) + { + ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Load Layout %d", i + 1); + RenderShortcut(Buffer, Config->LoadLayoutShortcuts[i]); + } + + ImGui::Separator(); + for (int32 i = 0; i < Config->SaveLayoutShortcuts.Num(); ++i) + { + ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Save Layout %d", i + 1); + RenderShortcut(Buffer, Config->SaveLayoutShortcuts[i]); + } + } + //------------------------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Config")) { @@ -198,3 +226,15 @@ void FCogWindow_Settings::SetDPIScale(float Value) const Config->DPIScale = Value; GetOwner()->GetContext().SetDPIScale(Config->DPIScale); } + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindow_Settings::RenderShortcut(const char* Label, FCogImGuiKeyInfo& KeyInfo) +{ + if (FCogWindowWidgets::InputKey(Label, KeyInfo)) + { + if (Config->bResolveShortcutsConflicts) + { + GetOwner()->DisableConflictingCommands(); + } + } +} diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h b/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h index a0695e1..fdb2325 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "CogImguiContext.h" +#include "CogWindow_Settings.h" #include "imgui.h" #include "CogWindowManager.generated.h" @@ -26,8 +27,6 @@ public: UCogWindowManager(); - virtual void PostInitProperties() override; - virtual void Shutdown(); virtual void SortMainMenu(); @@ -56,11 +55,11 @@ public: virtual void SetActivateSelectionMode(bool Value); + virtual bool GetActivateSelectionMode() const; + virtual void ResetAllWindowsConfig(); - virtual bool RegisterDefaultCommandBindings(); - - const FCogWindow_Settings* GetSettingsWindow() const { return SettingsWindow; } + const UCogWindowConfig_Settings* GetSettings() const { return Settings.Get(); } UCogCommonConfig* GetConfig(const TSubclassOf ConfigClass); @@ -80,6 +79,8 @@ public: static void SortCommands(UPlayerInput* PlayerInput); + void DisableConflictingCommands() const; + protected: friend class FCogWindow_Layouts; @@ -107,6 +108,8 @@ protected: virtual void ToggleInputMode(); virtual void DisableInputMode(); + + virtual void HandleInputs(); static void SettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*); @@ -118,6 +121,8 @@ protected: static void SettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); + static void DisableConflictingCommand(UPlayerInput* InPlayerInput, const FCogImGuiKeyInfo& InShortcut); + static FString ToggleInputCommand; static FString DisableInputCommand; @@ -135,8 +140,8 @@ protected: mutable TArray Assets; UPROPERTY(Config) - bool bRegisterDefaultCommands = true; - + bool bShowMainMenu = false; + FCogImguiContext Context; TArray Windows; @@ -148,6 +153,8 @@ protected: TArray SpaceWindows; FCogWindow_Settings* SettingsWindow = nullptr; + + TWeakObjectPtr Settings; FCogWindow_Layouts* LayoutsWindow = nullptr; @@ -156,6 +163,8 @@ protected: int32 LayoutToLoad = -1; int32 SelectionModeActiveCounter = 0; + + bool bIsInputEnabledBeforeEnteringSelectionMode = false; bool bIsSelectionModeActive = false; @@ -176,7 +185,7 @@ template T* UCogWindowManager::GetConfig() { static_assert(TPointerIsConvertibleFromTo::Value); - return Cast(&GetConfig(T::StaticClass())); + return Cast(GetConfig(T::StaticClass())); } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindow_Settings.h b/Plugins/Cog/Source/CogWindow/Public/CogWindow_Settings.h index 8775614..d20d54f 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindow_Settings.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindow_Settings.h @@ -2,7 +2,9 @@ #include "CoreMinimal.h" #include "CogCommonConfig.h" +#include "CogImguiKeyInfo.h" #include "CogWindow.h" +#include "GameFramework/PlayerInput.h" #include "CogWindow_Settings.generated.h" class UCogEngineConfig_Settings; @@ -30,6 +32,8 @@ protected: virtual void ResetConfig() override; + virtual void RenderShortcut(const char* Label, FCogImGuiKeyInfo& KeyInfo); + TObjectPtr Config = nullptr; }; @@ -75,6 +79,21 @@ public: UPROPERTY(Config) bool bNavEnableKeyboard = false; + UPROPERTY(Config) + bool bResolveShortcutsConflicts = true; + + UPROPERTY(Config) + FCogImGuiKeyInfo ToggleImguiInputShortcut = FCogImGuiKeyInfo(EKeys::F1); + + UPROPERTY(Config) + FCogImGuiKeyInfo ToggleSelectionShortcut = FCogImGuiKeyInfo(EKeys::F5); + + UPROPERTY(Config) + TArray LoadLayoutShortcuts = { FCogImGuiKeyInfo(EKeys::F2), FCogImGuiKeyInfo(EKeys::F3), FCogImGuiKeyInfo(EKeys::F4), FCogImGuiKeyInfo()}; + + UPROPERTY(Config) + TArray SaveLayoutShortcuts = { FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo()}; + //UPROPERTY(Config) //bool bNavEnableGamepad = false; @@ -97,5 +116,10 @@ public: bNavEnableKeyboard = false; //bNavEnableGamepad = false; //bNavNoCaptureInput = true; + + ToggleImguiInputShortcut = FCogImGuiKeyInfo(EKeys::F1); + ToggleSelectionShortcut = FCogImGuiKeyInfo(EKeys::F5); + LoadLayoutShortcuts = { FCogImGuiKeyInfo(EKeys::F2), FCogImGuiKeyInfo(EKeys::F3), FCogImGuiKeyInfo(EKeys::F4), FCogImGuiKeyInfo()}; + SaveLayoutShortcuts = { FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo()}; } }; \ No newline at end of file