Search Unity

Custom Cursor - How can I simulate mouse clicks?

Discussion in 'UGUI & TextMesh Pro' started by hubecube_, Sep 15, 2014.

  1. hubecube_

    hubecube_

    Joined:
    Aug 26, 2012
    Posts:
    18
    My mouse cursor is locked. It is hidden. I use a Rect Transform with a sprite and move it using GetAxis() for Mouse X and Mouse Y input data.

    I am interacting with my world objects by raycasting and I'd like to interact with the new Unity GUI as well. If I cast a ray to the UI layer how do I simulate a mouse click event to the object that was hit by the ray? More importantly how would I simulate the hover?

    I'm trying to avoid writing a GUI interaction class and instead finding a way to tell Unity "hey, the mouse is locked, so lets pretend its at (x,y,z) and continue all your mouse processing as usual from there".
     
  2. hubecube_

    hubecube_

    Joined:
    Aug 26, 2012
    Posts:
    18
    Any ideas?
     
  3. Scorr

    Scorr

    Joined:
    Jul 2, 2013
    Posts:
    73
    I think you could just change the mouse cursor sprite, or hide the mouse cursor and draw a sprite in its place. That way you don't have to use any workarounds.
     
  4. hubecube_

    hubecube_

    Joined:
    Aug 26, 2012
    Posts:
    18
    That is what I am doing . I am hiding the mouse cursor and drawing a sprite in its place.

    I have found a solution. I ended up writing a piece of code that raycasts from my custom cursor coordinates. If it catches a UI element it triggers its Enter state and makes it the target. If it doesn't but has a target it triggers its Exit state and removes the target. If I click and I have a target I trigger the "onclick" event.

    I will share some code once I clean it up.

    These two sources were a great help
    https://gist.github.com/stramit/c98b992c43f7313084ac
    https://gist.github.com/stramit/ce455682b7944bdff0e7

    Also this guy has a solution for VR Oculus Wordl Space cursors
    https://gist.github.com/flarb/052467190b84657f10d2
     
  5. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
    you know there is a mouse cursor setting in
    Edit->Project Settings->Player
    ?
     
  6. Scorr

    Scorr

    Joined:
    Jul 2, 2013
    Posts:
    73
    I meant rather than locking the mouse in one place and pretending it's somewhere else, let it move freely but draw something else. Unless I misunderstood, it seems like you're trying to create your own mouse input class with its own click events. If you keep the mouse unlocked you could just use the existing system.
     
  7. hubecube_

    hubecube_

    Joined:
    Aug 26, 2012
    Posts:
    18
    I am doing this in a custom class that extends BaseInputModule
    public class CustomCursor : BaseInputModule

    and I am attaching this class to the Event System component that came with the canvas

    Here is how you trigger the OnClick event of a GUI element.in the Update()

    BaseEventData data = GetBaseEventData();
    data.selectedObject = targetObject;
    ExecuteEvents.Execute(targetObject, data, ExecuteEvents.submitHandler);

    Here is how you get that TargetObject assigned raycasting into the scene

    //overriding the Process from BaseInputModule
    public override void Process()
    {
    //my custom cursor
    cursorCoords_.x = gc_.mCursor.anchoredPosition.x;
    cursorCoords_.y = gc_.mCursor.anchoredPosition.y;

    //set the custom cursor position
    pointer_ = new PointerEventData(eventSystem);
    pointer_.position = cursorCoords_;

    //raycast and set the TargetObject to the GUI element we hit.
    eventSystem.RaycastAll(pointer_, m_RaycastResultCache);
    pointer_.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);

    if(pointer_.pointerCurrentRaycast.go != null){
    SetTargetObject(pointer_.pointerCurrentRaycast.go);
    }else{
    SetTargetObject(null);
    }

    m_RaycastResultCache.Clear ();

    }


    This solution was causing me to hit Text element on buttons before I hit the button so I had to set all my text elements within the button structure to non interactive and non blocking using the Canvas Group component.
     
  8. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    There is a 'nicer' way to do this.

    There is the function:
    Code (csharp):
    1.  
    2.     GameObject go = ExecuteEvents.GetEventHandler<IPointerClickHandler> (currentOverGo);
    3.  
    Given a GO it will return the first in the heirarchy that implements the handler. So in this case if you have a background and a label but the first raycast is a label it will look at the label, see there is no IPointerClickhandler, then look at the background which does have the handler and return the button :)
     
    jgarbeidi and akuno like this.
  9. Bekatam

    Bekatam

    Joined:
    Jan 3, 2021
    Posts:
    3
    This may not help at all, but maybe it is because your ui button is not placed above the canvas it resides in. Try changing the PosZ value of the button(in its Rect Transform component) to a negative number and add your custom cursor as an image on your canvas with a PosZ value of 0. Sometimes your custom cursor can't register the button because the canvas is above it. Use the cursor on the canvas only when you need it and hide it when the player is not interacting with the canvas and activate another copy of your cursor(which isn't active when the other one is) when in world space if you use the cursor outside of said canvas. Hope I helped.
     
  10. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    Are there now more neat or unity providen way to do this? I made custom cursor too for console controller and now want to simulate mouse over function and mouse left click function.
     
  11. dtaddis

    dtaddis

    Joined:
    Oct 17, 2019
    Posts:
    20
    Sorry to necro this thread, but I found a cunning way of doing this, and wanted to share for future generations. In essence, I make a virtual mouse pointer, then get its world position (yes, even though it's a RectTransform, I use its Transform.position Vector3), then call RectTransformUtility.WorldToScreenPoint().

    I now have a screen point for the virtual mouse, which I plug back into the GraphicRaycaster for the canvas for a RayCast() and find what the virtual mouse is touching. I call OnPointerClick() with anything that has a Button component.

    I'm sure I'm going round the houses, but it works nicely for my purposes (I have a canvas rendered to a texture, and displayed on a curved mesh in VR).

    Code dump:

    Code (CSharp):
    1.                         Camera mainCamera = Camera.main;
    2.                         Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(mainCamera, _editorMousePointer.position);
    3.  
    4.                         EventSystem eventSystem = FindObjectOfType<EventSystem>();
    5.                         PointerEventData pointerEventData = new PointerEventData(eventSystem);
    6.                         pointerEventData.position = screenPoint;
    7.  
    8.                         List<RaycastResult> results = new List<RaycastResult>();
    9.                         _graphicRaycaster.Raycast(pointerEventData, results);
    10.                         foreach (RaycastResult result in results)
    11.                         {
    12.                             Button hitButton = result.gameObject.GetComponent<Button>();
    13.                             if (hitButton != null)
    14.                             {
    15.                                 hitButton.OnPointerClick(pointerEventData);
    16.                             }
    17.                         }
     
  12. TimesFaner

    TimesFaner

    Joined:
    Aug 21, 2023
    Posts:
    1
    Thanks for your great ideas that give me inspiration on my uty project.