How to fix mouse behaviour...is UE bugged?

What I want is this:

  • The mouse cursor is locked to the game window.
  • When right mouse button is held down:
    • The mouse cursor is hidden
    • Mouse movement affects camera angle.
  • When right mouse button is not held down:
    • The mouse cursor is shown.
    • Mouse movement affects cursor position.

Very normal really.

What I have is this…

DefaultInput.ini:

bCaptureMouseOnLaunch=False
DefaultViewportMouseCaptureMode=CaptureDuringRightMouseDown
DefaultViewportMouseLockMode=LockAlways

What happens is that when the game starts, the mouse cursor is shown, but not locked to screen. If I move it off the game screen and back again, then it becomes hidden within the game window. If I press the right mouse button while the cursor is visible, it is hidden, but not shown again when I release the right mouse button.

I changed DefaultInput.ini to have:

DefaultViewportMouseLockMode=LockInFullscreen

No difference.

I changed DefaultInput.ini to have:

DefaultViewportMouseLockMode=LockOnCapture

No difference.

I am a bit frustrated because earlier with, as far as I can remember, identical settings the cursor was initially locked to the game screen, just not after I pressed the right mouse button.

I have tried the code below, but it made no difference.

CustomPawn.cpp:

void CustomPawn::BeginPlay()
{
    APlayerController *controller;

    Super::BeginPlay();

    controller = Cast<APlayerController>(GetController());

    if (nullptr != controller)
    {
        FInputModeGameAndUI input_mode;
  
        input_mode.SetLockMouseToViewportBehavior(EMouseLockMode::LockAlways);
        input_mode.SetHideCursorDuringCapture(true);
        controller->SetInputMode(input_mode);
    }
}

How do I get the mouse input to behave as I wish?

I have checked the code in Engine/Private/Slate/SceneViewport.cpp and can see what it is meant to be doing. The code all looks sensible at a brief glance. It just is not doing it.

This is fairly horrible code and probably a lot more than I need, but…

I registered call backs for RMB press and release and implemented them as follows…

Press:

    UGameViewportClient   *viewport_client = GetWorld()->GetGameViewport();
    TSharedPtr<SViewport>  viewport_widget = viewport_client->GetGameViewportWidget();
    ULocalPlayer          *player          = _GetLocalPlayer();

    if (!viewport_widget.IsValid())
    {
        UE_LOG(LogTemp, Warning, TEXT("Invalid widget!"));
    }
    else if (nullptr == player)
    {
        UE_LOG(LogTemp, Warning, TEXT("Invalid player!"));
    }
    else
    {
        TSharedRef<SViewport>  widget_ref = viewport_widget.ToSharedRef();
        FReply                &slate      = player->GetSlateOperations();

        Cast<APlayerController>(GetController())->SetShowMouseCursor(false);
        FSlateApplication::Get().SetAllUserFocusToGameViewport(EFocusCause::Cleared);
        FSlateApplication::Get().OnCursorSet();
        slate.UseHighPrecisionMouseMovement(widget_ref);
        slate.LockMouseToWidget(widget_ref);
        viewport_client->SetMouseLockMode(EMouseLockMode::LockAlways);
        viewport_client->SetIgnoreInput(false);
        viewport_client->SetMouseCaptureMode(EMouseCaptureMode::CapturePermanently);
    }

Release:

    UGameViewportClient   *viewport_client = GetWorld()->GetGameViewport();
    TSharedPtr<SViewport>  viewport_widget = viewport_client->GetGameViewportWidget();
    ULocalPlayer          *player          = _GetLocalPlayer();

    if (!viewport_widget.IsValid())
    {
        UE_LOG(LogTemp, Warning, TEXT("Invalid widget!"));
    }
    else if (nullptr == player)
    {
        UE_LOG(LogTemp, Warning, TEXT("Invalid player!"));
    }
    else
    {
        TSharedRef<SViewport>  widget_ref = viewport_widget.ToSharedRef();
        FReply                &slate      = player->GetSlateOperations();

        Cast<APlayerController>(GetController())->SetShowMouseCursor(true);
        FSlateApplication::Get().SetAllUserFocusToGameViewport(EFocusCause::Cleared);
        slate.LockMouseToWidget(widget_ref);
        slate.ReleaseMouseCapture();
        viewport_client->SetMouseLockMode(EMouseLockMode::LockOnCapture);
        viewport_client->SetMouseCaptureMode(EMouseCaptureMode::CaptureDuringRightMouseDown);
    }

Now I need to spend a few hours removing lines of code to see which ones are redundant.

The mouse is still not restricted to the viewport though.

1 Like