diff --git a/Source/ImGui/ImGui.Build.cs b/Source/ImGui/ImGui.Build.cs index 8651ff9..b9bba6c 100644 --- a/Source/ImGui/ImGui.Build.cs +++ b/Source/ImGui/ImGui.Build.cs @@ -65,6 +65,7 @@ public class ImGui : ModuleRules new string[] { "Settings", + "UnrealEd", } ); } diff --git a/Source/ImGui/Private/ImGuiInputHandler.cpp b/Source/ImGui/Private/ImGuiInputHandler.cpp index 8288820..d1e78bb 100644 --- a/Source/ImGui/Private/ImGuiInputHandler.cpp +++ b/Source/ImGui/Private/ImGuiInputHandler.cpp @@ -10,24 +10,64 @@ #include #include +#if WITH_EDITOR +#include +#include +#include + +// Version 4.18 added support for dual key bindings. +#include +#define WITH_SINGLE_KEY_BINDING (ENGINE_MAJOR_VERSION < 4 || (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 18)) +#endif // WITH_EDITOR + + +DEFINE_LOG_CATEGORY_STATIC(LogImGuiInputHandler, Warning, All); FImGuiInputResponse UImGuiInputHandler::OnKeyDown(const FKeyEvent& KeyEvent) { - // Ignore console open events, so we don't block it from opening. - if (KeyEvent.GetKey() == EKeys::Tilde) + // Ignore console events, so we don't block it from opening. + if (IsConsoleEvent(KeyEvent)) { return FImGuiInputResponse{ false, false }; } - // Ignore escape event, if they are not meant for ImGui control. - if (KeyEvent.GetKey() == EKeys::Escape && !HasImGuiActiveItem()) +#if WITH_EDITOR + // If there is no active ImGui control that would get precedence and this key event is bound to a stop play session + // command, then ignore that event and let the command execute. + if (!HasImGuiActiveItem() && IsStopPlaySessionEvent(KeyEvent)) { return FImGuiInputResponse{ false, false }; } +#endif // WITH_EDITOR return DefaultResponse(); } +bool UImGuiInputHandler::IsConsoleEvent(const FKeyEvent& KeyEvent) const +{ + // Checking modifiers is based on console implementation. + const bool bModifierDown = KeyEvent.IsControlDown() || KeyEvent.IsShiftDown() || KeyEvent.IsAltDown() || KeyEvent.IsCommandDown(); + return !bModifierDown && GetDefault()->ConsoleKeys.Contains(KeyEvent.GetKey()); +} + +#if WITH_EDITOR +bool UImGuiInputHandler::IsStopPlaySessionEvent(const FKeyEvent& KeyEvent) const +{ + if (StopPlaySessionCommandInfo.IsValid()) + { + const FInputChord InputChord(KeyEvent.GetKey(), KeyEvent.IsShiftDown(), KeyEvent.IsControlDown(), KeyEvent.IsAltDown(), KeyEvent.IsCommandDown()); +#if WITH_SINGLE_KEY_BINDING + const bool bHasActiveChord = (InputChord == StopPlaySessionCommandInfo->GetActiveChord().Get()); +#else + const bool bHasActiveChord = StopPlaySessionCommandInfo->HasActiveChord(InputChord); +#endif + return bHasActiveChord && FPlayWorldCommands::GlobalPlayWorldActions->CanExecuteAction(StopPlaySessionCommandInfo.ToSharedRef()); + } + + return false; +} +#endif // WITH_EDITOR + bool UImGuiInputHandler::HasImGuiActiveItem() const { FImGuiContextProxy* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex); @@ -39,4 +79,13 @@ void UImGuiInputHandler::Initialize(FImGuiModuleManager* InModuleManager, UGameV ModuleManager = InModuleManager; GameViewport = InGameViewport; ContextIndex = InContextIndex; + +#if WITH_EDITOR + StopPlaySessionCommandInfo = FInputBindingManager::Get().FindCommandInContext("PlayWorld", "StopPlaySession"); + if (!StopPlaySessionCommandInfo.IsValid()) + { + UE_LOG(LogImGuiInputHandler, Warning, TEXT("Couldn't find 'StopPlaySession' in context 'PlayWorld'. ") + TEXT("PIE feature allowing execution of stop command in ImGui input mode will be disabled.")); + } +#endif // WITH_EDITOR } diff --git a/Source/ImGui/Public/ImGuiInputHandler.h b/Source/ImGui/Public/ImGuiInputHandler.h index 10612a4..34f5c10 100644 --- a/Source/ImGui/Public/ImGuiInputHandler.h +++ b/Source/ImGui/Public/ImGuiInputHandler.h @@ -15,6 +15,11 @@ struct FAnalogInputEvent; struct FCharacterEvent; struct FKeyEvent; +#if WITH_EDITOR +class FUICommandInfo; +#endif // WITH_EDITOR + + /** Response used by ImGui Input Handler to communicate input handling requests. */ struct IMGUI_API FImGuiInputResponse { @@ -149,7 +154,29 @@ public: protected: - /** Checks whether corresponding ImGui context has an active item. */ + /** + * Checks whether this is a key event that can open console. + * + * @param KeyEvent - Key event to test. + * @returns True, if this key event can open console. + */ + bool IsConsoleEvent(const FKeyEvent& KeyEvent) const; + +#if WITH_EDITOR + /** + * Checks whether this is a key event that can stop PIE session. + * + * @param KeyEvent - Key event to test. + * @returns True, if this key event can stop PIE session. + */ + bool IsStopPlaySessionEvent(const FKeyEvent& KeyEvent) const; +#endif + + /** + * Checks whether corresponding ImGui context has an active item (holding cursor focus). + * + * @returns True, if corresponding context has an active item. + */ bool HasImGuiActiveItem() const; private: @@ -164,5 +191,9 @@ private: int32 ContextIndex = -1; +#if WITH_EDITOR + TSharedPtr StopPlaySessionCommandInfo; +#endif + friend class FImGuiInputHandlerFactory; };