diff --git a/Source/ImGui/Private/ImGuiInputHandler.cpp b/Source/ImGui/Private/ImGuiInputHandler.cpp index 3a13f1d..87d0b0f 100644 --- a/Source/ImGui/Private/ImGuiInputHandler.cpp +++ b/Source/ImGui/Private/ImGuiInputHandler.cpp @@ -145,6 +145,25 @@ FReply UImGuiInputHandler::OnMouseMove(const FVector2D& MousePosition) return ToReply(true); } +FReply UImGuiInputHandler::OnTouchStarted(const FVector2D& CursorPosition, const FPointerEvent& TouchEvent) +{ + InputState->SetTouchDown(true); + InputState->SetTouchPosition(CursorPosition); + return ToReply(true); +} + +FReply UImGuiInputHandler::OnTouchMoved(const FVector2D& CursorPosition, const FPointerEvent& TouchEvent) +{ + InputState->SetTouchPosition(CursorPosition); + return ToReply(true); +} + +FReply UImGuiInputHandler::OnTouchEnded(const FVector2D& CursorPosition, const FPointerEvent& TouchEvent) +{ + InputState->SetTouchDown(false); + return ToReply(true); +} + void UImGuiInputHandler::OnKeyboardInputEnabled() { bKeyboardInputEnabled = true; diff --git a/Source/ImGui/Private/ImGuiInputState.cpp b/Source/ImGui/Private/ImGuiInputState.cpp index 45e7f80..da5b3c8 100644 --- a/Source/ImGui/Private/ImGuiInputState.cpp +++ b/Source/ImGui/Private/ImGuiInputState.cpp @@ -93,6 +93,8 @@ void FImGuiInputState::ClearUpdateState() MouseButtonsUpdateRange.SetEmpty(); MouseWheelDelta = 0.f; + + bTouchProcessed = bTouchDown; } void FImGuiInputState::ClearCharacters() diff --git a/Source/ImGui/Private/ImGuiInputState.h b/Source/ImGui/Private/ImGuiInputState.h index f8886e6..2681faa 100644 --- a/Source/ImGui/Private/ImGuiInputState.h +++ b/Source/ImGui/Private/ImGuiInputState.h @@ -82,11 +82,11 @@ public: // @param DeltaValue - Mouse wheel delta to add void AddMouseWheelDelta(float DeltaValue) { MouseWheelDelta += DeltaValue; } - // Get the current mouse position. + // Get the mouse position. const FVector2D& GetMousePosition() const { return MousePosition; } - // Set mouse position. - // @param Position - New mouse position + // Set the mouse position. + // @param Position - Mouse position void SetMousePosition(const FVector2D& Position) { MousePosition = Position; } // Check whether input has active mouse pointer. @@ -96,6 +96,24 @@ public: // @param bHasPointer - True, if input has active mouse pointer void SetMousePointer(bool bInHasMousePointer) { bHasMousePointer = bInHasMousePointer; } + // Check whether touch input is in progress. True, after touch is started until one frame after it has ended. + // One frame delay is used to process mouse release in ImGui since touch-down is simulated with mouse-down. + bool IsTouchActive() const { return bTouchDown || bTouchProcessed; } + + // Check whether touch input is down. + bool IsTouchDown() const { return bTouchDown; } + + // Set whether touch input is down. + // @param bIsDown - True, if touch is down (or started) and false, if touch is up (or ended) + void SetTouchDown(bool bIsDown) { bTouchDown = bIsDown; } + + // Get the touch position. + const FVector2D& GetTouchPosition() const { return TouchPosition; } + + // Set the touch position. + // @param Position - Touch position + void SetTouchPosition(const FVector2D& Position) { TouchPosition = Position; } + // Get Control down state. bool IsControlDown() const { return bIsControlDown; } @@ -197,6 +215,7 @@ private: void ClearNavigationInputs(); FVector2D MousePosition = FVector2D::ZeroVector; + FVector2D TouchPosition = FVector2D::ZeroVector; float MouseWheelDelta = 0.f; FMouseButtonsArray MouseButtonsDown; @@ -211,6 +230,8 @@ private: FNavInputArray NavigationInputs; bool bHasMousePointer = false; + bool bTouchDown = false; + bool bTouchProcessed = false; bool bIsControlDown = false; bool bIsShiftDown = false; diff --git a/Source/ImGui/Private/ImGuiInteroperability.cpp b/Source/ImGui/Private/ImGuiInteroperability.cpp index f78e34a..51d0861 100644 --- a/Source/ImGui/Private/ImGuiInteroperability.cpp +++ b/Source/ImGui/Private/ImGuiInteroperability.cpp @@ -247,16 +247,6 @@ namespace ImGuiInterops static const uint32 LeftAlt = GetKeyIndex(EKeys::LeftAlt); static const uint32 RightAlt = GetKeyIndex(EKeys::RightAlt); - // Check whether we need to draw cursor. - IO.MouseDrawCursor = InputState.HasMousePointer(); - - // Copy mouse position. - IO.MousePos.x = InputState.GetMousePosition().X; - IO.MousePos.y = InputState.GetMousePosition().Y; - - // Copy mouse wheel delta. - IO.MouseWheel += InputState.GetMouseWheelDelta(); - // Copy key modifiers. IO.KeyCtrl = InputState.IsControlDown(); IO.KeyShift = InputState.IsShiftDown(); @@ -287,5 +277,28 @@ namespace ImGuiInterops SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, InputState.IsKeyboardNavigationEnabled()); SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, InputState.IsGamepadNavigationEnabled()); SetFlag(IO.BackendFlags, ImGuiBackendFlags_HasGamepad, InputState.HasGamepad()); + + // Check whether we need to draw cursor. + IO.MouseDrawCursor = InputState.HasMousePointer(); + + // If touch is enabled and active, give it a precedence. + if (InputState.IsTouchActive()) + { + // Copy the touch position to mouse position. + IO.MousePos.x = InputState.GetTouchPosition().X; + IO.MousePos.y = InputState.GetTouchPosition().Y; + + // With touch active one frame longer than it is down, we have one frame to processed touch up. + IO.MouseDown[0] = InputState.IsTouchDown(); + } + else + { + // Copy the mouse position. + IO.MousePos.x = InputState.GetMousePosition().X; + IO.MousePos.y = InputState.GetMousePosition().Y; + + // Copy mouse wheel delta. + IO.MouseWheel += InputState.GetMouseWheelDelta(); + } } } diff --git a/Source/ImGui/Private/Widgets/SImGuiWidget.cpp b/Source/ImGui/Private/Widgets/SImGuiWidget.cpp index bfc617e..8a54a15 100644 --- a/Source/ImGui/Private/Widgets/SImGuiWidget.cpp +++ b/Source/ImGui/Private/Widgets/SImGuiWidget.cpp @@ -189,8 +189,7 @@ FReply SImGuiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEve FReply SImGuiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(MyGeometry.GetAccumulatedRenderTransform()); - return InputHandler->OnMouseMove(ImGuiToScreen.Inverse().TransformPoint(MouseEvent.GetScreenSpacePosition())); + return InputHandler->OnMouseMove(TransformScreenPointToImGui(MyGeometry, MouseEvent.GetScreenSpacePosition())); } FReply SImGuiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent) @@ -235,6 +234,22 @@ void SImGuiWidget::OnMouseLeave(const FPointerEvent& MouseEvent) InputHandler->OnMouseInputDisabled(); } +FReply SImGuiWidget::OnTouchStarted(const FGeometry& MyGeometry, const FPointerEvent& TouchEvent) +{ + return InputHandler->OnTouchStarted(TransformScreenPointToImGui(MyGeometry, TouchEvent.GetScreenSpacePosition()), TouchEvent); +} + +FReply SImGuiWidget::OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& TouchEvent) +{ + return InputHandler->OnTouchMoved(TransformScreenPointToImGui(MyGeometry, TouchEvent.GetScreenSpacePosition()), TouchEvent); +} + +FReply SImGuiWidget::OnTouchEnded(const FGeometry& MyGeometry, const FPointerEvent& TouchEvent) +{ + UpdateVisibility(); + return InputHandler->OnTouchEnded(TransformScreenPointToImGui(MyGeometry, TouchEvent.GetScreenSpacePosition()), TouchEvent); +} + void SImGuiWidget::CreateInputHandler(const FStringClassReference& HandlerClassReference) { ReleaseInputHandler(); @@ -446,8 +461,7 @@ void SImGuiWidget::UpdateTransparentMouseInput(const FGeometry& AllottedGeometry { if (!GameViewport->GetGameViewportWidget()->HasMouseCapture()) { - const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(AllottedGeometry.GetAccumulatedRenderTransform()); - InputHandler->OnMouseMove(ImGuiToScreen.Inverse().TransformPoint(FSlateApplication::Get().GetCursorPos())); + InputHandler->OnMouseMove(TransformScreenPointToImGui(AllottedGeometry, FSlateApplication::Get().GetCursorPos())); } } } @@ -490,6 +504,12 @@ void SImGuiWidget::OnPostImGuiUpdate() UpdateMouseCursor(); } +FVector2D SImGuiWidget::TransformScreenPointToImGui(const FGeometry& MyGeometry, const FVector2D& Point) const +{ + const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(MyGeometry.GetAccumulatedRenderTransform()); + return ImGuiToScreen.Inverse().TransformPoint(Point); +} + namespace { FORCEINLINE FSlateRenderTransform RoundTranslation(const FSlateRenderTransform& Transform) diff --git a/Source/ImGui/Private/Widgets/SImGuiWidget.h b/Source/ImGui/Private/Widgets/SImGuiWidget.h index 4806224..7239833 100644 --- a/Source/ImGui/Private/Widgets/SImGuiWidget.h +++ b/Source/ImGui/Private/Widgets/SImGuiWidget.h @@ -70,6 +70,12 @@ public: virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; + virtual FReply OnTouchStarted(const FGeometry& MyGeometry, const FPointerEvent& TouchEvent) override; + + virtual FReply OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& TouchEvent) override; + + virtual FReply OnTouchEnded(const FGeometry& MyGeometry, const FPointerEvent& TouchEvent) override; + private: void CreateInputHandler(const FStringClassReference& HandlerClassReference); @@ -101,6 +107,8 @@ private: void OnPostImGuiUpdate(); + FVector2D TransformScreenPointToImGui(const FGeometry& MyGeometry, const FVector2D& Point) const; + virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& WidgetStyle, bool bParentEnabled) const override; virtual FVector2D ComputeDesiredSize(float) const override; diff --git a/Source/ImGui/Public/ImGuiInputHandler.h b/Source/ImGui/Public/ImGuiInputHandler.h index f490a58..a73b599 100644 --- a/Source/ImGui/Public/ImGuiInputHandler.h +++ b/Source/ImGui/Public/ImGuiInputHandler.h @@ -82,11 +82,35 @@ public: /** * Called to handle mouse move events. - * @param Mouse position (in ImGui space) + * @param MousePosition Mouse position (in ImGui space) * @returns Response whether the event was handled */ virtual FReply OnMouseMove(const FVector2D& MousePosition); + /** + * Called to handle touch started event. + * @param TouchPosition Touch position (in ImGui space) + * @param TouchEvent Touch event passed from Slate + * @returns Response whether the event was handled + */ + virtual FReply OnTouchStarted(const FVector2D& TouchPosition, const FPointerEvent& TouchEvent); + + /** + * Called to handle touch moved event. + * @param TouchPosition Touch position (in ImGui space) + * @param TouchEvent Touch event passed from Slate + * @returns Response whether the event was handled + */ + virtual FReply OnTouchMoved(const FVector2D& TouchPosition, const FPointerEvent& TouchEvent); + + /** + * Called to handle touch ended event. + * @param TouchPosition Touch position (in ImGui space) + * @param TouchEvent Touch event passed from Slate + * @returns Response whether the event was handled + */ + virtual FReply OnTouchEnded(const FVector2D& TouchPosition, const FPointerEvent& TouchEvent); + /** Called to handle activation of the keyboard input. */ virtual void OnKeyboardInputEnabled();