Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New ImGui IO event API #23

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 8 additions & 2 deletions Source/ImGui/Private/ImGuiContextProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ FImGuiContextProxy::FImGuiContextProxy(const FString& InName, int32 InContextInd

// Start initialization.
ImGuiIO& IO = ImGui::GetIO();
InputState.IO = IO;

// Set session data storage.
IO.IniFilename = IniFilename.c_str();
Expand All @@ -104,7 +105,7 @@ FImGuiContextProxy::FImGuiContextProxy(const FString& InName, int32 InContextInd
SetDPIScale(InDPIScale);

// Initialize key mapping, so context can correctly interpret input state.
ImGuiInterops::SetUnrealKeyMap(IO);
ImGuiInterops::SetUnrealKeyMap();

// Begin frame to complete context initialization (this is to avoid problems with other systems calling to ImGui
// during startup).
Expand Down Expand Up @@ -207,6 +208,12 @@ void FImGuiContextProxy::Tick(float DeltaSeconds)

// Update remaining context information.
bWantsMouseCapture = ImGui::GetIO().WantCaptureMouse;

GEngine->AddOnScreenDebugMessage(1111, .25f, FColor::Purple, FString::Printf(TEXT("[GUI Context] HasActive Item: %s"),
bHasActiveItem ? TEXT("True") : TEXT("False")));

GEngine->AddOnScreenDebugMessage(1112, .25f, FColor::Purple, FString::Printf(TEXT("[GUI Context] WantsMouseCapture: %s"),
bWantsMouseCapture ? TEXT("True") : TEXT("False")));
}
}

Expand All @@ -217,7 +224,6 @@ void FImGuiContextProxy::BeginFrame(float DeltaTime)
ImGuiIO& IO = ImGui::GetIO();
IO.DeltaTime = DeltaTime;

ImGuiInterops::CopyInput(IO, InputState);
InputState.ClearUpdateState();

IO.DisplaySize = { (float)DisplaySize.X, (float)DisplaySize.Y };
Expand Down
69 changes: 24 additions & 45 deletions Source/ImGui/Private/ImGuiInputHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "ImGuiModuleSettings.h"
#include "VersionCompatibility.h"

#include <Engine/Console.h>
#include <Framework/Application/SlateApplication.h>
#include <GameFramework/InputSettings.h>
#include <InputCoreTypes.h>
Expand Down Expand Up @@ -45,68 +44,56 @@ FReply UImGuiInputHandler::OnKeyDown(const FKeyEvent& KeyEvent)
bool bConsume = false;
if (InputState->IsGamepadNavigationEnabled())
{
InputState->SetGamepadNavigationKey(KeyEvent, true);
InputState->SetKeyDown(KeyEvent, true);
bConsume = !ModuleManager->GetProperties().IsGamepadInputShared();
}

return ToReply(bConsume);
}
else

// Ignore console events, so we don't block it from opening.
if (IsConsoleEvent(KeyEvent))
{
// Ignore console events, so we don't block it from opening.
if (IsConsoleEvent(KeyEvent))
{
return ToReply(false);
}
return ToReply(false);
}

#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 ToReply(false);
}
// 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 ToReply(false);
}
#endif // WITH_EDITOR

const bool bConsume = !ModuleManager->GetProperties().IsKeyboardInputShared();

// With shared input we can leave command bindings for DebugExec to handle, otherwise we need to do it here.
if (bConsume && IsToggleInputEvent(KeyEvent))
{
ModuleManager->GetProperties().ToggleInput();
}

InputState->SetKeyDown(KeyEvent, true);
CopyModifierKeys(KeyEvent);

InputState->KeyDownEvents.Add(KeyEvent.GetKeyCode(), KeyEvent);
const bool bConsume = !ModuleManager->GetProperties().IsKeyboardInputShared();

return ToReply(bConsume);
// With shared input we can leave command bindings for DebugExec to handle, otherwise we need to do it here.
if (bConsume && IsToggleInputEvent(KeyEvent))
{
ModuleManager->GetProperties().ToggleInput();
}

InputState->SetKeyDown(KeyEvent, true);
return ToReply(bConsume);
}

FReply UImGuiInputHandler::OnKeyUp(const FKeyEvent& KeyEvent)
{
InputState->KeyUpEvents.Add(KeyEvent.GetKeyCode(), KeyEvent);

if (KeyEvent.GetKey().IsGamepadKey())
{
bool bConsume = false;
if (InputState->IsGamepadNavigationEnabled())
{
InputState->SetGamepadNavigationKey(KeyEvent, false);
InputState->SetKeyDown(KeyEvent, false);
bConsume = !ModuleManager->GetProperties().IsGamepadInputShared();
}

return ToReply(bConsume);
}
else
{
InputState->SetKeyDown(KeyEvent, false);
CopyModifierKeys(KeyEvent);

return ToReply(!ModuleManager->GetProperties().IsKeyboardInputShared());
}
InputState->SetKeyDown(KeyEvent, false);
return ToReply(!ModuleManager->GetProperties().IsKeyboardInputShared());
}

FReply UImGuiInputHandler::OnAnalogValueChanged(const FAnalogInputEvent& AnalogInputEvent)
Expand Down Expand Up @@ -224,7 +211,6 @@ void UImGuiInputHandler::OnGamepadInputDisabled()
if (bGamepadInputEnabled)
{
bGamepadInputEnabled = false;
InputState->ResetGamepadNavigation();
}
}

Expand All @@ -247,14 +233,7 @@ void UImGuiInputHandler::OnMouseInputDisabled()
}
}

void UImGuiInputHandler::CopyModifierKeys(const FInputEvent& InputEvent)
{
InputState->SetControlDown(InputEvent.IsControlDown());
InputState->SetShiftDown(InputEvent.IsShiftDown());
InputState->SetAltDown(InputEvent.IsAltDown());
}

bool UImGuiInputHandler::IsConsoleEvent(const FKeyEvent& KeyEvent) const
bool UImGuiInputHandler::IsConsoleEvent(const FKeyEvent& KeyEvent)
{
// Checking modifiers is based on console implementation.
const bool bModifierDown = KeyEvent.IsControlDown() || KeyEvent.IsShiftDown() || KeyEvent.IsAltDown() || KeyEvent.IsCommandDown();
Expand Down
117 changes: 73 additions & 44 deletions Source/ImGui/Private/ImGuiInputState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,87 +14,116 @@ FImGuiInputState::FImGuiInputState()

void FImGuiInputState::AddCharacter(TCHAR Char)
{
InputCharacters.Add(Char);
IO.AddInputCharacter(ImGuiInterops::CastInputChar(Char));
}

void FImGuiInputState::SetKeyDown(uint32 KeyIndex, bool bIsDown)
void FImGuiInputState::SetKeyDown(const FKeyEvent& KeyEvent, bool bIsDown)
{
if (KeyIndex < Utilities::GetArraySize(KeysDown))
{
if (KeysDown[KeyIndex] != bIsDown)
{
KeysDown[KeyIndex] = bIsDown;
KeysUpdateRange.AddPosition(KeyIndex);
}
}
const FKey& Key = KeyEvent.GetKey();
SetKeyDown(Key, bIsDown);
}

void FImGuiInputState::SetMouseDown(uint32 MouseIndex, bool bIsDown)
void FImGuiInputState::SetKeyDown(const FKey& Key, bool bIsDown)
{
if (MouseIndex < Utilities::GetArraySize(MouseButtonsDown))
const ImGuiKey& ImKey = ImGuiInterops::UnrealToImGuiKey(Key);
IO.AddKeyEvent(ImKey, bIsDown);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UnrealToImGuiKey has ImGuiKey_LeftShift, ImGuiKey_RightShift, ImGuiKey_LeftControl, ImGuiKey_RightControl, ImGuiKey_LeftAlt, ImGuiKey_RightAlt, ImGuiKey_LeftSuper and ImGuiKey_RightSuper But we also need to pass events for ImGuiKey_ModShift, ImGuiKey_ModControl, ImGuiKey_ModAlt and ImGuiKey_ModSuper.

Maybe you can have a UnrealToImGuiModKeyMap map UnrealToImGuiKeyMap just like as:

{
    EKeys::LeftShift : ImGuiKey_ModShift,
    EKeys::RigthShift : ImGuiKey_ModShift,
    EKeys::LeftControl : ImGuiKey_ModCtrl,
    EKeys::RightControl : ImGuiKey_ModCtrl,
    EKeys::LeftAlt : ImGuiKey_ModAlt,
    EKeys::RightAlt : ImGuiKey_ModAlt,
    EKeys::LeftCommand : ImGuiKey_ModSuper,
    EKeys::RightCommand : ImGuiKey_ModSuper,
}

And then:

if(ImGuiInterops::UnrealToImGuiModKey(Key) != ImGuiKey_None)
{
    // Will need UnrealToImGuiModKey function just like UnrealToImGuiKey, maybe without the log
    IO.AddKeyEvent(ImGuiInterops::UnrealToImGuiModKey(Key), bIsDown);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without these anything that uses Mod keys break with this PR change


if (ImKey == ImGuiKey_LeftCtrl || ImKey == ImGuiKey_RightCtrl)
{
bIsControlDown = bIsDown;
}
else if (ImKey == ImGuiKey_LeftShift || ImKey == ImGuiKey_RightShift)
{
bIsShiftDown = bIsDown;
}
else if (ImKey == ImGuiKey_LeftAlt || ImKey == ImGuiKey_RightAlt)
{
bIsAltDown = bIsDown;
}
else if (ImKey == ImGuiKey_LeftSuper || ImKey == ImGuiKey_RightSuper)
{
if (MouseButtonsDown[MouseIndex] != bIsDown)
{
MouseButtonsDown[MouseIndex] = bIsDown;
MouseButtonsUpdateRange.AddPosition(MouseIndex);
}
bIsCommandDown = bIsDown;
}
}

void FImGuiInputState::ClearUpdateState()
void FImGuiInputState::SetMouseDown(const FPointerEvent& MouseEvent, bool bIsDown)
{
ClearCharacters();
const uint32 MouseIndex = ImGuiInterops::GetMouseIndex(MouseEvent);
IO.AddMouseButtonEvent(MouseIndex, bIsDown);
}

KeyDownEvents.Reset();
KeyUpEvents.Reset();
void FImGuiInputState::SetMouseDown(const FKey& MouseButton, bool bIsDown)
{
const uint32 MouseIndex = ImGuiInterops::GetMouseIndex(MouseButton);
IO.AddMouseButtonEvent(MouseIndex, bIsDown);
}

KeysUpdateRange.SetEmpty();
MouseButtonsUpdateRange.SetEmpty();
void FImGuiInputState::AddMouseWheelDelta(float DeltaValue)
{
IO.AddMouseWheelEvent(0, DeltaValue);
}

MouseWheelDelta = 0.f;
void FImGuiInputState::SetMousePosition(const FVector2D& Position)
{
IO.AddMousePosEvent(Position.X, Position.Y);
MousePosition = Position;
}

bTouchProcessed = bTouchDown;
void FImGuiInputState::SetMousePointer(bool bInHasMousePointer)
{
IO.MouseDrawCursor = bInHasMousePointer;
bHasMousePointer = bInHasMousePointer;
}

void FImGuiInputState::SetTouchDown(bool bIsDown)
{
IO.AddMouseButtonEvent(0, bIsDown);
bTouchDown = bIsDown;
}

void FImGuiInputState::ClearCharacters()
void FImGuiInputState::SetTouchPosition(const FVector2D& Position)
{
InputCharacters.Empty();
IO.AddMousePosEvent(Position.X, Position.Y);
}

void FImGuiInputState::ClearKeys()
void FImGuiInputState::SetGamepadNavigationAxis(const FAnalogInputEvent& AnalogInputEvent, float Value)
{
using std::fill;
fill(KeysDown, &KeysDown[Utilities::GetArraySize(KeysDown)], false);
ImGuiInterops::SetGamepadNavigationAxis(IO, AnalogInputEvent.GetKey(), Value);
}

void FImGuiInputState::SetKeyboardNavigationEnabled(bool bEnabled)
{
ImGuiInterops::SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, bEnabled);
bKeyboardNavigationEnabled = bEnabled;
}

// Mark the whole array as dirty because potentially each entry could be affected.
KeysUpdateRange.SetFull();
void FImGuiInputState::SetGamepadNavigationEnabled(bool bEnabled)
{
ImGuiInterops::SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, bEnabled);
bGamepadNavigationEnabled = bEnabled;
}

void FImGuiInputState::ClearMouseButtons()
void FImGuiInputState::SetGamepad(bool bInHasGamepad)
{
using std::fill;
fill(MouseButtonsDown, &MouseButtonsDown[Utilities::GetArraySize(MouseButtonsDown)], false);
ImGuiInterops::SetFlag(IO.BackendFlags, ImGuiBackendFlags_HasGamepad, bInHasGamepad);
bHasGamepad = bInHasGamepad;
}

// Mark the whole array as dirty because potentially each entry could be affected.
MouseButtonsUpdateRange.SetFull();
void FImGuiInputState::ClearUpdateState()
{
bTouchProcessed = bTouchDown;
}

void FImGuiInputState::ClearMouseAnalogue()
{
MousePosition = FVector2D::ZeroVector;
MouseWheelDelta = 0.f;
}

void FImGuiInputState::ClearModifierKeys()
{
bIsControlDown = false;
bIsShiftDown = false;
bIsAltDown = false;
}

void FImGuiInputState::ClearNavigationInputs()
{
using std::fill;
fill(NavigationInputs, &NavigationInputs[Utilities::GetArraySize(NavigationInputs)], 0.f);
bIsCommandDown = false;
}