Search Unity

Question: How do I detect if the mouse is over any UI element? [UI Elements]

Discussion in 'UI Toolkit' started by erlapso, Feb 16, 2020.

  1. erlapso

    erlapso

    Joined:
    Apr 7, 2019
    Posts:
    6
    In the old Unity UI I would have
    `EventSystem.current.IsPointerOverGameObject()`
    and that would work in stuff like (pseudo code follows)
    `getbuttondown("fire1") if ( EventSystem.current.IsPointerOverGameObject() ) } do nothing { else } `
    Now im trying to switch to UIElements - which looks awesome - but I really need to be able to tell if the user is clicking on the UI or somewhere else. How do I do that? I could not find it in the docs
     
    OMGOMGXAXA likes this.
  2. VOTRUBEC

    VOTRUBEC

    Joined:
    Dec 17, 2014
    Posts:
    106
    Do you want to know when the mouse enters and leaves the VisualElement, or when the MouseUpEvent/MouseDownEvents occur?

    Depending on your need, one of these should do the trick:

    Code (CSharp):
    1. yourElement.RegisterCallback<MouseEnterEvent> ( x => OnMouseEnter ( x ) );
    2. yourElement.RegisterCallback<MouseLeaveEvent> ( x => OnMouseLeave ( x ) );
    3. yourElement.RegisterCallback<MouseUpEvent> ( x => OnMouseUp ( x ) );
     
    bodiamykhats and jGate99 like this.
  3. PMacDev

    PMacDev

    Joined:
    Sep 8, 2020
    Posts:
    7
    This would work for a one-off, but what if you would want to do this for ALL of the elements, so essentially checking if the player is clicking a UI Element or trying to interact with the game?
     
  4. Arkenhammer

    Arkenhammer

    Joined:
    Nov 10, 2019
    Posts:
    51
    What I did was create my own custom background element for each UI panel which goes over my game; those panels register/unregister themselves in a list of UI areas (via an interface). Then when my game gets a mouse click it runs through each of the areas to see if the mouse is in a UI area and, if so, it rejects the click and lets the UI Event system handle it. It's not pretty, particularly for panels which move or animate but, for my game, it got me the enough to replace the old "IsMouseOverUI" functionality.

    Note: MouseEnterEvent and MouseLeaveEvent do not solve this problem because the mouse will "Leave" the background when it enters an interactable child element. Adding mouse enter/leave to 100s of elements in the UI is not really an option so rectangle testing it is.
     
    Issus94 likes this.
  5. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    For the record, we will have proper Panel layering and event handling between UI Toolkit Panels, UGUI Panels, and the game view in 2021.1. Should hopefully reduce the need for the creative but legitimate solutions in this thread.
     
    craftsmanbeck likes this.
  6. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    397
    I am at this point right now with 2021.1. Here you cannot click through from one ui document to another anymore, and also not on to UGUI.
    The Sort order also works now with UGUI.

    But I still don't see an option to detect if the mouse is over the UI without a detection-Panel which reacts to MouseEnter and MouseLeave.
    And doing that with uitoolkit only can detect if the mouse is on that particular uidocument. If there are more layered this does not work.
    What works is having a UGUI Canvas behind sorted behind all the UIToolkit-documents and detect there if the mouse is over the ui or not.
    But this method has it's own problems because now, the detection-Panel blocks events.

    Systems I knew solved this by raycasting and detecting if the raycast was blocked by the "UI" layer. This seems not possible with UIToolkit.

    Or do I miss something important?
     
  7. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    397
    And it does not work in builds! My canvas UI detection mechanism works in the editor but not in build... :(

    Edit:
    Hm I have some other UGUI panels in front of that ui detector panel. It seams one of those panels blocks the detector in build but not in editor
     
    Last edited: May 18, 2021
  8. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    780
    Hi, on 2021 you should simply be able to use the EventSystem.IsPointerOverGameObject method to detect if the mouse is over any UI (both UI Toolkit and UGUI). This requires having an EventSystem in the scene.
     
    mcbauer and manuelgoellnitz like this.
  9. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    397
    Oh yes that works! Many thanks
    I tried it before, but probably something else in my code broke it :)
     
  10. whiteclouds2016

    whiteclouds2016

    Joined:
    Sep 22, 2017
    Posts:
    18
    @manuelgoellnitz Hi, bro, When I use "EventSystem.current.IsPointerOverGameObject()",it always return false.
    It is any trick for it?
     
    Kazko likes this.
  11. Kazko

    Kazko

    Joined:
    Apr 2, 2014
    Posts:
    82
    EventSystem.current.IsPointerOverGameObject() return True for me, most of the time. UITK panel seems to not block the pointer being over GO, and also it seems it needs the EventSystem component, so when I use InputSystemEventSystem(UITookkit) component, there is a warning that only one event system can be active.

    I found a solution in another thread yesterday. https://forum.unity.com/threads/using-new-input-system-with-ui-toolkit.1026847/

    It's a hacky one, and one that probably requires you to use a single UI Document. I transitioned from using multiple UIDocs to a single one couple of weeks ago because of another problem, and I suggest this is the way you do it. If you do, then you can create a VisualElement master in your main Document and then place all your other UI inside the master. So then if you do (somewhere on Start or Awake) the following:

    Code (CSharp):
    1. MasterVisualElement.RegisterCallback<PointerOverEvent>((evt) =>
    2.             {
    3.                 OverUI = true;
    4.             });
    5.            
    6.             MasterVisualElement.RegisterCallback<PointerOutEvent>((evt) =>
    7.             {
    8.                 OverUI = false;
    9.             });
    Where OverUI is some static bool, you are now able to check this bool and if it's true, exit from your other input operations. This would work the best if your UI is static on screen. Mine wasn't, so there were couple of problems with showing/hiding UI panels (for example an options menu).

    I used to show/hide panels using style.opacity, because using Flex/None or transform.scale Vector3.Zero/One was causing the UI to lose some of the layout. But when using opacity, the UI is still there, so this hack won't work. I tried modifying the picking mode to Ignore along with hiding the panel, but that did not work either. I had to reposition the panel outside of screen (for example style.top = Screen.height * 2) for this to work.

    It works, but it all seems so hacky and buggy for such a trivial thing and I can't wait for this to be fixed. Someone if reading this, please perhaps suggest some improvements.
     
  12. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    397
    Dion't use the EventSystem of UIToolkit but the Unity Standard one. And only have one EventSystem in the scene.
     
  13. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    397
    I also tried this solution. But it has one flaw: I didn't try "PointeroutEvent" but "PointerLeaveEvent". And That Event is not fired when the user has the app in Window mode and moves the mouse from a UI element outside of the Window.
     
  14. whiteclouds2016

    whiteclouds2016

    Joined:
    Sep 22, 2017
    Posts:
    18
    OK, I have fixed my problem and shared why it always return false
    1.You must add the Standard EventSystem as what @manuelgoellnitz suggested
    2.Set the "PickingMode.Ignore" even thought the panel include nothing but itself. It will broke the mouse event.

    FYI
     
    Leslie-Young likes this.
  15. Leslie-Young

    Leslie-Young

    Joined:
    Dec 24, 2008
    Posts:
    1,148
    Unity, is there an official solution to this?

    Using Component/Event/EventSystem result on not being able to use Component/UIToolkit/InputSysteEventSystem (UI Toolkit) (Unity throw warning about there being two event systems). The controls does not work correctly if I do not use the UI Toolkit specific component. I could for example not drag a slider, only click to change its position. But not using EventSystem (non UI Toolkit) causes that one can not use EventSystem.current.IsPointerOverGameObject().

    [Edit] I see that EventSystem.current.IsPointerOverGameObject(), and my Slider, works despite the warning of having two event systems in the scene. This feels all so messy but I guess it is what we have to live with while UIToolkit is in "preview".

    Now to figure out why TwoPaneSplitView is causing pickingmode=ignored to be ... ignored.
     
    Last edited: May 30, 2021
  16. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Leslie, I'm very sorry for the situation of [EventSystem + UI Toolkit + new Input] not working fully at the moment. We have specific feature cutoff dates and one of the pieces to the puzzle got in while a second piece got left out, in the last major feature cutoff. This is no excuse, but I do feel bad about the current situation. You have the right idea though: this situation is temporary, a fix should be our shortly in the Input System package for UI Toolkit compatibility with the EventSystem component.
     
  17. bloodthirst69

    bloodthirst69

    Joined:
    Oct 1, 2017
    Posts:
    28
    I dunno if this is what ur looking for , but this one worked for me :

    Code (CSharp):
    1.         /// <summary>
    2.         /// Is mouse inside the rect of a visual element ?
    3.         /// </summary>
    4.         /// <param name="pos">The world space position of the mouse (evt.position)</param>
    5.         /// <returns></returns>
    6.         private bool IsInsideElement(VisualElement v , Vector2 pos)
    7.         {
    8.                 return v.worldBound.Contains(pos);
    9.         }
    10.  
     
    randomdragon, OMGOMGXAXA and Kazko like this.
  18. CoryMaklin

    CoryMaklin

    Joined:
    Oct 10, 2020
    Posts:
    29
    How can we check whether the mouse is over a specific element? I have an inventory and equipment UI, and I've been using worldBound.Contains for drag and drop functionality. However, when one UI is behind the other, I need a way of determining which is in front prior to checking whether the item being dragged overlaps with the slots.
     
  19. bloodthirst69

    bloodthirst69

    Joined:
    Oct 1, 2017
    Posts:
    28
    This depends on your uxml structure , for example if u have something like
    <parent>
    <inventory>
    <equipement>
    </parent>

    then u can just use inventoryVisualElement.parent.IndexOf(inventoryVisualElement) or equipementVisualElement.parent.IndexOf(equipementVisualElement) to get who's in front , if u want to change the order of who's in front you can use the BringToFront() and SendToBack() methods.

    if your hierarchy is more complex then you'll need to find their common ancestor in the hiararchy (aka their first parent element) and under that -let's call it "A" , then you find out the closest distinct parent of each under "A" element.
    then you use the index of those two to figure out who's in front

    Hope this helps
     
  20. CoryMaklin

    CoryMaklin

    Joined:
    Oct 10, 2020
    Posts:
    29
    Hey! That does help! However, how would you use that method if you had multiple UI Documents?
     
  21. bloodthirst69

    bloodthirst69

    Joined:
    Oct 1, 2017
    Posts:
    28
    By UI Documents you mean mutliple EditorWindows ? cuz multiple UI Documents != multiple EditorWindowsv.
    if you mean multiple editor windows open , then i would start with this (i am just suggesting here , this is just where i would start and not tested)
    - first i would register them in a static list to keep a list of the opens windows.
    - Use the "OnFocus" unity special method to shuffle the list according to their order on screen
    - if that doesn't work , i would look into "GUI.depth" which shows the current window's depth (careful , this used IMGUI and no UI Toolkit , so make sure to use the IMGUIContainer thingy)
    - every editorWindow has a "position" property , it's the window's top-left corner postion in screenSpace , the rest of the elements in the window are in "local space" of the window.
    - so if i wanted to test if elements (A and B for example) are on different windows are overlapping , i would basically
    do something like :
    Vec2 A_pos_In_screenSpace = A_position_in_its_own_window_local_space => A_pos_in_screen_space (based on the window's pos)

    Vec2 B_pos_In_screenSpace = B_position_in_its_own_window_local_space => B_pos_in_screen_space (based on the window's pos)

    do the comparison now since they are in the same space.

    some like that
     
  22. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    Is it fixed now in preview.18?
     
  23. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Yes, it's fixed since Input System 1.1.1 (or more precisely 1.0.0-pre.5), and should work with Unity 2021.1 + UI Toolkit package preview.18, or Unity 2021.2 built-in UI Toolkit runtime.
     
  24. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    Tested it again, while having both
    Input System UI Input Module
    and
    Input System Event System (UI Toolkit)
    enabled doesn't produce any warnings or errors,
    EventSystem.current.IsPointerOverGameObject();
    still throws an exception.

    Is there still no way to detect pointer over UI Toolkit elements?
     
  25. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    You can't have both components at once. You should remove InputSystemEventSystem (UI Toolkit) and keep only InputSystemUIInputModule with the EventSystem component that comes with it. Both InputSystem components have slightly different roles and we are currently in the process of replacing the first one in favor of the second one.


    (If you're still having an exception after that, can I ask the type of exception, file and line number, and the exact version of Unity you're using? I might go have a try at reproducing your situation, so I will probably need some info to copy your setup, or maybe an attached project I can use.)
     
  26. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    If I turn off UI Toolkit EventSystem, I receive the following exception every frame:


    Code (CSharp):
    1. InvalidOperationException: You are trying to read Input using the UnityEngine.Input class, but you have switched active Input handling to Input System package in Player Settings.
    2. UnityEngine.UIElements.DefaultEventSystem+Input.GetAxisRaw (System.String axis) (at Library/PackageCache/com.unity.ui@1.0.0-preview.18/Core/DefaultEventSystem.cs:423)
    3. UnityEngine.UIElements.DefaultEventSystem.GetRawMoveVector () (at Library/PackageCache/com.unity.ui@1.0.0-preview.18/Core/DefaultEventSystem.cs:332)
    4. UnityEngine.UIElements.DefaultEventSystem.ShouldSendMoveFromInput () (at Library/PackageCache/com.unity.ui@1.0.0-preview.18/Core/DefaultEventSystem.cs:362)
    5. UnityEngine.UIElements.DefaultEventSystem.SendInputEvents () (at Library/PackageCache/com.unity.ui@1.0.0-preview.18/Core/DefaultEventSystem.cs:117)
    6. UnityEngine.UIElements.DefaultEventSystem.Update (UnityEngine.UIElements.DefaultEventSystem+UpdateMode updateMode) (at Library/PackageCache/com.unity.ui@1.0.0-preview.18/Core/DefaultEventSystem.cs:77)
    7. UnityEngine.UIElements.UIElementsRuntimeUtility.UpdateRuntimePanels () (at Library/PackageCache/com.unity.ui@1.0.0-preview.18/Core/UIElementsRuntimeUtility.cs:214)
    8. UnityEngine.UIElements.UIElementsRuntimeUtilityNative.UpdateRuntimePanels () (at /Users/bokken/buildslave/unity/build/Modules/UIElementsNative/UIElementsUtility.bindings.cs:26)
    9.  
    Edit:
    Unity 2021.1.23f1,
    UIToolkit 1.0.0-preview.18
    Input System 1.1.1
     
    Last edited: Nov 10, 2021
  27. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    I'm trying to understand how you're set up, something seems wrong in what components you have there. I've taken the liberty to create an empty project and set it up with 1 UI Toolkit button and 1 UGUI button, with the same editor and packages you have. On my side I have no warning or exceptions and everything works like it should. Can you check that you have a similar set up?
     

    Attached Files:

  28. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    Ok the difference was that I have previously disabled regular `Event System` script and enabled `Input System Event System (UI Toolkit)` to make UI Toolkit work woth Input System. After our discussion I disabled the UI Toolkit system and enabled `Input System UI Input Module (Script)` back. But I didn't enabled general Event System since I didn't think it was used at all without UGUI. upload_2021-11-11_15-25-35.png

    Now that I have enabled it, everything works, including `IsPointerOverGameObject()`. Thanks a lot!
     
  29. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    I didn't manage to make it work with touch screen. I have added an IsPointerOverGameObject check on an Input Action handler, and now I receive the following warning:

    Code (CSharp):
    1. Calling IsPointerOverGameObject() from within event processing (such as from InputAction callbacks) will not work as expected; it will query UI state from the last frame
    2. UnityEngine.EventSystems.EventSystem:IsPointerOverGameObject ()
    3.  
    On touch screen scene raycast is not prevented with this check.
    I suppose that the issue is that last frame state on touch input is not relevant in the frame of PointerDown event, but I can't imagine another place to put the IsPointerOverGameObject() check. With touch input the PointerDown event is the first to appear so there's even no pointer movement to update the UI state before handling the click.

    What is the recommended way to block raycasts with touch input then?
     
  30. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Touch screen support is done through the InputSystemUIInputModule component. Whatever touch problems you have probably come from a configuration of that component that doesn't correctly reflect your situation. Try using PointerBehavior = "All Pointers As Is", that's what usually works best for me when using a touch screen, in particular if I'm using a laptop that also has a mouse or trackpad. At this point I suggest testing if UGUI components also show the same problems with Touch on your system, and if so you might want to refer to the Input System's forum for further help. If All Pointers As Is doesn't work, or if UGUI shows no sign of problems but UI Toolkit is completely non responding, then let me know and I'll try to help some more.
     
  31. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    I tried the setting you mentioned, however it did not solve the issue. Also there's no issue with trackpad and mouse, only touchscreen is affected by inability to detect buttons with IsPointerOverGameObject(). I will research this issue more since I think it's an issue with logic in my code and IGUI buttons would not be detected as well.
     
  32. Neopolitans

    Neopolitans

    Joined:
    Sep 2, 2013
    Posts:
    3
    I've found that even with a singular event system in the scene this can return as always true when you're hovering over *any* game object. I cannot find any solution that won't be hacky in some way (e.g. compare mouse position vector to point A and point B spanning the length of a UI to see if it's within that UI range) for what I'm trying to do in my CoH-style RTS.

    I'm using 2021.3.6f1 as required by my university for unity projects, which is why I've posted here about this.
     
  33. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    226
    I hope Unity puts some effort into making this easier. Feels obtuse right now.

    Feels like there is a really powerful platform here but it's a headache to work with. I don't even see the EventSystem in the 2022.2.x documents. Is the EventSystem deprecated?
     
    keithjones and t2g4 like this.
  34. keithjones

    keithjones

    Joined:
    Jan 19, 2023
    Posts:
    2
    It doesn't seem to be in 2021.3 either.
     
  35. sasyda

    sasyda

    Joined:
    Mar 31, 2022
    Posts:
    9
    hi there, just wanted to know if it is done yet and how should it be used now?
    i actually want button-clicks not to be translated into ar raycasts...
     
    Mikael-H likes this.
  36. FactotumDigital

    FactotumDigital

    Joined:
    Mar 8, 2018
    Posts:
    2
    My extremely hacky solution for this was to create a virtual device that I bind to touch in my case, then listen to the started and canceled events of Pointer Press, store them locally as bools, and meanwhile, monitor in Update for the EventSystem.current.IsPointerOverGameObject();- and if I start and I am over UI I disable the whole virtual device and if I cancel - I reenable if it was disabled. This way I stop firing virtual events - so whatever logic is using them stops receiving actions. But this is a bit absurd.