Search Unity

Preventing InputSystem callback on UI click

Discussion in 'Scripting' started by Rocky_Unity, Apr 11, 2021.

  1. Rocky_Unity

    Rocky_Unity

    Joined:
    Oct 13, 2017
    Posts:
    96
    Hello!

    I am using the new Input System and one of the inputs is a Left mouse click. Everything works great! Except I have this logic issue..

    I don't want my Input system to process a left click if I clicked on a UI element though. Or at least I want to prevent some game logic that is normally called on a "left click" event, if I happen to click on a raycast target.

    Any ideas on how I could go about this?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    This is an issue that plagues not only the new input system but also the old input system.

    Basically either of the above input systems versus the UI system provides two different "streams" of input that really don't interact.

    The input coming from the UI system is coming from the EventSystem.

    You could also operate only on that event stream by adding an invisible button behind all your other buttons, and hooking up an EventTrigger() to it so you can get clicks straight from the same EventSystem stream of happenings via that invisible button.

    That way if someone clicks on another button in front of your massive all-screen button, the all screen button won't see it.

    I like to use this for invisible buttons: it's a raycast grabber that costs nothing GPU-wise (draws nothing)

    https://gist.github.com/kurtdekker/043891a1d27b0e7df6f3f064da6d70ad
     
    Last edited: Apr 11, 2021
  3. Rocky_Unity

    Rocky_Unity

    Joined:
    Oct 13, 2017
    Posts:
    96
    Oh that's a cool way of going about it! I would have to implement this invisible button over each UI element I have though, not just other buttons. That could get tedious and easy to make mistakes. I'd be sad to implement a "hack" so to speak too..

    It's almost as if there was a nearly perfect way of solving this with
    Code (CSharp):
    1. EventSystem.current.IsPointerOverGameObject()
    but...
    This doesn't help because I only want "
    IsPointerOverUIObject
    ". Some of my GameObjects implement
    IPointerHandler 
    callbacks, that do some `Action` delegation upon a LeftClick. Writing this out, I guess I could keep using
    IsPointerOverGameObject
    , and not assign an `Action` override, but instead use
    IPointerClickHandler
    , which is actually cleaner..... hmm.
    I'll give that a whirl. I know I could use
    OnMouseEnter 
    instead of
    IPointerHandler
    , but I think using an interface instead of magic messages is a better design choice. Especially because I may want to port to consoles someday that won't have a mouse.
    IPointerHandler 
    callbacks pass in
    PointerEventData
    , which contains data I'd want for my original use case, but it's not entirely helpful because I can't access that from the
    InputSystem 
    callbacks. What I could theoretically do in this case is use assign the hover variable of
    PointerEventData 
    each time I get an
    IPointerEnter 
    and
    IPointerExit 
    to some custom static variable, then use that in conjunction with
    IsPointerOverUIObject
    . That sounds a little messy but could work.

    Thanks for reading my ramblings. It'd be nice if Unity just provided the flexibility of more pointer data in the
    EventSystem
    . Power to the creators! (gamestop pun)
     
    Last edited: Apr 11, 2021
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    No... The other way around! You only need one invisible UI object that is underneath all the other UI stuff. This inviso-button is just waiting under everything else for what might "fall through" all your other clickables.

    In fact, it could probably be loaded once, live in its own separate canvas that renders under all others, and never unload.

    Honestly the biggest annoyance is every Text and TMPRo item (on a button or otherwise) is by default marked as RaycastTarget, which would block ALL input going through them, even if they were not technically used in an interactable sense.
     
  5. Rocky_Unity

    Rocky_Unity

    Joined:
    Oct 13, 2017
    Posts:
    96
    Ooooh! That would work very well then! So I think that leaves two options then;
    1. use both systems: within your InputSystem script, run the EventSystem.IsPointerOverGameObject() check (bearing in mind this is only true if over a raycastable UI object, or game objects implementing the IPointerXXXHandler + physics raycaster on a camera)
      1. You can still have click interactions on objects by then using IPointerClickHandler
    2. or, just use the EventSystem to handle all the mouse interaction and do the invisible button.

    And yes I totally agree, I would love the RaycastTarget default to be false. It's probably true for beginners, so it's less difficult for them to get up and running with things, which is understandable, but annoying lol.