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, InMouseEvent.GetUserIndex(), InMouseEvent.GetEffectingButton(), IE_DoubleClick)) { CurrentReplyState = FReply::Unhandled(); } } 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, InMouseEvent.GetUserIndex(), ViewportClientKey, IE_Pressed); ViewportClient->InputKey(this, InMouseEvent.GetUserIndex(), ViewportClientKey, IE_Released); ViewportClient->InputAxis(this, InMouseEvent.GetUserIndex(), EKeys::MouseWheelAxis, InMouseEvent.GetWheelDelta(), FApp::GetDeltaTime()); } return CurrentReplyState; }
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::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; }
int32 UKismetInputLibrary::PointerEvent_GetUserIndex(const FPointerEvent& Input) { return Input.GetUserIndex(); }