Added support for touch input (experimental and right now only non-shared):

- Added to SImGuiWidget and FImGuiInputHandler handling of touch started, move and ended events.
- Events are passed to FImGuiInputState to be copied to ImGui IO as a mouse move and left button down.
- Added one frame lag between touch ending event and ending processing, to allow ImGui handle mouse-up event.
This commit is contained in:
Sebastian 2019-08-01 21:41:12 +01:00
parent e651b0f88f
commit 5f1dc964cf
7 changed files with 125 additions and 18 deletions

View File

@ -145,6 +145,25 @@ FReply UImGuiInputHandler::OnMouseMove(const FVector2D& MousePosition)
return ToReply(true); 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() void UImGuiInputHandler::OnKeyboardInputEnabled()
{ {
bKeyboardInputEnabled = true; bKeyboardInputEnabled = true;

View File

@ -93,6 +93,8 @@ void FImGuiInputState::ClearUpdateState()
MouseButtonsUpdateRange.SetEmpty(); MouseButtonsUpdateRange.SetEmpty();
MouseWheelDelta = 0.f; MouseWheelDelta = 0.f;
bTouchProcessed = bTouchDown;
} }
void FImGuiInputState::ClearCharacters() void FImGuiInputState::ClearCharacters()

View File

@ -82,11 +82,11 @@ public:
// @param DeltaValue - Mouse wheel delta to add // @param DeltaValue - Mouse wheel delta to add
void AddMouseWheelDelta(float DeltaValue) { MouseWheelDelta += DeltaValue; } void AddMouseWheelDelta(float DeltaValue) { MouseWheelDelta += DeltaValue; }
// Get the current mouse position. // Get the mouse position.
const FVector2D& GetMousePosition() const { return MousePosition; } const FVector2D& GetMousePosition() const { return MousePosition; }
// Set mouse position. // Set the mouse position.
// @param Position - New mouse position // @param Position - Mouse position
void SetMousePosition(const FVector2D& Position) { MousePosition = Position; } void SetMousePosition(const FVector2D& Position) { MousePosition = Position; }
// Check whether input has active mouse pointer. // Check whether input has active mouse pointer.
@ -96,6 +96,24 @@ public:
// @param bHasPointer - True, if input has active mouse pointer // @param bHasPointer - True, if input has active mouse pointer
void SetMousePointer(bool bInHasMousePointer) { bHasMousePointer = bInHasMousePointer; } 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. // Get Control down state.
bool IsControlDown() const { return bIsControlDown; } bool IsControlDown() const { return bIsControlDown; }
@ -197,6 +215,7 @@ private:
void ClearNavigationInputs(); void ClearNavigationInputs();
FVector2D MousePosition = FVector2D::ZeroVector; FVector2D MousePosition = FVector2D::ZeroVector;
FVector2D TouchPosition = FVector2D::ZeroVector;
float MouseWheelDelta = 0.f; float MouseWheelDelta = 0.f;
FMouseButtonsArray MouseButtonsDown; FMouseButtonsArray MouseButtonsDown;
@ -211,6 +230,8 @@ private:
FNavInputArray NavigationInputs; FNavInputArray NavigationInputs;
bool bHasMousePointer = false; bool bHasMousePointer = false;
bool bTouchDown = false;
bool bTouchProcessed = false;
bool bIsControlDown = false; bool bIsControlDown = false;
bool bIsShiftDown = false; bool bIsShiftDown = false;

View File

@ -247,16 +247,6 @@ namespace ImGuiInterops
static const uint32 LeftAlt = GetKeyIndex(EKeys::LeftAlt); static const uint32 LeftAlt = GetKeyIndex(EKeys::LeftAlt);
static const uint32 RightAlt = GetKeyIndex(EKeys::RightAlt); 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. // Copy key modifiers.
IO.KeyCtrl = InputState.IsControlDown(); IO.KeyCtrl = InputState.IsControlDown();
IO.KeyShift = InputState.IsShiftDown(); IO.KeyShift = InputState.IsShiftDown();
@ -287,5 +277,28 @@ namespace ImGuiInterops
SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, InputState.IsKeyboardNavigationEnabled()); SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, InputState.IsKeyboardNavigationEnabled());
SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, InputState.IsGamepadNavigationEnabled()); SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, InputState.IsGamepadNavigationEnabled());
SetFlag(IO.BackendFlags, ImGuiBackendFlags_HasGamepad, InputState.HasGamepad()); 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();
}
} }
} }

View File

@ -189,8 +189,7 @@ FReply SImGuiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEve
FReply SImGuiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) FReply SImGuiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{ {
const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(MyGeometry.GetAccumulatedRenderTransform()); return InputHandler->OnMouseMove(TransformScreenPointToImGui(MyGeometry, MouseEvent.GetScreenSpacePosition()));
return InputHandler->OnMouseMove(ImGuiToScreen.Inverse().TransformPoint(MouseEvent.GetScreenSpacePosition()));
} }
FReply SImGuiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent) FReply SImGuiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent)
@ -235,6 +234,22 @@ void SImGuiWidget::OnMouseLeave(const FPointerEvent& MouseEvent)
InputHandler->OnMouseInputDisabled(); 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) void SImGuiWidget::CreateInputHandler(const FStringClassReference& HandlerClassReference)
{ {
ReleaseInputHandler(); ReleaseInputHandler();
@ -446,8 +461,7 @@ void SImGuiWidget::UpdateTransparentMouseInput(const FGeometry& AllottedGeometry
{ {
if (!GameViewport->GetGameViewportWidget()->HasMouseCapture()) if (!GameViewport->GetGameViewportWidget()->HasMouseCapture())
{ {
const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(AllottedGeometry.GetAccumulatedRenderTransform()); InputHandler->OnMouseMove(TransformScreenPointToImGui(AllottedGeometry, FSlateApplication::Get().GetCursorPos()));
InputHandler->OnMouseMove(ImGuiToScreen.Inverse().TransformPoint(FSlateApplication::Get().GetCursorPos()));
} }
} }
} }
@ -490,6 +504,12 @@ void SImGuiWidget::OnPostImGuiUpdate()
UpdateMouseCursor(); UpdateMouseCursor();
} }
FVector2D SImGuiWidget::TransformScreenPointToImGui(const FGeometry& MyGeometry, const FVector2D& Point) const
{
const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(MyGeometry.GetAccumulatedRenderTransform());
return ImGuiToScreen.Inverse().TransformPoint(Point);
}
namespace namespace
{ {
FORCEINLINE FSlateRenderTransform RoundTranslation(const FSlateRenderTransform& Transform) FORCEINLINE FSlateRenderTransform RoundTranslation(const FSlateRenderTransform& Transform)

View File

@ -70,6 +70,12 @@ public:
virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; 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: private:
void CreateInputHandler(const FStringClassReference& HandlerClassReference); void CreateInputHandler(const FStringClassReference& HandlerClassReference);
@ -101,6 +107,8 @@ private:
void OnPostImGuiUpdate(); 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 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; virtual FVector2D ComputeDesiredSize(float) const override;

View File

@ -82,11 +82,35 @@ public:
/** /**
* Called to handle mouse move events. * 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 * @returns Response whether the event was handled
*/ */
virtual FReply OnMouseMove(const FVector2D& MousePosition); 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. */ /** Called to handle activation of the keyboard input. */
virtual void OnKeyboardInputEnabled(); virtual void OnKeyboardInputEnabled();