I’m working on implementing dragging with a mouse. Here is the code that I am using to change the mouse cursor depending on the mouse button (in my PlayerController derived class):
What I find is that when I hold the LMB down, the cursor changes as expected. However when I release the mouse button, and keep the pointer still, the cursor doesn’t change. It only changes when I move it a pixel. I can see the debug message on the screen, so I 'm confident the code is being called. I have even tried moving the code into the PlayerTick method with exactly the same results.
Does anyone know how I can force the mouse cursor to update on screen?
I think I know why, though I don’t know how to fix it.
We only set a value in the PlayerController’s value structure without the aid of a function. That means that whatever is set can only be retrieved if
a) another signal will pump a new message into the game’s event queue and retrieve your value (hence the need for something to detect the new value and set a flag for the next round to react on this flag; or,
b) the game queue is not finished yet and somewhere, something in the bottom of the engine will pick up the new value.
After tracing the whole message queue (yea, about a day or so), I found that neither events are happening. Our derived classes are very low in the food chain and nothing picks up the value we’ve set unless, like you mentioned, we create an additional event like moving the mouse which will get the new cursor value.
The culprit is located in UGameViewportClient::GetCursor() which is called by FSceneViewport::OnCursorQuery();
the cursor value it gets is earlier that anything we set on the game level. It retrieves the last value set prior to raising the mouse button and never comes back unless another signal is sent.
I’ve also noticed that when we keep the mouse button down, FSceneViewport::OnCursorQuery() is fired repetitively although a single message for LMB::IE_Pressed is sent in your application. I think the change between the normal arrow and the hand is delayed the same way, but because it is fired repetitively, the change occurs only the second time around, at 1/60th of a second.
The solution is that @Epic should provide some method to call when we change the cursor so that it triggers some flag that asks to re-read the cursor again, instead of simply letting us set a value. There maybe is one, but it’s not clear in any documentation.
I had the same problem and found a hacky fix by simulating mouse movement.
I added a variable to my custom player controller:
EMouseCursor::Type DesiredMouseCursor;
And added this code to the PlayerTick function:
// UE4 Hack: The cursor change doesn't happen until the mouse is moved
// As a workaround, simulate some mouse movement.
// Make sure we only do this once per frame, otherwise we can create lots of
// unnecessary pointer events which are more likely to cause noticeable mouse jitter.
if (CurrentMouseCursor != DesiredMouseCursor)
{
CurrentMouseCursor = DesiredMouseCursor;
auto& App = FSlateApplication::Get();
FVector2D CursorPos = App.GetCursorPos();
App.SetCursorPos(CursorPos + FVector2D(0, 1));
App.OnMouseMove();
App.SetCursorPos(CursorPos);
App.OnMouseMove();
}
Then to change the cursor I assign to DesiredMouseCursor instead of CurrentMouseCursor.
This is a dirty hack and has only been tested on Windows 7, but it might be useful to someone until there’s an actual fix. From what I’ve read it looks like Linux requires a click rather than a move (and faking clicks could obviously cause some problems).
Unfortunately this doesn’t work here on 4.8 preview, Windows 8.
Hiding the cursor through DesiredMouseCursor will still require a click to get mouse inputs, and Slate hover events will still require a click after showing the cursor. Same behavior as before.
FYI this was acknowledged to be a UE bug and is in the known bugs list for 4.8P4 - hopefully we get answers soon.
For people still wondering about this and getting some error when using FSlateApplication, and are working in newer versions of unreal (I’m working in UE5 EA), you need to go in the .Build.cs file and uncomment or add this:
PrivateDependencyModuleNames.AddRange(new string[] { “Slate”, “SlateCore” });
firstly, thanks all of you, Same thing still occurs in UE5.0
I’ve struggled to find this post and tried some solution.
Issue
Trying to find a way to set a mouse cursor of a controller,
but the cursor does not change even when the CurrentMouseCursor’s value is changed correctly.(Need a click or some event to make the cursor change in the viewport…)
What I found
There are some other post saying about this(pls refer to Reference)
Happens to find that UWidgetBlueprintLibrary has a function does the exactly same thing.(Which can be called from BP&&Cpp without additional dependency)