From 852a5010228e04bf163ec2f8814958c9a486b268 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 23 Jun 2019 20:29:25 +0100 Subject: [PATCH] Moved input state from SImGuiWidget to FImGuiContextProxy and modified implementation of FImGuiInputState reset functionality. Moving input state to context proxy decouples it a bit from a particular input source and although not used right now, it allows multiple sources to send input in parallel. --- Source/ImGui/Private/ImGuiContextProxy.cpp | 6 +- Source/ImGui/Private/ImGuiContextProxy.h | 15 +--- Source/ImGui/Private/ImGuiInputState.cpp | 31 +------- Source/ImGui/Private/ImGuiInputState.h | 35 ++++++--- Source/ImGui/Private/Widgets/SImGuiWidget.cpp | 77 +++++++++---------- Source/ImGui/Private/Widgets/SImGuiWidget.h | 7 +- 6 files changed, 72 insertions(+), 99 deletions(-) diff --git a/Source/ImGui/Private/ImGuiContextProxy.cpp b/Source/ImGui/Private/ImGuiContextProxy.cpp index 38916e6..73cbb2c 100644 --- a/Source/ImGui/Private/ImGuiContextProxy.cpp +++ b/Source/ImGui/Private/ImGuiContextProxy.cpp @@ -151,10 +151,8 @@ void FImGuiContextProxy::BeginFrame(float DeltaTime) ImGuiIO& IO = ImGui::GetIO(); IO.DeltaTime = DeltaTime; - if (InputState) - { - ImGuiInterops::CopyInput(IO, *InputState); - } + ImGuiInterops::CopyInput(IO, InputState); + InputState.ClearUpdateState(); ImGui::NewFrame(); diff --git a/Source/ImGui/Private/ImGuiContextProxy.h b/Source/ImGui/Private/ImGuiContextProxy.h index f2fb997..f20291e 100644 --- a/Source/ImGui/Private/ImGuiContextProxy.h +++ b/Source/ImGui/Private/ImGuiContextProxy.h @@ -3,7 +3,7 @@ #pragma once #include "ImGuiDrawData.h" - +#include "ImGuiInputState.h" #include "Utilities/WorldContextIndex.h" #include @@ -13,8 +13,6 @@ #include -class FImGuiInputState; - // Represents a single ImGui context. All the context updates should be done through this proxy. During update it // broadcasts draw events to allow listeners draw their controls. After update it stores draw data. class FImGuiContextProxy @@ -58,13 +56,8 @@ public: const TArray& GetDrawData() const { return DrawLists; } // Get input state used by this context. - const FImGuiInputState* GetInputState() const { return InputState; } - - // Set input state to be used by this context. - void SetInputState(const FImGuiInputState* SourceInputState) { InputState = SourceInputState; } - - // If context is currently using input state to remove then remove that binding. - void RemoveInputState(const FImGuiInputState* InputStateToRemove) { if (InputState == InputStateToRemove) InputState = nullptr; } + FImGuiInputState& GetInputState() { return InputState; } + const FImGuiInputState& GetInputState() const { return InputState; } // Is this context the current ImGui context. bool IsCurrentContext() const { return ImGui::GetCurrentContext() == Context.Get(); } @@ -117,7 +110,7 @@ private: bool bIsDrawEarlyDebugCalled = false; bool bIsDrawDebugCalled = false; - const FImGuiInputState* InputState = nullptr; + FImGuiInputState InputState; TArray DrawLists; diff --git a/Source/ImGui/Private/ImGuiInputState.cpp b/Source/ImGui/Private/ImGuiInputState.cpp index d561b27..45e7f80 100644 --- a/Source/ImGui/Private/ImGuiInputState.cpp +++ b/Source/ImGui/Private/ImGuiInputState.cpp @@ -46,7 +46,7 @@ namespace FImGuiInputState::FImGuiInputState() { - ResetState(); + Reset(); } void FImGuiInputState::AddCharacter(TCHAR Char) @@ -82,31 +82,6 @@ void FImGuiInputState::SetMouseDown(uint32 MouseIndex, bool bIsDown) } } -void FImGuiInputState::Reset(bool bKeyboard, bool bMouse, bool bNavigation) -{ - if (bKeyboard) - { - ClearCharacters(); - ClearKeys(); - } - - if (bMouse) - { - ClearMouseButtons(); - ClearMouseAnalogue(); - } - - if (bKeyboard && bMouse) - { - ClearModifierKeys(); - } - - if (bNavigation) - { - ClearNavigationInputs(); - } -} - void FImGuiInputState::ClearUpdateState() { if (InputCharactersNum > 0) @@ -132,7 +107,7 @@ void FImGuiInputState::ClearKeys() using std::fill; fill(KeysDown, &KeysDown[Utilities::GetArraySize(KeysDown)], false); - // Expand update range because keys array has been updated. + // Mark the whole array as dirty because potentially each entry could be affected. KeysUpdateRange.SetFull(); } @@ -141,7 +116,7 @@ void FImGuiInputState::ClearMouseButtons() using std::fill; fill(MouseButtonsDown, &MouseButtonsDown[Utilities::GetArraySize(MouseButtonsDown)], false); - // Expand update range because mouse buttons array has been updated. + // Mark the whole array as dirty because potentially each entry could be affected. MouseButtonsUpdateRange.SetFull(); } diff --git a/Source/ImGui/Private/ImGuiInputState.h b/Source/ImGui/Private/ImGuiInputState.h index dcb52de..f8886e6 100644 --- a/Source/ImGui/Private/ImGuiInputState.h +++ b/Source/ImGui/Private/ImGuiInputState.h @@ -151,17 +151,34 @@ public: // @param bInHasGamepad - True, if gamepad is attached void SetGamepad(bool bInHasGamepad) { bHasGamepad = bInHasGamepad; } - // Reset the whole state and mark as dirty. - void ResetState() { Reset(true, true, true); } + // Reset the whole input state and mark it as dirty. + void Reset() + { + ResetKeyboard(); + ResetMouse(); + ResetGamepadNavigation(); + } - // Reset keyboard state and mark as dirty. - void ResetKeyboardState() { Reset(true, false, false); } + // Reset the keyboard input state and mark it as dirty. + void ResetKeyboard() + { + ClearCharacters(); + ClearKeys(); + ClearModifierKeys(); + } - // Reset mouse state and mark as dirty. - void ResetMouseState() { Reset(false, true, false); } + // Reset the mouse input state and mark it as dirty. + void ResetMouse() + { + ClearMouseButtons(); + ClearMouseAnalogue(); + } - // Reset navigation state. - void ResetNavigationState() { Reset(false, false, true); } + // Reset the gamepad navigation state. + void ResetGamepadNavigation() + { + ClearNavigationInputs(); + } // Clear part of the state that is meant to be updated in every frame like: accumulators, buffers, navigation data // and information about dirty parts of keys or mouse buttons arrays. @@ -172,8 +189,6 @@ private: void SetKeyDown(uint32 KeyIndex, bool bIsDown); void SetMouseDown(uint32 MouseIndex, bool IsDown); - void Reset(bool bKeyboard, bool bMouse, bool bNavigation); - void ClearCharacters(); void ClearKeys(); void ClearMouseButtons(); diff --git a/Source/ImGui/Private/Widgets/SImGuiWidget.cpp b/Source/ImGui/Private/Widgets/SImGuiWidget.cpp index c1c90ba..adf6393 100644 --- a/Source/ImGui/Private/Widgets/SImGuiWidget.cpp +++ b/Source/ImGui/Private/Widgets/SImGuiWidget.cpp @@ -10,6 +10,7 @@ #include "ImGuiImplementation.h" #include "ImGuiInputHandler.h" #include "ImGuiInputHandlerFactory.h" +#include "ImGuiInputState.h" #include "ImGuiInteroperability.h" #include "ImGuiModuleManager.h" #include "ImGuiModuleSettings.h" @@ -83,7 +84,7 @@ void SImGuiWidget::Construct(const FArguments& InArgs) #if IMGUI_WIDGET_DEBUG ContextProxy->OnDraw().AddRaw(this, &SImGuiWidget::OnDebugDraw); #endif // IMGUI_WIDGET_DEBUG - ContextProxy->SetInputState(&InputState); + InputState = &ContextProxy->GetInputState(); // Register for settings change. RegisterImGuiSettingsDelegates(); @@ -119,7 +120,6 @@ SImGuiWidget::~SImGuiWidget() #if IMGUI_WIDGET_DEBUG ContextProxy->OnDraw().RemoveAll(this); #endif // IMGUI_WIDGET_DEBUG - ContextProxy->RemoveInputState(&InputState); } // Unregister from post-update notifications. @@ -148,7 +148,7 @@ FReply SImGuiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEven const FImGuiInputResponse Response = InputHandler->OnKeyChar(CharacterEvent); if (Response.HasProcessingRequest()) { - InputState.AddCharacter(CharacterEvent.GetCharacter()); + InputState->AddCharacter(CharacterEvent.GetCharacter()); } return ToSlateReply(Response); @@ -158,12 +158,12 @@ FReply SImGuiWidget::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& Key { if (KeyEvent.GetKey().IsGamepadKey()) { - if (InputState.IsGamepadNavigationEnabled()) + if (InputState->IsGamepadNavigationEnabled()) { const FImGuiInputResponse Response = InputHandler->OnGamepadKeyDown(KeyEvent); if (Response.HasProcessingRequest()) { - InputState.SetGamepadNavigationKey(KeyEvent, true); + InputState->SetGamepadNavigationKey(KeyEvent, true); } return ToSlateReply(Response); @@ -180,7 +180,7 @@ FReply SImGuiWidget::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& Key const FImGuiInputResponse Response = InputHandler->OnKeyDown(KeyEvent); if (Response.HasProcessingRequest()) { - InputState.SetKeyDown(KeyEvent, true); + InputState->SetKeyDown(KeyEvent, true); CopyModifierKeys(KeyEvent); } @@ -192,10 +192,10 @@ FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEv { if (KeyEvent.GetKey().IsGamepadKey()) { - if (InputState.IsGamepadNavigationEnabled()) + if (InputState->IsGamepadNavigationEnabled()) { // Always handle key up events to protect from leaving accidental keys not cleared in ImGui input state. - InputState.SetGamepadNavigationKey(KeyEvent, false); + InputState->SetGamepadNavigationKey(KeyEvent, false); return ToSlateReply(InputHandler->OnGamepadKeyUp(KeyEvent)); } @@ -209,7 +209,7 @@ FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEv UpdateCanvasControlMode(KeyEvent); // Always handle key up events to protect from leaving accidental keys not cleared in ImGui input state. - InputState.SetKeyDown(KeyEvent, false); + InputState->SetKeyDown(KeyEvent, false); CopyModifierKeys(KeyEvent); return ToSlateReply(InputHandler->OnKeyUp(KeyEvent)); @@ -218,12 +218,12 @@ FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEv FReply SImGuiWidget::OnAnalogValueChanged(const FGeometry& MyGeometry, const FAnalogInputEvent& AnalogInputEvent) { - if (AnalogInputEvent.GetKey().IsGamepadKey() && InputState.IsGamepadNavigationEnabled()) + if (AnalogInputEvent.GetKey().IsGamepadKey() && InputState->IsGamepadNavigationEnabled()) { const FImGuiInputResponse Response = InputHandler->OnGamepadAxis(AnalogInputEvent); if (Response.HasProcessingRequest()) { - InputState.SetGamepadNavigationAxis(AnalogInputEvent, AnalogInputEvent.GetAnalogValue()); + InputState->SetGamepadNavigationAxis(AnalogInputEvent, AnalogInputEvent.GetAnalogValue()); } return ToSlateReply(Response); @@ -236,32 +236,32 @@ FReply SImGuiWidget::OnAnalogValueChanged(const FGeometry& MyGeometry, const FAn FReply SImGuiWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.SetMouseDown(MouseEvent, true); + InputState->SetMouseDown(MouseEvent, true); return FReply::Handled(); } FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.SetMouseDown(MouseEvent, true); + InputState->SetMouseDown(MouseEvent, true); return FReply::Handled(); } FReply SImGuiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.SetMouseDown(MouseEvent, false); + InputState->SetMouseDown(MouseEvent, false); return FReply::Handled(); } FReply SImGuiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.AddMouseWheelDelta(MouseEvent.GetWheelDelta()); + InputState->AddMouseWheelDelta(MouseEvent.GetWheelDelta()); return FReply::Handled(); } FReply SImGuiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(MyGeometry.GetAccumulatedRenderTransform()); - InputState.SetMousePosition(ImGuiToScreen.Inverse().TransformPoint(MouseEvent.GetScreenSpacePosition())); + InputState->SetMousePosition(ImGuiToScreen.Inverse().TransformPoint(MouseEvent.GetScreenSpacePosition())); return FReply::Handled(); } @@ -300,7 +300,7 @@ void SImGuiWidget::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent { for (const FKey& Button : { EKeys::LeftMouseButton, EKeys::MiddleMouseButton, EKeys::RightMouseButton, EKeys::ThumbMouseButton, EKeys::ThumbMouseButton2 }) { - InputState.SetMouseDown(Button, MouseEvent.IsMouseButtonDown(Button)); + InputState->SetMouseDown(Button, MouseEvent.IsMouseButtonDown(Button)); } } @@ -375,9 +375,9 @@ void SImGuiWidget::UnregisterImGuiSettingsDelegates() void SImGuiWidget::CopyModifierKeys(const FInputEvent& InputEvent) { - InputState.SetControlDown(InputEvent.IsControlDown()); - InputState.SetShiftDown(InputEvent.IsShiftDown()); - InputState.SetAltDown(InputEvent.IsAltDown()); + InputState->SetControlDown(InputEvent.IsControlDown()); + InputState->SetShiftDown(InputEvent.IsShiftDown()); + InputState->SetAltDown(InputEvent.IsAltDown()); } bool SImGuiWidget::IsConsoleOpened() const @@ -493,10 +493,10 @@ void SImGuiWidget::UpdateInputEnabled() if (bInputEnabled) { - InputState.SetKeyboardNavigationEnabled(ModuleManager && ModuleManager->GetProperties().IsKeyboardNavigationEnabled()); - InputState.SetGamepadNavigationEnabled(ModuleManager && ModuleManager->GetProperties().IsGamepadNavigationEnabled()); + InputState->SetKeyboardNavigationEnabled(ModuleManager && ModuleManager->GetProperties().IsKeyboardNavigationEnabled()); + InputState->SetGamepadNavigationEnabled(ModuleManager && ModuleManager->GetProperties().IsGamepadNavigationEnabled()); const auto& Application = FSlateApplication::Get().GetPlatformApplication(); - InputState.SetGamepad(Application.IsValid() && Application->IsGamepadAttached()); + InputState->SetGamepad(Application.IsValid() && Application->IsGamepadAttached()); } } @@ -516,18 +516,18 @@ void SImGuiWidget::UpdateInputMode(bool bHasKeyboardFocus, bool bHasMousePointer // mouse-only input mode. if (NewInputMode == EInputMode::None) { - InputState.ResetState(); + InputState->Reset(); } else if (InputMode == EInputMode::Full) { - InputState.ResetKeyboardState(); - InputState.ResetNavigationState(); + InputState->ResetKeyboard(); + InputState->ResetGamepadNavigation(); } InputMode = NewInputMode; } - InputState.SetMousePointer(bUseSoftwareCursor && bHasMousePointer); + InputState->SetMousePointer(bUseSoftwareCursor && bHasMousePointer); } void SImGuiWidget::UpdateCanvasControlMode(const FInputEvent& InputEvent) @@ -537,11 +537,6 @@ void SImGuiWidget::UpdateCanvasControlMode(const FInputEvent& InputEvent) void SImGuiWidget::OnPostImGuiUpdate() { - if (InputMode != EInputMode::None) - { - InputState.ClearUpdateState(); - } - ImGuiRenderTransform = ImGuiTransform; } @@ -780,7 +775,7 @@ void SImGuiWidget::OnDebugDraw() { TwoColumns::Value("Input Enabled", bInputEnabled); TwoColumns::Value("Input Mode", TEXT_INPUT_MODE(InputMode)); - TwoColumns::Value("Input Has Mouse Pointer", InputState.HasMousePointer()); + TwoColumns::Value("Input Has Mouse Pointer", InputState->HasMousePointer()); }); TwoColumns::CollapsingGroup("Widget", [&]() @@ -837,7 +832,7 @@ void SImGuiWidget::OnDebugDraw() { const FKey& Key = Keys[Idx]; const uint32 KeyIndex = ImGuiInterops::GetKeyIndex(Key); - Styles::TextHighlight(InputState.GetKeys()[KeyIndex], [&]() + Styles::TextHighlight(InputState->GetKeys()[KeyIndex], [&]() { TwoColumns::Value(*Key.GetDisplayName().ToString(), KeyIndex); }); @@ -852,9 +847,9 @@ void SImGuiWidget::OnDebugDraw() Columns::CollapsingGroup("Modifier Keys", 4, [&]() { - Styles::TextHighlight(InputState.IsShiftDown(), [&]() { ImGui::Text("Shift"); }); ImGui::NextColumn(); - Styles::TextHighlight(InputState.IsControlDown(), [&]() { ImGui::Text("Control"); }); ImGui::NextColumn(); - Styles::TextHighlight(InputState.IsAltDown(), [&]() { ImGui::Text("Alt"); }); ImGui::NextColumn(); + Styles::TextHighlight(InputState->IsShiftDown(), [&]() { ImGui::Text("Shift"); }); ImGui::NextColumn(); + Styles::TextHighlight(InputState->IsControlDown(), [&]() { ImGui::Text("Control"); }); ImGui::NextColumn(); + Styles::TextHighlight(InputState->IsAltDown(), [&]() { ImGui::Text("Alt"); }); ImGui::NextColumn(); ImGui::NextColumn(); }); @@ -877,7 +872,7 @@ void SImGuiWidget::OnDebugDraw() { const FKey& Button = Buttons[Idx]; const uint32 MouseIndex = ImGuiInterops::GetMouseIndex(Button); - Styles::TextHighlight(InputState.GetMouseButtons()[MouseIndex], [&]() + Styles::TextHighlight(InputState->GetMouseButtons()[MouseIndex], [&]() { TwoColumns::Value(*Button.GetDisplayName().ToString(), MouseIndex); }); @@ -892,9 +887,9 @@ void SImGuiWidget::OnDebugDraw() Columns::CollapsingGroup("Mouse Axes", 4, [&]() { - TwoColumns::Value("Position X", InputState.GetMousePosition().X); - TwoColumns::Value("Position Y", InputState.GetMousePosition().Y); - TwoColumns::Value("Wheel Delta", InputState.GetMouseWheelDelta()); + TwoColumns::Value("Position X", InputState->GetMousePosition().X); + TwoColumns::Value("Position Y", InputState->GetMousePosition().Y); + TwoColumns::Value("Wheel Delta", InputState->GetMouseWheelDelta()); ImGui::NextColumn(); ImGui::NextColumn(); }); diff --git a/Source/ImGui/Private/Widgets/SImGuiWidget.h b/Source/ImGui/Private/Widgets/SImGuiWidget.h index b494f8c..3a6dc24 100644 --- a/Source/ImGui/Private/Widgets/SImGuiWidget.h +++ b/Source/ImGui/Private/Widgets/SImGuiWidget.h @@ -2,7 +2,6 @@ #pragma once -#include "ImGuiInputState.h" #include "ImGuiModuleDebug.h" #include "ImGuiModuleSettings.h" @@ -12,6 +11,7 @@ // Hide ImGui Widget debug in non-developer mode. #define IMGUI_WIDGET_DEBUG IMGUI_MODULE_DEVELOPER +class FImGuiInputState; class FImGuiModuleManager; class SImGuiCanvasControl; class UImGuiInputHandler; @@ -37,9 +37,6 @@ public: // Get index of the context that this widget is targeting. int32 GetContextIndex() const { return ContextIndex; } - // Get input state associated with this widget. - const FImGuiInputState& GetInputState() const { return InputState; } - //---------------------------------------------------------------------------------------------------- // SWidget overrides //---------------------------------------------------------------------------------------------------- @@ -137,7 +134,7 @@ private: int32 ContextIndex = 0; - FImGuiInputState InputState; + FImGuiInputState* InputState; EInputMode InputMode = EInputMode::None; bool bInputEnabled = false;