One workaround is to set the position of the mouse every frame while the viewport is captured so as to prevent the mouse from getting near the edge of the screen. You could constantly set the mouse to be in the center of the screen (as below), or alternatively remember the cursor’s last position and keep it there while the mouse is captured by the viewport.
Adding the below code to your PlayerController’s Tick function should do the trick:
FViewport* viewPort = CastChecked<ULocalPlayer>(this->Player)->ViewportClient->Viewport;
if ( viewport->HasMouseCapture() ) // alternatively, could use viewport->HasFocus() based on what you are doing
{
FIntPoint sizeXY = viewport->GetSizeXY();
viewport->SetMouse( sizeXY.X/2, sizeXY.Y/2 );
}
Edit: When trying to implement the second method I described above (saving the mouse position and setting the saved position while the cursor is captured), I noticed that strangely, SetMouse has different behavior for PIE windows and standalone windows.
For standalone windows, everything works correctly, but when setting the saved position in editor windows, the result would be drastically offset.
Looking through the answerhub, it didn’t seem like there was a solution, but after a lot of debugging I found that multiplying the saved mouse coordinates by the viewport resolution’s Y/X ratio would give extremely good results (maybe not 100% perfect? or maybe it’s just rounding?)
If anyone else has the same issue, try out something like the below code:
if (viewport->HasMouseCapture())
{
viewport->SetMouse(m_lastMousePosition.X, m_lastMousePosition.Y);
}
else
{
// remember last mouse pos
FIntPoint lastMousePosition;
viewport->GetMousePos(lastMousePosition, true);
if (lastMousePosition.X >= 0 && lastMousePosition.Y >= 0)
{
// skip if mouse is outside window (when outside window, X and Y become -1)
float viewportRatio = 1.0f; // use 1.0 for standalone builds etc
if (viewport->IsPlayInEditorViewport())
{
FIntPoint screenResolutionViewport(GSystemResolution.ResX, GSystemResolution.ResY);
viewportRatio = (float)screenResolutionViewport.Y / (float)screenResolutionViewport.X;
}
m_lastMousePosition.X = (float)lastMousePosition.X * viewportRatio;
m_lastMousePosition.Y = (float)lastMousePosition.Y * viewportRatio;
}
}
Edit 2: I noticed that with the above code active, ejecting from the player character and moving environment data around with the mouse in PIE mode no longer functions because the mouse cursor will get stuck in one position when clicking on the viewport. I couldn’t find a way of checking if the editor is in “Possess” or “Eject” mode, so instead I temporarily resolved this by disabling the functionality when in PIE mode. Note that the original bug doesn’t seem to occur in PIE mode anyway, so this is a decent enough workaround, I guess.