mirror of
https://github.com/kevinporetti/UnrealImGui.git
synced 2025-01-18 00:10:32 +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);
|
||||
}
|
@ -158,7 +158,7 @@ protected:
|
||||
* 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.
|
||||
* @returns True, if this key event can open console.
|
||||
*/
|
||||
bool IsConsoleEvent(const FKeyEvent& KeyEvent) const;
|
||||
|
||||
@ -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