void FSceneViewport::ApplyModifierKeys( const FModifierKeysState& InKeysState ) { if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if ( InKeysState.IsLeftAltDown() ) { ViewportClient->InputKey( this, 0, EKeys::LeftAlt, IE_Pressed ); } if ( InKeysState.IsRightAltDown() ) { ViewportClient->InputKey( this, 0, EKeys::RightAlt, IE_Pressed ); } if ( InKeysState.IsLeftControlDown() ) { ViewportClient->InputKey( this, 0, EKeys::LeftControl, IE_Pressed ); } if ( InKeysState.IsRightControlDown() ) { ViewportClient->InputKey( this, 0, EKeys::RightControl, IE_Pressed ); } if ( InKeysState.IsLeftShiftDown() ) { ViewportClient->InputKey( this, 0, EKeys::LeftShift, IE_Pressed ); } if ( InKeysState.IsRightShiftDown() ) { ViewportClient->InputKey( this, 0, EKeys::RightShift, IE_Pressed ); } } }
void FSceneViewport::OnDrawViewport( const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) { // Switch to the viewport clients world before resizing FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); /** Check to see if the viewport should be resized */ FIntPoint DrawSize = FIntPoint( FMath::RoundToInt( AllottedGeometry.GetDrawSize().X ), FMath::RoundToInt( AllottedGeometry.GetDrawSize().Y ) ); if( GetSizeXY() != DrawSize ) { TSharedPtr<SWindow> Window = FSlateApplication::Get().FindWidgetWindow( ViewportWidget.Pin().ToSharedRef() ); check(Window.IsValid()); ResizeViewport(FMath::Max(0, DrawSize.X), FMath::Max(0, DrawSize.Y), Window->GetWindowMode(), 0, 0); } // Cannot pass negative canvas positions float CanvasMinX = FMath::Max(0.0f, AllottedGeometry.AbsolutePosition.X); float CanvasMinY = FMath::Max(0.0f, AllottedGeometry.AbsolutePosition.Y); FIntRect CanvasRect( FMath::RoundToInt( CanvasMinX ), FMath::RoundToInt( CanvasMinY ), FMath::RoundToInt( CanvasMinX + AllottedGeometry.Size.X * AllottedGeometry.Scale ), FMath::RoundToInt( CanvasMinY + AllottedGeometry.Size.Y * AllottedGeometry.Scale ) ); DebugCanvasDrawer->BeginRenderingCanvas( CanvasRect ); // Draw above everything else uint32 MaxLayer = MAX_uint32; FSlateDrawElement::MakeCustom( OutDrawElements, MAX_uint32, DebugCanvasDrawer ); }
FReply FSceneViewport::OnMouseButtonDoubleClick( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); // Note: When double-clicking, the following message sequence is sent: // WM_*BUTTONDOWN // WM_*BUTTONUP // WM_*BUTTONDBLCLK (Needs to set the KeyStates[*] to true) // WM_*BUTTONUP KeyStateMap.Add( InMouseEvent.GetEffectingButton(), true ); UpdateCachedMousePos( InGeometry, InMouseEvent ); UpdateCachedGeometry(InGeometry); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( !ViewportClient->InputKey( this, 0, InMouseEvent.GetEffectingButton(), IE_DoubleClick ) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
void FSceneViewport::OnViewportClosed() { if( ViewportClient ) { FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); ViewportClient->CloseRequested( this ); } }
TOptional<bool> FSceneViewport::OnQueryShowFocus(const EFocusCause InFocusCause) const { if (ViewportClient) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher(ViewportClient); return ViewportClient->QueryShowFocus(InFocusCause); } return TOptional<bool>(); }
FReply FSceneViewport::OnMouseButtonUp( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); KeyStateMap.Add( InMouseEvent.GetEffectingButton(), false ); UpdateModifierKeys( InMouseEvent ); UpdateCachedMousePos( InGeometry, InMouseEvent ); UpdateCachedGeometry(InGeometry); // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); bool bCursorVisible = true; bool bReleaseMouse = true; if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { if (!ViewportClient->InputKey(this, InMouseEvent.GetUserIndex(), InMouseEvent.GetEffectingButton(), IE_Released)) { CurrentReplyState = FReply::Unhandled(); } bCursorVisible = ViewportClient->GetCursor(this, GetMouseX(), GetMouseY()) != EMouseCursor::None; bReleaseMouse = bCursorVisible || ViewportClient->CaptureMouseOnClick() == EMouseCaptureMode::CaptureDuringMouseDown || ( ViewportClient->CaptureMouseOnClick() == EMouseCaptureMode::CaptureDuringRightMouseDown && InMouseEvent.GetEffectingButton() == EKeys::RightMouseButton ); } if (!((FApp::IsGame() && !GIsEditor) || bIsPlayInEditorViewport) || bReleaseMouse) { // On mouse up outside of the game (editor viewport) or if the cursor is visible in game, we should make sure the mouse is no longer captured // as long as the left or right mouse buttons are not still down if( !InMouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ) && !InMouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton )) { if( bCursorHiddenDueToCapture ) { bCursorHiddenDueToCapture = false; CurrentReplyState.SetMousePos( MousePosBeforeHiddenDueToCapture ); MousePosBeforeHiddenDueToCapture = FIntPoint( -1, -1 ); } CurrentReplyState.ReleaseMouseCapture(); if (bCursorVisible) { CurrentReplyState.ReleaseMouseLock(); } } } return CurrentReplyState; }
FReply FSceneViewport::OnKeyChar( const FGeometry& InGeometry, const FCharacterEvent& InCharacterEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( !ViewportClient->InputChar( this,0, InCharacterEvent.GetCharacter() ) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnMotionDetected( const FGeometry& MyGeometry, const FMotionEvent& MotionEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); if( ViewportClient ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( !ViewportClient->InputMotion( this, MotionEvent.GetUserIndex(), MotionEvent.GetTilt(), MotionEvent.GetRotationRate(), MotionEvent.GetGravity(), MotionEvent.GetAcceleration()) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnControllerButtonReleased( const FGeometry& MyGeometry, const FControllerEvent& ControllerEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); KeyStateMap.Add( ControllerEvent.GetEffectingButton(), false ); if( ViewportClient ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( !ViewportClient->InputKey( this, ControllerEvent.GetUserIndex(), ControllerEvent.GetEffectingButton(), IE_Released, 1.0f, true ) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnKeyboardFocusReceived( const FKeyboardFocusEvent& InKeyboardFocusEvent ) { CurrentReplyState = FReply::Handled(); if( ViewportClient ) { FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); ViewportClient->ReceivedFocus( this ); if( ( FApp::IsGame() && !GIsEditor ) || bIsPlayInEditorViewport ) { if( IsForegroundWindow() ) { const bool bIsCursorForcedVisible = ( ViewportClient != NULL && ViewportClient->GetCursor( this, GetMouseX(), GetMouseY() ) != EMouseCursor::None ); const bool bPlayInEditorCapture = !bIsPlayInEditorViewport || InKeyboardFocusEvent.GetCause() != EKeyboardFocusCause::SetDirectly || bPlayInEditorGetsMouseControl; // capturing the mouse interferes with slate UI (like the virtual joysticks) if (FPlatformProperties::SupportsWindowedMode() && bPlayInEditorCapture && !bIsCursorForcedVisible && !FSlateApplication::Get().IsFakingTouchEvents()) { // Only require the user to click in the window the first time - after that return focus to the game so long as it was the last focused widget. // Means that tabbing in/out will return the mouse control to where it was & the in-game console won't leave the mouse under editor control. bPlayInEditorGetsMouseControl = true; CurrentReplyState.UseHighPrecisionMouseMovement( ViewportWidget.Pin().ToSharedRef() ); CurrentReplyState.LockMouseToWidget( ViewportWidget.Pin().ToSharedRef() ); } else if(!bPlayInEditorCapture) { FSlateApplication::Get().ClearKeyboardFocus( EKeyboardFocusCause::SetDirectly ); FSlateApplication::Get().ResetToDefaultInputSettings(); } } else { FSlateApplication::Get().ClearKeyboardFocus( EKeyboardFocusCause::Cleared ); } } } return CurrentReplyState; }
FReply FSceneViewport::OnControllerAnalogValueChanged( const FGeometry& MyGeometry, const FControllerEvent& ControllerEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); KeyStateMap.Add( ControllerEvent.GetEffectingButton(), true ); if( ViewportClient ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if (!ViewportClient->InputAxis(this, ControllerEvent.GetUserIndex(), ControllerEvent.GetEffectingButton(), ControllerEvent.GetEffectingButton() == EKeys::Gamepad_RightY ? -ControllerEvent.GetAnalogValue() : ControllerEvent.GetAnalogValue(), FApp::GetDeltaTime(), 1, true)) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
void FSceneViewport::OnFocusLost( const FFocusEvent& InFocusEvent ) { KeyStateMap.Empty(); if (ViewportClient != nullptr) { FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); ViewportClient->LostFocus( this ); TSharedPtr<SWidget> ViewportWidgetPin = ViewportWidget.Pin(); if( ViewportWidgetPin.IsValid() ) { for (int32 UserIndex = 0; UserIndex < SlateApplicationDefs::MaxUsers; ++UserIndex) { if (FSlateApplication::Get().GetUserFocusedWidget(UserIndex) == ViewportWidgetPin) { FSlateApplication::Get().ClearUserFocus(UserIndex); } } } } }
void FSceneViewport::OnKeyboardFocusLost( const FKeyboardFocusEvent& InKeyboardFocusEvent ) { KeyStateMap.Empty(); if( ViewportClient ) { FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); ViewportClient->LostFocus( this ); TSharedPtr<SWidget> ViewportWidgetPin = ViewportWidget.Pin(); if( ViewportWidgetPin.IsValid() ) { for( int32 UserIndex = 0; UserIndex < SlateApplicationDefs::MaxUsers; ++UserIndex ) { if( FSlateApplication::Get().GetJoystickCaptor(UserIndex) == ViewportWidgetPin ) { FSlateApplication::Get().ReleaseJoystickCapture( UserIndex ); } } } } }
FReply FSceneViewport::OnKeyDown( const FGeometry& InGeometry, const FKeyboardEvent& InKeyboardEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); FKey Key = InKeyboardEvent.GetKey(); KeyStateMap.Add( Key, true ); //@todo Slate Viewports: FWindowsViewport checks for Alt+Enter or F11 and toggles fullscreen. Unknown if fullscreen via this method will be needed for slate viewports. if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( !ViewportClient->InputKey( this, 0, Key, InKeyboardEvent.IsRepeat() ? IE_Repeat : IE_Pressed ) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnKeyUp( const FGeometry& InGeometry, const FKeyboardEvent& InKeyboardEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); FKey Key = InKeyboardEvent.GetKey(); KeyStateMap.Add( Key, false ); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( !ViewportClient->InputKey(this, 0, Key, IE_Released) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnAnalogValueChanged(const FGeometry& MyGeometry, const FAnalogInputEvent& InAnalogInputEvent) { // Start a new reply state CurrentReplyState = FReply::Handled(); FKey Key = InAnalogInputEvent.GetKey(); KeyStateMap.Add(Key, true); if (ViewportClient) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher(ViewportClient); if (!ViewportClient->InputAxis(this, InAnalogInputEvent.GetUserIndex(), Key, Key == EKeys::Gamepad_RightY ? -InAnalogInputEvent.GetAnalogValue() : InAnalogInputEvent.GetAnalogValue(), FApp::GetDeltaTime(), 1, Key.IsGamepadKey())) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnMouseMove( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); if( !InMouseEvent.GetCursorDelta().IsZero() ) { UpdateCachedMousePos( InGeometry, InMouseEvent ); UpdateCachedGeometry(InGeometry); const bool bViewportHasCapture = ViewportWidget.IsValid() && ViewportWidget.Pin()->HasMouseCapture(); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( bViewportHasCapture ) { ViewportClient->CapturedMouseMove( this, GetMouseX(), GetMouseY() ); } else { ViewportClient->MouseMove( this, GetMouseX(), GetMouseY() ); } if( bViewportHasCapture ) { // Accumulate delta changes to mouse movment. Depending on the sample frequency of a mouse we may get many per frame. //@todo Slate: In directinput, number of samples in x/y could be different... const FVector2D CursorDelta = InMouseEvent.GetCursorDelta(); MouseDelta.X += CursorDelta.X; ++NumMouseSamplesX; MouseDelta.Y -= CursorDelta.Y; ++NumMouseSamplesY; } } } return CurrentReplyState; }
FReply FSceneViewport::OnMouseWheel( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); UpdateCachedMousePos( InGeometry, InMouseEvent ); UpdateCachedGeometry(InGeometry); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); // The viewport client accepts two different keys depending on the direction of scroll. FKey const ViewportClientKey = InMouseEvent.GetWheelDelta() < 0 ? EKeys::MouseScrollDown : EKeys::MouseScrollUp; // Pressed and released should be sent ViewportClient->InputKey( this, 0, ViewportClientKey, IE_Pressed ); ViewportClient->InputKey( this, 0, ViewportClientKey, IE_Released ); } return CurrentReplyState; }
void FSceneViewport::ProcessInput( float DeltaTime ) { if( !ViewportClient ) { return; } // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); const bool bViewportHasCapture = ViewportWidget.IsValid() && ViewportWidget.Pin()->HasMouseCapture(); if (NumMouseSamplesX > 0 || NumMouseSamplesY > 0) { ViewportClient->InputAxis( this, 0, EKeys::MouseX, MouseDelta.X, DeltaTime, NumMouseSamplesX ); ViewportClient->InputAxis( this, 0, EKeys::MouseY, MouseDelta.Y, DeltaTime, NumMouseSamplesY ); } MouseDelta = FIntPoint::ZeroValue; NumMouseSamplesX = 0; NumMouseSamplesY = 0; }
FReply FSceneViewport::OnTouchGesture( const FGeometry& MyGeometry, const FPointerEvent& GestureEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); UpdateCachedMousePos( MyGeometry, GestureEvent ); UpdateCachedGeometry( MyGeometry ); if( ViewportClient ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); FSlateApplication::Get().SetKeyboardFocus(ViewportWidget.Pin()); if( !ViewportClient->InputGesture( this, GestureEvent.GetGestureType(), GestureEvent.GetGestureDelta() ) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnTouchEnded( const FGeometry& MyGeometry, const FPointerEvent& TouchEvent ) { // Start a new reply state CurrentReplyState = FReply::Handled(); UpdateCachedMousePos(MyGeometry, TouchEvent); UpdateCachedGeometry(MyGeometry); if( ViewportClient ) { // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); const FVector2D TouchPosition = MyGeometry.AbsoluteToLocal(TouchEvent.GetLastScreenSpacePosition()); if( !ViewportClient->InputTouch( this, TouchEvent.GetUserIndex(), TouchEvent.GetPointerIndex(), ETouchType::Ended, TouchPosition, FDateTime::Now(), TouchEvent.GetTouchpadIndex()) ) { CurrentReplyState = FReply::Unhandled(); } } return CurrentReplyState; }
FReply FSceneViewport::OnMouseButtonDown( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) { // Start a new reply state // Prevent throttling when interacting with the viewport so we can move around in it CurrentReplyState = FReply::Handled().PreventThrottling(); KeyStateMap.Add(InMouseEvent.GetEffectingButton(), true); UpdateModifierKeys( InMouseEvent ); UpdateCachedMousePos( InGeometry, InMouseEvent ); UpdateCachedGeometry(InGeometry); // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // If we're obtaining focus, we have to copy the modifier key states prior to processing this mouse button event, as this is the only point at which the mouse down // event is processed when focus initially changes and the modifier keys need to be in-place to detect any unique drag-like events. if ( !HasFocus() ) { FModifierKeysState KeysState = FSlateApplication::Get().GetModifierKeys(); ApplyModifierKeys( KeysState ); } const bool bAnyMenuWasVisible = FSlateApplication::Get().AnyMenusVisible(); // Process the mouse event if (!ViewportClient->InputKey(this, InMouseEvent.GetUserIndex(), InMouseEvent.GetEffectingButton(), IE_Pressed)) { CurrentReplyState = FReply::Unhandled(); } // a new menu was opened if there was previously not a menu visible but now there is const bool bNewMenuWasOpened = !bAnyMenuWasVisible && FSlateApplication::Get().AnyMenusVisible(); if (!ViewportClient->IgnoreInput() && !bNewMenuWasOpened && // We should not focus the viewport if a menu was opened as it would close the menu ( ViewportClient->CaptureMouseOnClick() == EMouseCaptureMode::CapturePermanently || ViewportClient->CaptureMouseOnClick() == EMouseCaptureMode::CaptureDuringMouseDown || ( ViewportClient->CaptureMouseOnClick() == EMouseCaptureMode::CaptureDuringRightMouseDown && InMouseEvent.GetEffectingButton() == EKeys::RightMouseButton ) ) ) { TSharedRef<SViewport> ViewportWidgetRef = ViewportWidget.Pin().ToSharedRef(); // Mouse down should focus viewport for user input CurrentReplyState.SetUserFocus(ViewportWidgetRef, EFocusCause::SetDirectly, true); UWorld* World = ViewportClient->GetWorld(); if (World && World->IsGameWorld() && World->GetFirstPlayerController()) { CurrentReplyState.CaptureMouse(ViewportWidgetRef); CurrentReplyState.LockMouseToWidget(ViewportWidgetRef); bool bShouldShowMouseCursor = World->GetFirstPlayerController()->ShouldShowMouseCursor(); if (ViewportClient->HideCursorDuringCapture() && bShouldShowMouseCursor) { bCursorHiddenDueToCapture = true; MousePosBeforeHiddenDueToCapture = FIntPoint( InMouseEvent.GetScreenSpacePosition().X, InMouseEvent.GetScreenSpacePosition().Y ); } if (bCursorHiddenDueToCapture || !bShouldShowMouseCursor) { CurrentReplyState.UseHighPrecisionMouseMovement(ViewportWidgetRef); } } else { CurrentReplyState.UseHighPrecisionMouseMovement(ViewportWidgetRef); } } } // Re-set prevent throttling here as it can get reset when inside of InputKey() CurrentReplyState.PreventThrottling(); return CurrentReplyState; }
FReply FSceneViewport::OnMouseButtonDown( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) { // Start a new reply state // Prevent throttling when interacting with the viewport so we can move around in it CurrentReplyState = FReply::Handled().PreventThrottling(); KeyStateMap.Add(InMouseEvent.GetEffectingButton(), true); UpdateModifierKeys( InMouseEvent ); UpdateCachedMousePos( InGeometry, InMouseEvent ); UpdateCachedGeometry(InGeometry); // Switch to the viewport clients world before processing input FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient ); if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue ) { // If we're obtaining focus, we have to copy the modifier key states prior to processing this mouse button event, as this is the only point at which the mouse down // event is processed when focus initially changes and the modifier keys need to be in-place to detect any unique drag-like events. if ( !HasFocus() ) { FModifierKeysState KeysState = FSlateApplication::Get().GetModifierKeys(); ApplyModifierKeys( KeysState ); } // Process the mouse event if( !ViewportClient->InputKey( this, 0, InMouseEvent.GetEffectingButton(), IE_Pressed ) ) { CurrentReplyState = FReply::Unhandled(); } if (ViewportClient->CaptureMouseOnClick() != EMouseCaptureMode::NoCapture && !ViewportClient->IgnoreInput()) { TSharedRef<SViewport> ViewportWidgetRef = ViewportWidget.Pin().ToSharedRef(); // Mouse down should focus viewport for keyboard input CurrentReplyState.SetKeyboardFocus(ViewportWidgetRef, EKeyboardFocusCause::Mouse); UWorld* World = ViewportClient->GetWorld(); if (World && World->IsGameWorld() && World->GetFirstPlayerController()) { CurrentReplyState.CaptureMouse(ViewportWidgetRef); CurrentReplyState.LockMouseToWidget(ViewportWidgetRef); bool bShouldShowMouseCursor = World->GetFirstPlayerController()->ShouldShowMouseCursor(); if (ViewportClient->HideCursorDuringCapture() && bShouldShowMouseCursor) { bCursorHiddenDueToCapture = true; } if (bCursorHiddenDueToCapture || !bShouldShowMouseCursor) { CurrentReplyState.UseHighPrecisionMouseMovement(ViewportWidgetRef); } } else { CurrentReplyState.UseHighPrecisionMouseMovement(ViewportWidgetRef); } } } // Re-set prevent throttling here as it can get reset when inside of InputKey() CurrentReplyState.PreventThrottling(); return CurrentReplyState; }