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.
This commit is contained in:
Sebastian 2019-06-23 20:29:25 +01:00
parent 22c5b42387
commit 852a501022
6 changed files with 72 additions and 99 deletions

View File

@ -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();

View File

@ -3,7 +3,7 @@
#pragma once
#include "ImGuiDrawData.h"
#include "ImGuiInputState.h"
#include "Utilities/WorldContextIndex.h"
#include <ICursor.h>
@ -13,8 +13,6 @@
#include <string>
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<FImGuiDrawList>& 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<FImGuiDrawList> DrawLists;

View File

@ -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();
}

View File

@ -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();

View File

@ -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();
});

View File

@ -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;