mirror of
				https://github.com/kevinporetti/UnrealImGui.git
				synced 2025-11-04 07:33:18 +00:00 
			
		
		
		
	Added 'ImGui.SwitchInputMode' command and configurable key binding to DebugExecBindings.
This commit is contained in:
		
							parent
							
								
									eabff7b839
								
							
						
					
					
						commit
						a90f217ab3
					
				@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include "ImGuiContextProxy.h"
 | 
			
		||||
#include "ImGuiModuleManager.h"
 | 
			
		||||
#include "ImGuiSettings.h"
 | 
			
		||||
 | 
			
		||||
#include <Engine/Console.h>
 | 
			
		||||
#include <Input/Events.h>
 | 
			
		||||
@ -25,6 +26,13 @@ DEFINE_LOG_CATEGORY_STATIC(LogImGuiInputHandler, Warning, All);
 | 
			
		||||
 | 
			
		||||
FImGuiInputResponse UImGuiInputHandler::OnKeyDown(const FKeyEvent& KeyEvent)
 | 
			
		||||
{
 | 
			
		||||
	// If this is an input mode switch event then handle it here and consume.
 | 
			
		||||
	if (IsSwitchInputModeEvent(KeyEvent))
 | 
			
		||||
	{
 | 
			
		||||
		FImGuiModule::Get().ToggleInputMode();
 | 
			
		||||
		return FImGuiInputResponse().RequestConsume();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ignore console events, so we don't block it from opening.
 | 
			
		||||
	if (IsConsoleEvent(KeyEvent))
 | 
			
		||||
	{
 | 
			
		||||
@ -68,6 +76,28 @@ bool UImGuiInputHandler::IsStopPlaySessionEvent(const FKeyEvent& KeyEvent) const
 | 
			
		||||
}
 | 
			
		||||
#endif // WITH_EDITOR
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
	bool IsMatching(ECheckBoxState CheckBoxState, bool bValue)
 | 
			
		||||
	{
 | 
			
		||||
		return (CheckBoxState == ECheckBoxState::Undetermined) || ((CheckBoxState == ECheckBoxState::Checked) == bValue);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool AreModifiersMatching(const FImGuiKeyInfo& KeyInfo, const FKeyEvent& KeyEvent)
 | 
			
		||||
	{
 | 
			
		||||
		return IsMatching(KeyInfo.Shift, KeyEvent.IsShiftDown())
 | 
			
		||||
			&& IsMatching(KeyInfo.Ctrl, KeyEvent.IsControlDown())
 | 
			
		||||
			&& IsMatching(KeyInfo.Alt, KeyEvent.IsAltDown())
 | 
			
		||||
			&& IsMatching(KeyInfo.Cmd, KeyEvent.IsCommandDown());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UImGuiInputHandler::IsSwitchInputModeEvent(const FKeyEvent& KeyEvent) const
 | 
			
		||||
{
 | 
			
		||||
	const FImGuiKeyInfo KeyInfo = GetDefault<UImGuiSettings>()->GetSwitchInputModeKey();
 | 
			
		||||
	return (KeyEvent.GetKey() == KeyInfo.Key) && AreModifiersMatching(KeyInfo, KeyEvent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UImGuiInputHandler::HasImGuiActiveItem() const
 | 
			
		||||
{
 | 
			
		||||
	FImGuiContextProxy* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex);
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,21 @@ namespace CVars
 | 
			
		||||
	extern TAutoConsoleVariable<int32> ShowDemo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Commands
 | 
			
		||||
{
 | 
			
		||||
	const TCHAR* SwitchInputMode = TEXT("ImGui.SwitchInputMode");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SwitchImGuiInputMode()
 | 
			
		||||
{
 | 
			
		||||
	FImGuiModule::Get().ToggleInputMode();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FAutoConsoleCommand SwitchInputModeCommand = FAutoConsoleCommand(
 | 
			
		||||
	Commands::SwitchInputMode,
 | 
			
		||||
	TEXT("Changes ImGui input mode."),
 | 
			
		||||
	FConsoleCommandDelegate::CreateStatic(SwitchImGuiInputMode));
 | 
			
		||||
 | 
			
		||||
struct EDelegateCategory
 | 
			
		||||
{
 | 
			
		||||
	enum
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
#include "ImGuiPrivatePCH.h"
 | 
			
		||||
 | 
			
		||||
#include "ImGuiSettings.h"
 | 
			
		||||
#include "Utilities/DebugExecBindings.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UImGuiSettings::UImGuiSettings()
 | 
			
		||||
@ -19,6 +20,21 @@ UImGuiSettings::~UImGuiSettings()
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Commands
 | 
			
		||||
{
 | 
			
		||||
	extern const TCHAR* SwitchInputMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UImGuiSettings::PostInitProperties()
 | 
			
		||||
{
 | 
			
		||||
	Super::PostInitProperties();
 | 
			
		||||
 | 
			
		||||
	// Instead of saving binding to input config, we manually update DebugExecBindings from here. This has an advantage
 | 
			
		||||
	// that there is no ambiguity where settings are stored and more importantly, it works out of the box in packed
 | 
			
		||||
	// and staged builds.  
 | 
			
		||||
	DebugExecBindings::UpdatePlayerInputs(SwitchInputModeKey, Commands::SwitchInputMode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if WITH_EDITOR
 | 
			
		||||
 | 
			
		||||
void UImGuiSettings::RegisterPropertyChangedDelegate()
 | 
			
		||||
@ -38,13 +54,16 @@ void UImGuiSettings::OnPropertyChanged(class UObject* ObjectBeingModified, struc
 | 
			
		||||
{
 | 
			
		||||
	if (ObjectBeingModified == this)
 | 
			
		||||
	{
 | 
			
		||||
		static const FName ImGuiInputHandlerPropertyName = GET_MEMBER_NAME_CHECKED(UImGuiSettings, ImGuiInputHandlerClass);
 | 
			
		||||
 | 
			
		||||
		const FName UpdatedPropertyName = PropertyChangedEvent.MemberProperty ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;
 | 
			
		||||
		if (UpdatedPropertyName == ImGuiInputHandlerPropertyName)
 | 
			
		||||
 | 
			
		||||
		if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, ImGuiInputHandlerClass))
 | 
			
		||||
		{
 | 
			
		||||
			OnImGuiInputHandlerClassChanged.Broadcast();
 | 
			
		||||
		}
 | 
			
		||||
		else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, SwitchInputModeKey))
 | 
			
		||||
		{
 | 
			
		||||
			DebugExecBindings::UpdatePlayerInputs(SwitchInputModeKey, Commands::SwitchInputMode);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,31 @@
 | 
			
		||||
#include "ImGuiSettings.generated.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Struct containing key information that can be used for key binding. Using 'Undetermined' value for modifier keys
 | 
			
		||||
 * means that those keys should be ignored when testing for a match.
 | 
			
		||||
 */
 | 
			
		||||
USTRUCT()
 | 
			
		||||
struct FImGuiKeyInfo
 | 
			
		||||
{
 | 
			
		||||
	GENERATED_BODY()
 | 
			
		||||
 | 
			
		||||
	UPROPERTY(EditAnywhere)
 | 
			
		||||
	FKey Key;
 | 
			
		||||
 | 
			
		||||
	UPROPERTY(EditAnywhere)
 | 
			
		||||
	ECheckBoxState Shift = ECheckBoxState::Undetermined;
 | 
			
		||||
 | 
			
		||||
	UPROPERTY(EditAnywhere)
 | 
			
		||||
	ECheckBoxState Ctrl = ECheckBoxState::Undetermined;
 | 
			
		||||
 | 
			
		||||
	UPROPERTY(EditAnywhere)
 | 
			
		||||
	ECheckBoxState Alt = ECheckBoxState::Undetermined;
 | 
			
		||||
 | 
			
		||||
	UPROPERTY(EditAnywhere)
 | 
			
		||||
	ECheckBoxState Cmd = ECheckBoxState::Undetermined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Settings for ImGui module.
 | 
			
		||||
UCLASS(config=ImGui, defaultconfig)
 | 
			
		||||
class UImGuiSettings : public UObject
 | 
			
		||||
@ -33,9 +58,14 @@ public:
 | 
			
		||||
	// Path to custom implementation of ImGui Input Handler.
 | 
			
		||||
	const FStringClassReference& GetImGuiInputHandlerClass() const { return ImGuiInputHandlerClass; }
 | 
			
		||||
 | 
			
		||||
	// Get mapping for 'ImGui.SwitchInputMode' command.
 | 
			
		||||
	const FImGuiKeyInfo& GetSwitchInputModeKey() const { return SwitchInputModeKey; }
 | 
			
		||||
 | 
			
		||||
	// Delegate raised when ImGuiInputHandlerClass property has changed.
 | 
			
		||||
	FSimpleMulticastDelegate OnImGuiInputHandlerClassChanged;
 | 
			
		||||
 | 
			
		||||
	virtual void PostInitProperties() override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
	// Path to own implementation of ImGui Input Handler allowing to customize handling of keyboard and gamepad input.
 | 
			
		||||
@ -43,8 +73,16 @@ protected:
 | 
			
		||||
	UPROPERTY(EditAnywhere, config, Category = "Input", meta = (MetaClass = "ImGuiInputHandler"))
 | 
			
		||||
	FStringClassReference ImGuiInputHandlerClass;
 | 
			
		||||
 | 
			
		||||
	// Define a custom key binding to 'ImGui.SwitchInputMode' command. Mapping will be only set if Key property in this
 | 
			
		||||
	// structure is set to a valid key. Modifier keys can be either completely ignored (Undetermined), required to be
 | 
			
		||||
	// pressed (Checked) or required to be not pressed (Unchecked).
 | 
			
		||||
	UPROPERTY(EditAnywhere, config, Category = "Input")
 | 
			
		||||
	FImGuiKeyInfo SwitchInputModeKey;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	void UpdateSwitchInputModeBinding();
 | 
			
		||||
 | 
			
		||||
#if WITH_EDITOR
 | 
			
		||||
 | 
			
		||||
	void RegisterPropertyChangedDelegate();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										95
									
								
								Source/ImGui/Private/Utilities/DebugExecBindings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Source/ImGui/Private/Utilities/DebugExecBindings.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
			
		||||
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
 | 
			
		||||
 | 
			
		||||
#include "ImGuiPrivatePCH.h"
 | 
			
		||||
 | 
			
		||||
#include "DebugExecBindings.h"
 | 
			
		||||
#include "ImGuiSettings.h"
 | 
			
		||||
 | 
			
		||||
#include <GameFramework/PlayerInput.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
	FKeyBind CreateKeyBind(const FImGuiKeyInfo& KeyInfo, const FString& Command)
 | 
			
		||||
	{
 | 
			
		||||
		FKeyBind KeyBind;
 | 
			
		||||
		KeyBind.Command = Command;
 | 
			
		||||
		KeyBind.Key = KeyInfo.Key;
 | 
			
		||||
		KeyBind.bDisabled = false;
 | 
			
		||||
 | 
			
		||||
#define FILL_MODIFIER_DATA(KeyInfoProperty, BindProperty, BindIgnoreProperty)\
 | 
			
		||||
			if (KeyInfo.KeyInfoProperty == ECheckBoxState::Undetermined)\
 | 
			
		||||
			{\
 | 
			
		||||
				KeyBind.BindProperty = KeyBind.BindIgnoreProperty = false;\
 | 
			
		||||
			}\
 | 
			
		||||
			else\
 | 
			
		||||
			{\
 | 
			
		||||
				KeyBind.BindProperty = (KeyInfo.KeyInfoProperty == ECheckBoxState::Checked);\
 | 
			
		||||
				KeyBind.BindIgnoreProperty = !KeyBind.BindProperty;\
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		FILL_MODIFIER_DATA(Shift, Shift, bIgnoreShift);
 | 
			
		||||
		FILL_MODIFIER_DATA(Ctrl, Control, bIgnoreCtrl);
 | 
			
		||||
		FILL_MODIFIER_DATA(Alt, Alt, bIgnoreAlt);
 | 
			
		||||
		FILL_MODIFIER_DATA(Cmd, Cmd, bIgnoreCmd);
 | 
			
		||||
 | 
			
		||||
#undef FILL_MODIFIER_DATA
 | 
			
		||||
 | 
			
		||||
		return KeyBind;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool IsBindable(const FKey& Key)
 | 
			
		||||
	{
 | 
			
		||||
		return Key.IsValid() && Key != EKeys::AnyKey && !Key.IsFloatAxis() && !Key.IsVectorAxis()
 | 
			
		||||
			&& !Key.IsGamepadKey() && !Key.IsModifierKey() && !Key.IsMouseButton();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void UpdatePlayerInput(UPlayerInput* PlayerInput, const FKeyBind& KeyBind)
 | 
			
		||||
	{
 | 
			
		||||
		const int32 Index = PlayerInput->DebugExecBindings.IndexOfByPredicate([&](const FKeyBind& PlayerKeyBind)
 | 
			
		||||
		{
 | 
			
		||||
			return PlayerKeyBind.Command.Equals(KeyBind.Command, ESearchCase::IgnoreCase);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		if (IsBindable(KeyBind.Key))
 | 
			
		||||
		{
 | 
			
		||||
			if (Index != INDEX_NONE)
 | 
			
		||||
			{
 | 
			
		||||
				PlayerInput->DebugExecBindings[Index] = KeyBind;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				PlayerInput->DebugExecBindings.Add(KeyBind);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if (Index != INDEX_NONE)
 | 
			
		||||
			{
 | 
			
		||||
				PlayerInput->DebugExecBindings.RemoveAt(Index);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace DebugExecBindings
 | 
			
		||||
{
 | 
			
		||||
	void UpdatePlayerInputs(const FImGuiKeyInfo& KeyInfo, const FString& Command)
 | 
			
		||||
	{
 | 
			
		||||
		checkf(!Command.IsEmpty(), TEXT("Empty command."));
 | 
			
		||||
 | 
			
		||||
		const FKeyBind KeyBind = CreateKeyBind(KeyInfo, Command);
 | 
			
		||||
 | 
			
		||||
		// Update default player input, so changes will be visible in all PIE sessions created after this point.
 | 
			
		||||
		if (UPlayerInput* DefaultPlayerInput = GetMutableDefault<UPlayerInput>())
 | 
			
		||||
		{
 | 
			
		||||
			UpdatePlayerInput(DefaultPlayerInput, KeyBind);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Update all existing player inputs to see changes in running PIE session.
 | 
			
		||||
		for (TObjectIterator<UPlayerInput> It; It; ++It)
 | 
			
		||||
		{
 | 
			
		||||
			UpdatePlayerInput(*It, KeyBind);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								Source/ImGui/Private/Utilities/DebugExecBindings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Source/ImGui/Private/Utilities/DebugExecBindings.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
struct FImGuiKeyInfo;
 | 
			
		||||
 | 
			
		||||
namespace DebugExecBindings
 | 
			
		||||
{
 | 
			
		||||
	void UpdatePlayerInputs(const FImGuiKeyInfo& KeyInfo, const FString& Command);
 | 
			
		||||
}
 | 
			
		||||
@ -172,6 +172,14 @@ protected:
 | 
			
		||||
	bool IsStopPlaySessionEvent(const FKeyEvent& KeyEvent) const;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks whether this key event can switch ImGui input mode (as defined in settings).
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param KeyEvent - Key event to test.
 | 
			
		||||
	 * @returns True, if this key is bound to 'ImGui.SwitchInputMode' command that switches ImGui input mode.
 | 
			
		||||
	 */
 | 
			
		||||
	bool IsSwitchInputModeEvent(const FKeyEvent& KeyEvent) const;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks whether corresponding ImGui context has an active item (holding cursor focus).
 | 
			
		||||
	 *
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user