There needs to be mouse cursor freezing functionality

If you ever bShowMouseCursor in your PlayerController, from there on the mouse cursor is locked to the viewport which is fine, but that means if you use it as an axis, the player will stop rotating once you reach screen edges (even if it wasnt locked, it will stop rotating once you reach monitor edges)
What other games do in this situation is to, as fast as possible, in the windows message pump, reset the location of the mouse cursor to the position it had when you first froze it. This way you can flail it all you want and it will still never reach the edges.

I’ve tried doing this in a custom PlayerController, like so:

header file:

#pragma once

#include "GameFramework/PlayerController.h"
#include "MousePlayerController.generated.h"

UCLASS()
class AMousePlayerController : public APlayerController
{
	GENERATED_UCLASS_BODY()

public:
	void EnableMouseLock();
	void DisableMouseLock();

	void PlayerTick(float DeltaTime) override;

private:
	bool MouseLockEngaged;
	FVector2D LockedMousePosition;
};

C++ file

#include "MousePlayerController.h"

//////////////////////////////////////////////////////////////////////////

AMousePlayerController::AMousePlayerController(const class FObjectInitializer& PCIP)
	: Super(PCIP),MouseLockEngaged(false),LockedMousePosition(ForceInitToZero)
{
	bShowMouseCursor = true;
	DefaultMouseCursor = EMouseCursor::Default;
}

void AMousePlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);

	if (MouseLockEngaged)
		GEngine->GameViewport->Viewport->SetMouse(LockedMousePosition.X,LockedMousePosition.Y);
}

void AMousePlayerController::EnableMouseLock()
{
	MouseLockEngaged = this->GetMousePosition(LockedMousePosition.X,LockedMousePosition.Y);
}

void AMousePlayerController::DisableMouseLock()
{
	MouseLockEngaged = false;
	LockedMousePosition = FVector2D::ZeroVector;
}

And this works “alright”, except that the Game code tick rate isn’t high enough to prevent the mouse cursor from jittering all over the place (it can get away by like 50px away from the lock center, depending on speed).

So I’m requesting a freeze functionality somewhere deeper in the core that won’t be tick rate dependent.
This is present in most ‘frameworks’, even in SDL, so why wouldn’t you include it in a game engine ? Also, how does infinite flailing work when the mouse cursor is always hidden ? Maybe the same thing can be used explicitly when the mouse cursor is shown.

I think you want the input mouse delta instead of the mouse position. I haven’t done anything like it in ue4, but usually if the mouse is hidden you want to get the change of input of the mouse instead of the position of a hidden cursor (which is bound in this case).

I do not hide my mouse cursor when i am holding to pan/rotate.

Hardware cursor is paramount for good responsiveness at 30fps.
Lets say you were making a RTS, and you want to click-and-drag to rotate a structure after placing it
You want the cursor to stay on the structure as you clicked it (dont want to hide it) so good-enough freezing of the cursor is needed. I guess a TERRIBLE hack would be to keep using hardware cursor always EXCEPT when frozen, which is when i could render a UMG element of the fake cursor at the frozen position, then hide it when unfreezing.

I don’t really understand what you are trying to accomplish from what you wrote. What is the action you want to happen when you enable mouse lock? You can always overcome any limit of a viewport if you make your own “mouse” that acts as a cursor and make it driven by the delta change of the mouse input.

If that is the case, keep showing the hardware cursor but make the calculations on a “software” cursor that is invisible, it would read the values of any delta beyond a viewport while the hardware cursor is on the edge.

You cannot. If bShowMouseCursor is true on init of the PlayerController, mouse axes no longer respond when you reach screen edges.
Also, the hardware cursor moves if your mouse moves. You can’t stop that.

There should be some way to override and basically “eat” the input. If you want the cursor to stay in the same place when you are doing that action. Im assuming you want something along the lines of what the editor does when you right click and rotate but doing that to an object and keeping the cursor visable.

I think the terrible hack wouldn’t be so terrible :stuck_out_tongue:

Keep in mind in practice your code is not application that uses library (as you compared UE4 to SDL) but i’s a extension of engine, it’s a one of over 400 modules that engine already has, it allows to alter a lot of things in engine without modifying engine itself and by simply extending existing classes, you already doing that with PlayerController or GameMode. Input processing as well as window state procesing comes from Viewport classes, you can alter how they work by creating your own UGameViewportClient class and set it as default UGameViewportClass, there you can override focus event classes

As well as Mouse entering and leaving window:

and use those event to have behavior as you like :slight_smile: Explore the whole class:

Hi, i know im a little late to this party but I was messing with this kind of issue but i was trying to capture mouse over events in my FPS game and wanted the Cursor to stay in the center of the Viewport so where the user looks the mouse points for mouse over event to fire.

I came up with using the mouse input event to capture and change the cursor position to the centre.

void APlayerController::AddControllerYawInput(float Val)
{
	auto pawn = GetPawn();
	if (pawn)
	{
		pawn->AddControllerYawInput(Val);	
                SetMousePosition();		
	}
}

void APlayerController::SetMousePosition()
{
	FViewport* Viewport = CastChecked<ULocalPlayer>(this->Player)->ViewportClient->Viewport;
	auto viewportSize = Viewport->GetSizeXY();
	
	Viewport->SetMouse((viewportSize.X * 0.5f), (viewportSize.Y * 0.5f));
}

This seems to work well for now but am yet to really stress test it and i cant help to feel there is a better way.

but maybe this will help some one :slight_smile: