How do I change the hardware cursor?

I know how to use UnityGUI and DrawTexture to draw a cursor at Input.mousePosition, but it lags behind the real cursor too much when the framerate gets low. How can I change the hardware cursor (the one that is rendered independently of the memory allocated to the program)? On windows I would use the System.Windows.Input.Mouse.SetCursor() method, but I don't think this works in Unity (it uses Windows libraries).

5 Answers

5

In case you landed here trying to change the cursor to another standard/native cursor, so not a custom texture but one available in the OS by default, here is what I ended up doing (Windows only!):

  public enum WindowsCursor
    {
        StandardArrowAndSmallHourglass = 32650,
        StandardArrow = 32512,
        Crosshair = 32515,
        Hand = 32649,
        ArrowAndQuestionMark = 32651,
        IBeam = 32513,
        //Icon = 32641, // Obsolete for applications marked version 4.0 or later. 
        SlashedCircle = 32648,
        //Size = 32640,  // Obsolete for applications marked version 4.0 or later. Use FourPointedArrowPointingNorthSouthEastAndWest
        FourPointedArrowPointingNorthSouthEastAndWest = 32646,
        DoublePointedArrowPointingNortheastAndSouthwest = 32643,
        DoublePointedArrowPointingNorthAndSouth = 32645,
        DoublePointedArrowPointingNorthwestAndSoutheast = 32642,
        DoublePointedArrowPointingWestAndEast = 32644,
        VerticalArrow = 32516,
        Hourglass = 32514
    }

    private static void ChangeCursor(WindowsCursor cursor){
        SetCursor(LoadCursor(IntPtr.Zero , (int)cursor));
    }

    [DllImport("user32.dll", EntryPoint = "SetCursor")]
    public static extern IntPtr SetCursor(IntPtr hCursor);

    [DllImport("user32.dll", EntryPoint = "LoadCursor")]
    public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

At first I was like "Wtf, 9 year old question" but this is pretty useful

You can’t change the hardware cursor in Unity.

Edit: in Unity 3, that is. You can in Unity 4.

This is true. However, there may be more options, perhaps within the Mono framework.

You can use Cursor.SetCursor(). See my answer below and the documentation [here][1]. [1]: http://docs.unity3d.com/ScriptReference/Cursor.SetCursor.html

If its for a Windows build you can try using user32.dll:

`

[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr SetCursor(IntPtr  hCursor);

[DllImport("user32.dll")]
public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

[DllImport("user32.dll")]
public static extern IntPtr LoadImage(
    IntPtr hInstance, 
    string lpImageName,
    uint uType,
    int cxDesired,
    int cyDesired,
    uint fuLoad
);

`

And write some methods that you can call from your scripts:

`

public static void changeCursorToHand(){
    SetCursor(LoadCursor(IntPtr.Zero ,32649));
}

public static void changeCursorToArrow(){
    SetCursor(LoadCursor(IntPtr.Zero ,32512));
}

`

This looks valid... But how do we do platform-based compile-time instructions? I remember a few weeks ago hearing that Unity 3 would have the ability for it. $compilerinstructions didn't work in the last C# implementation Unity used, and I'm not sure if that's been fixed yet. Anyone know a mac solution, too?

http://unity3d.com/support/documentation/Manual/Platform%20Dependent%20Compilation.html - Check this link for platform dependent compilation. I don't know of a mac solution, it's probably something similar, but using the equivalent to user32.dll

@SenhordetodooMal do you know if there is an alternative to your great example for unity free version? Apparently DllImport is a pro only feature :/

I know this is an old post but still the problem persists and yours is I think the only solution that works without any external 3rd party dlls. The problem is that with my current version of Unity (3.5.5) the cursor changes back to the original whenever I move the mouse. Am I doing something wrong? Do you know if unity is the problem and if so any workarounds. Thanks a lot!

A good "workaround" is to use Unity 4, which has native support for hardware cursors.

Though this question is old, perhaps this answer will help someone else.

The simplest way to do this is to have a Texture2D replace the default OS cursor. This is not a Pro-Only feature and is not limited to Windows only. This is the code I used:

	public Texture2D customCursor;
	private CursorMode cursorMode;
	private Vector2 hotSpot;


	// Use this for initialization
	void Start () {

		//change the cursor texture
		cursorMode = CursorMode.ForceSoftware;
		hotSpot = new Vector2 (0, 0);
		Cursor.SetCursor (customCursor, hotSpot, cursorMode);
    }

Please be aware that when you are testing this, you will have to BUILD AND RUN your project to see it work. It will not change the cursor if you just press the play button in Unity.

There is more documentation available here if you want to see about having the cursor change as you mouse over other objects.

If the cursor is lagging, the rest of your game must be, too (that, or your mouse cursor code is inefficient - maybe you should post it here). The only way I've discovered of drawing a cursor is via UnityGUI (of course there are more inefficient ways then UnityGUI, but none more efficient, as far as I can tell).

The game runs at ~40fps at full graphics, and the GUI code uses <6%, according to the profiler. It's just a little bit of lag, but that lag gets really annoying. It's an MMO, and as the number of users increases the lag does, too, which makes it even worse.