Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Set mouse position?

Discussion in 'Scripting' started by SparrowGS, Sep 11, 2017.

  1. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Hey, i've looked through the forums and google and all i find is 2010-ish answers saying it cant be done.

    so, how do we do it?
    Unity must have given a solution to this by now or at least a work around, i saw someone talking about getting into to OS itself, but that's way to far imo.

    why can't i find it, anyone?
     
  2. Scabbage

    Scabbage

    Joined:
    Dec 11, 2014
    Posts:
    268
    Looks like this is the top result when googling for "set cursor position" now.

    You have 2 options:
    - Use a software cursor; set the position using the mouse delta and you can move it wherever you want.
    - Use Mouse.WarpCursorPosition from the new input system:
    Code (CSharp):
    1. Mouse.current.WarpCursorPosition(Vector2 mousePosition);
     
    Last edited: Aug 21, 2023
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,400
    Unity uses Mono, not .NET, on all platforms including Windows, and Unity's version of Mono has not changed since 2010. So that won't work. (Well, except Windows Store uses .NET, not sure anyone would target just that platform though.) If you use a software cursor, you can do whatever you want with it.

    --Eric
     
    Miscellaneous and Ryiah like this.
  4. Scabbage

    Scabbage

    Joined:
    Dec 11, 2014
    Posts:
    268
    @Eric5h5 Hence why I said only if he's targeting windows exclusively ;p

    It's bodgy though and I see no reason to be controlling the cursor position anyway.
     
  5. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Oh don't get me wrong, i hate those things too, what I'm after is for an RTS camera, when you right click and drag to rotate i want the cursor to go invisible and then pop back up where it was.

    currently i'm making it invisible and on MouseButtonUp i do
    LockMode = Locked;
    LockMode = None;

    that pops it back to the center, but i don't like it at all.
    is there really no way to do this?
     
  6. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    make the cursor invisible.
    set an image to follow the cursor position.
    hide/show that image instead.
     
    BecubeCo likes this.
  7. Scabbage

    Scabbage

    Joined:
    Dec 11, 2014
    Posts:
    268
    Last edited: Feb 25, 2021
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,400
    Windows and Windows Store are two quite different platforms. "Targetting Windows" isn't covered by Windows Store. That has specific requirements/limitations. Unity Windows apps don't use .NET.

    Use a software cursor?

    --Eric
     
    Ryiah likes this.
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Here, if you're looking for Windows Standalone:
    Code (csharp):
    1.  
    2. #if UNITY_STANDALONE_WIN
    3. public class Win32
    4. {
    5.     [DllImport("User32.Dll")]
    6.     public static extern long SetCursorPos(int x, int y);
    7.  
    8.     [DllImport("user32.dll")]
    9.     [return: MarshalAs(UnmanagedType.Bool)]
    10.     public static extern bool GetCursorPos(out POINT lpPoint);
    11.  
    12.     [StructLayout(LayoutKind.Sequential)]
    13.     public struct POINT
    14.     {
    15.         public int X;
    16.         public int Y;
    17.  
    18.         public POINT(int x, int y)
    19.         {
    20.             this.X = x;
    21.             this.Y = y;
    22.         }
    23.     }
    24. }
    25. // You can use like this:
    26. #if UNITY_STANDALONE_WIN
    27.                 Win32.POINT pt = new Win32.POINT();
    28.                 Win32.GetCursorPos(out pt);
    29.                 pos.x = pt.X;
    30.                 pos.y = pt.Y;
    31. #endif
    32. // and / or like this:
    33. #if UNITY_STANDALONE_WIN
    34.                 Win32.SetCursorPos((int)pos.x, (int)pos.y);
    35. #endif
    36.  
    Hopefully I copied the correct code for you. I once found the proper code for Mac (I think?) But sadly I could not ever find it, again. Not setup properly for Unity in a way that I could understand, sadly..

    If anyone knows for Mac (or linux?) I'd love to hear about it :) :)

    To the OP: I actually use this for exactly the reason you described. I love it - I think it's a great addition. I also lock and hide the cursor, but didn't include that code, as it's just regular Unity stuff..
     
  10. zhuk1011

    zhuk1011

    Joined:
    Jan 28, 2016
    Posts:
    3
    Awesome!
     
  11. remosloot

    remosloot

    Joined:
    Aug 14, 2020
    Posts:
    1
    what am i doing wrong?


    upload_2020-9-15_15-31-24.png
     
  12. Xefier

    Xefier

    Joined:
    Dec 22, 2012
    Posts:
    80
    The code below line 32 is supposed to be inserted into valid code like within a method in your script that uses this Win32 class. He just provided those snippets of code at the bottom as a few usage examples, they don't belong below the class definition, that's not valid code.
     
  13. rboerdijk

    rboerdijk

    Joined:
    Aug 4, 2018
    Posts:
    96
    Exactly my usecase, homeworld-style move-mode, where you can move your target-x/y-line with during a "move mode", during this "move mode" you can still RMB-hold to orbit the screen around the targetted ship which then hides the mouse (and keeps the move-line locked in the original place while you are orbitting). On unpressing RMB then the mouse should jump back to the move-location (wherever it is now) so the movement-line stays "in place".
    Might sound like an obscure case, but this is how it actually works in a released game, and it feels pretty good (much better then the mousecursor ending up "wherever" on the screen and your move-line popping wherever the mouse now happens to be the moment you let go of RMB).

    Anyway, with the new input system (install via packagemanager) you can use Mouse.current.WarpCursorPosition

    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Mouse.html:
    On desktop platforms (Windows, Mac, Linux, and UWP), you can move the mouse cursor via code. Note that this moves the system's actual mouse cursor, not just Unity's internally-stored mouse position. This means that the user sees the cursor jumping to a different position, which is generally considered to be bad UX practice. It's advisable to only do this if the cursor is hidden (see the Cursor API documentation for more information).
     
    Last edited: Nov 15, 2020
  14. mariusgeorge

    mariusgeorge

    Joined:
    Jan 29, 2016
    Posts:
    18
    For those wondering why it should ever be needed...

    When you Lock the cursor, Unity will center it. This centered Lock cursor will still interfere with UI elements, which is hyper annoying when you are trying to control the UI with a gamepad.

    The only solution I ever found was to force the cursor to position (0,0) and to hide it.

    Unity has no proper solution for this, which kinda sucks.
     
  15. rboerdijk

    rboerdijk

    Joined:
    Aug 4, 2018
    Posts:
    96
    No proper solution indeed, but you can get it mostly working like this:

    Code (CSharp):
    1.         Vector3 mousepos = Camera.main.WorldToScreenPoint(pos + MoveTarget);
    2.         // 'feature' workaround: https://forum.unity.com/threads/inputsystem-reporting-wrong-mouse-position-after-warpcursorposition.929019/
    3.         //InputSystem.QueueDeltaStateEvent(Mouse.current.position,  (Vector2)mousepos);   // required 8 bytes, not 12!
    4.         InputState.Change(Mouse.current.position, (Vector2)mousepos);
    5. #if !UNITY_EDITOR
    6.             // bug workaround : https://forum.unity.com/threads/mouse-y-position-inverted-in-build-using-mouse-current-warpcursorposition.682627/#post-5387577
    7.             mousepos.Set(mousepos.x, Screen.height - mousepos.y, mousepos.z);
    8. #endif
    9.         Mouse.current.WarpCursorPosition(mousepos);
    What is especially sad is that the mouse-inverted bug was reported almost 2 years ago... Also I think there's still another bug when you desktop resolution is smaller than the fullscreen resolution...
    If anyone finds another workaround for that (or better: a decent solution) please also share :)
     
  16. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    314
    Version for Mac:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Runtime.InteropServices;
    3. using System;
    4.  
    5. public class Mouse : MonoBehaviour
    6. {
    7.     // Mac calculates global screen coordinates from top left corner of screen
    8.     #if (UNITY_EDITOR && UNITY_EDITOR_OSX) || (!UNITY_EDITOR && UNITY_STANDALONE_OSX)
    9.  
    10.         [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")]
    11.         public static extern int CGWarpMouseCursorPosition(CGPoint point);
    12.  
    13.         [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")]
    14.         public static extern IntPtr CGEventCreate(IntPtr source);
    15.  
    16.         [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")]
    17.         public static extern CGPoint CGEventGetLocation(IntPtr evt);
    18.  
    19.         [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")]
    20.         public static extern void CFRelease(IntPtr cf);
    21.  
    22.         public struct CGPoint
    23.         {
    24.             public double X { get; set; }
    25.             public double Y { get; set; }
    26.         }
    27.  
    28.         Vector2 GetCursorPos ()
    29.         {
    30.             IntPtr ptr = CGEventCreate(IntPtr.Zero);
    31.             CGPoint loc = CGEventGetLocation(ptr);
    32.             CFRelease(ptr);
    33.             return new Vector2((float)loc.X, (float)loc.Y);
    34.         }
    35.  
    36.         void SetCursorPos(float x, float y)
    37.         {
    38.             CGPoint point = new CGPoint() {X = x, Y = y};
    39.             CGWarpMouseCursorPosition(point);
    40.         }
    41.  
    42.     #endif
    43.  
    44.     void Update()
    45.     {
    46.         if (Time.time < 12.0f) //test: mouse circular movement through 12 seconds
    47.         {
    48.             SetCursorPos((Mathf.Sin(Time.time) * 0.5f + 0.5f) * 500.0f, (Mathf.Cos(Time.time) * 0.5f + 0.5f) * 500.0f);
    49.             Debug.Log(GetCursorPos());
    50.         }
    51.     }
    52. }
     
    rboerdijk likes this.
  17. DarknessBlade

    DarknessBlade

    Joined:
    Apr 21, 2014
    Posts:
    9
  18. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    The positives to using a software cursor is that you won't have to bother with making it work on the different platforms you're targetting because you're in control of how it moves.

    The downside to using a software cursor is that it will be affected by your game's fps drops while the hardware cursor is not.

    Finally: there is a great solution to this problem IF you use Unity's new input system.
    I haven't tested it on different platforms but I assume it works just fine.
    Code (CSharp):
    1. Mouse.current.WarpCursorPosition(Vector2 mousePosition);
     
    Last edited: Apr 7, 2022