Why is there no way to hide the mouse cursor when entering Play Mode?

This has frustrated me since moving from 2019 LTS to 2021 LTS. I figured I’d eventually just get used to the new way things work, but it’s been about a year, and I still deal with this annoyance every day.

Previously, under 2019.X versions of Unity, hiding the mouse cursor worked fine when entering play mode. You’d do something like this:

    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

Enter play mode, the cursor goes away, and you start playing.

But started in Unity 2020, and in all versions since then, this code no longer works as-is. Instead, you first need to click somewhere into the Game view to get the mouse cursor to go away. Every single time I enter play mode, I need to click the Game view.

Making this even more annoying is that until you click the game view, the mouse cursor’s hovering all over the Editor, and if you’re not careful, your first click might land on the “X” to close Unity, the Play button (so you cancel Play mode immediately) or some other part of the Unity UI that you had no intention of clicking.

I’d be happy with some kludge to hiding the cursor, if anyone knows of a way, but so far I’m unaware of one. I’m really tired of needing to perform this extra click every time I enter play mode.

FWIW, I initially reported this as a regression bug, but Unity responded it’s intentional, and will not be fixed.

Can we please have some way to hide the cursor when entering Play mode?

3 Likes

I have encountered this stupid issue as well

Got the same response from the Unity team. I wrote a script that fixes this issue (It uses DllImport stuff) but I will not publish it publicly so that Unity team doesn’t “fix” it and ruin our experience again. Anyone who struggles with the same issue, PM me and I will send you the script as soon as I can

1 Like

I’m finding that the cursor doesn’t stay locked in multi-monitor setups even in player builds. Does anyone know of a better hack that doesn’t use external DLL function calls?

// Don’t ever use this code. This is for demonstration purposes only.

using System.Drawing;
using System.Runtime.InteropServices;
using UnityEngine;

public class CursorHack : MonoBehaviour
{
    [DllImport("user32.dll")]
    static extern bool SetCursorPos(int X, int Y);

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public static implicit operator Point(POINT point)
        {
            return new Point(point.X, point.Y);
        }
    }

    void LateUpdate()
    {
        if (Cursor.lockState == CursorLockMode.Locked)
            SetCursorPos(Screen.width / 2, Screen.height / 2);
    }
}

That sounds like a bug. Can you report it?

1 Like

Until Unity does something about this, here is a solution. Obviously you can move out the UnityEditor portions into an editor script and hang onto the playModeStateChanged event if you want.

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class TestComponent : MonoBehaviour
{
    private void Awake()
    {
#if UNITY_EDITOR
        var gameWindow = EditorWindow
            .GetWindow(typeof(EditorWindow).Assembly.GetType("UnityEditor.GameView"));
        gameWindow.Focus();
        gameWindow.SendEvent(new Event
        {
            button = 0,
            clickCount = 1,
            type = EventType.MouseDown,
            mousePosition = gameWindow.rootVisualElement.contentRect.center
        });
#endif
     
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false; 
    }
}

Here is the same with some extras:
https://github.com/LurkingNinja/com.lurking-ninja.game-utils/blob/main/Editor/GameViewExtensions.cs

Tools/Lurking Ninja/Forced GameView focus checkbox menu point turning the service on and off. Also the GameView doesn’t force focus if Play Unfocused is selected.
You still need to add the cursor lock and visibility handling in an Awake method as normal.

3 Likes

It’s nice to see a workaround for this that doesn’t require some external DLL imports. Thanks for sharing. This seems to do the trick for me.

Another little trick you can use here, to avoid needing to have this component in every scene, is to tie into EditorApplication.playModeStateChanged. This causes the script to be loaded once when Unity launches, and it triggers the game view focus every time you enter play mode. Here’s your code wrapped in that approach. Now you can just drop this script into any project, and it works without adding a component to anything in the scene:

using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class AutoFocusGameViewOnPlay
{
    // Static constructor that gets called when unity fires up.
    static AutoFocusGameViewOnPlay()
    {
        EditorApplication.playModeStateChanged += (PlayModeStateChange state) =>
        {
            // If we're about to run the scene...
            if (state == PlayModeStateChange.EnteredPlayMode)
            {
                var gameWindow = EditorWindow.GetWindow(typeof(EditorWindow).Assembly.GetType("UnityEditor.GameView"));
                gameWindow.Focus();
                gameWindow.SendEvent(new Event
                {
                    button = 0,
                    clickCount = 1,
                    type = EventType.MouseDown,
                    mousePosition = gameWindow.rootVisualElement.contentRect.center
                });

            }
        };
    }
}
1 Like

Yeah, this is what I did in my util-package among other small things like checking if unfocused selected.
https://github.com/LurkingNinja/com.lurking-ninja.game-utils/blob/main/Editor/GameViewExtensions.cs

1 Like

Note that static constructors in Unity are called in seemingly random fashion (I guess each recompilation does a call). Better use [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]

It is not really relevant, even if what you describe is true, these are Editor scripts with InitializeOnLoad attribute, which means the static constructor runs upon project load and upon domain reload. Doesn’t matter when, it should happen before the user can hit the play button, nothing else matters.

1 Like

It’s a regression, and one you should both be aware of (and now are) and able to internally call for it to be fixed.

Please do get it fixed!

As per forum rules , we do not take posts on the forum as bug reports. Here are some guidelines for reporting bugs: https://unity.com/releases/editor/qa/bug-reporting

And no, I am not “now aware” of the bug. Yes, there’s a forum post complaining about it not working but there isn’t nearly enough information in that forum post to investigate and fix it. Hence asking for a bug report, so it could be processed by QA: missing details filled out, reproduced, duplicate discovery done, added to the issue tracker, when it gets fixed actually verified against the same project that was submitted to confirm that it will fix the issue for the reporter.

Keep in mind that folks that post on the forum like me do it because we want to help but it is not our job to do so and we cannot spend significant amount of time dealing with stuff reported here. We have dedicated team that looks at bug reports and tries to reproduce them all day long: but they only look at stuff that comes through the bug reporter (rather than forums).

For everyone else reading, if you do end up reporting a bug, if you give me a bug number I can look at its status and tell you about it. I can also go bug the relevant team if you’re not getting traction to see where it lies in their priority list.

Anyway, let’s stick to the topic at hand: mouse cursor hiding/locking.

That’s not good enough.

It doesn’t matter what your processes are in your company and organisation.

It only matters that this is broken, and needs to be fixed, and that your company and your organisation have caused it to be broken.

If your processes don’t permit, nor encourage staff to get things fixed, that’s on you, your bosses, the management and the organisation within the company you work. It should never be placed upon users that discover these breakages. Which reminds that this should have been discovered and prevented by the organisation of your company and its quality control.

Please just get it fixed. Internally, since that’s where this was broken.

1 Like

All big software companies require bug reports for anything issue to be rectified.

If you think that’s not good enough, go make your own software company that doesn’t take bug reports. See how that pans out for you.

Otherwise stop disrupting every thread and harassing staff every time this comes up. You’re making the forums worse and worse and contribute nothing of use.

5 Likes

Creating a reproduction project with associated video of the behavior, as seen with multiple monitors present, is on my list today. I’ll reply back with a report id.

4 Likes

@Tautvydas-Zilys In a separate project I can confirm the mouse constrain and lock behavior works as expected in builds. This was totally user error on my part and I messed up.

Thank you for the quick response here in the forums!

2 Likes