Search Unity

Force a pointer press on a Button from code (as if it came from a mouse/touch event)

Discussion in 'UGUI & TextMesh Pro' started by CanisLupus, Nov 14, 2014.

  1. CanisLupus

    CanisLupus

    Joined:
    Jul 29, 2013
    Posts:
    427
    For the purposes of a tutorial we're making for our 2D game, we want to force a mouse/touch press (and release) on a certain Button at certain times (controlled by an animation).

    We could achieve the desired effect by sending AnimationEvents from the animation and, with code, activate the button's "down" sprite and call Invoke() on a PointerDown EventTrigger present in the button object. This would act almost as if a pointer pressed the button. However, if the button does other things when pressed (animated state transitions, for instance), this doesn't seem like a good solution.

    Is there a better way, like a method we can call that actually presses the button like a touch/mouse click would? I wasn't able to find any in the documentation.

    Edit: This would also be useful for creating key bindings for buttons and actually see the button being pressed as you press the keyboard key, instead of some OnPress/OnRelease event just being generated.
     
    Last edited: Nov 14, 2014
    dappledore likes this.
  2. CremaGames

    CremaGames

    Joined:
    Mar 5, 2014
    Posts:
    59
    This will simulate a click on "buttonToFire", will do the animations and the onClick assigned.

    Code (CSharp):
    1. ExecuteEvents.Execute(buttonToFire.gameObject, new BaseEventData(EventSystem.current), ExecuteEvents.submitHandler);
     
  3. CanisLupus

    CanisLupus

    Joined:
    Jul 29, 2013
    Posts:
    427
    Ah, I didn't know that ExecuteEvents existed! Thank you! :) Your post was very useful.
     
    Last edited: Nov 15, 2014
  4. CanisLupus

    CanisLupus

    Joined:
    Jul 29, 2013
    Posts:
    427
    For people searching for the same and /or having problems with this:

    We needed to use "pointerDownHandler" and "pointerUpHandler" (in some cases we want to simulate a press for a few seconds, and then release), but executing those seemed to do nothing to the button. The problem was that the down event will only happen if the button is being hovered first (it makes sense). Consequently, we need to execute the "pointerEnterHandler" first:

    Code (CSharp):
    1. var pointer = new PointerEventData(EventSystem.current);
    2. ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerEnterHandler);
    3. ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerDownHandler);
    And to release:
    Code (CSharp):
    1. var pointer = new PointerEventData(EventSystem.current);
    2. ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerUpHandler);
    Depending on your setup, you shouldn't need to execute "pointerEnterHandler" before every "pointerDownHandler". Doing it once is enough, unless you use your actual mouse/touch to do stuff to the button (which can trigger the "exit" event on the button, requiring a new "enter").

    Don't try to call the OnPointerEnter, OnPointerDown, etc methods on the Button class, because these will affect the button visually but not trigger the events themselves (the ones you're listening to).
     
  5. cyraxchel

    cyraxchel

    Joined:
    Jul 10, 2012
    Posts:
    3
    Note, that now for detecting current EventSystem need use:
    Code (CSharp):
    1. EventSystemManager.currentSystem
    Update: Sorry, this actual for Unity 4.6.0 b1
    Correct, of cource, is:
    Code (CSharp):
    1. EventSystem.current
     
    Last edited: Mar 30, 2015
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I did a video here that does most of what you are asking for.

     
  7. CoalCzar

    CoalCzar

    Joined:
    Nov 25, 2012
    Posts:
    22
    Further info:

    If you know your IEventHandler target and/or want to target only a specific handler of the event on a certain gameObject (and not just any and all handler components on a gameObject), you can use the helper methods, e.g.,

    Code (CSharp):
    1. [SerializeField] private Button _button;
    2. //whatever method this call belongs in
    3. ExecuteEvents.pointerDownHandler(_button, new BaseEventData(EventSystem.current));
     
    FlightOfOne and IgorAherne like this.
  8. NavarroFamily

    NavarroFamily

    Joined:
    Feb 15, 2016
    Posts:
    15
    Sorry about reviving a dead post,
    But is there anyway to do this outside of UI.

    Like with game objects in the scene if I had 2 squares with box collider 2Ds on them.
    I'd want it so if I clicked square 1, square 2 got a fake click.
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Sure. It all depends on exactly how you are picking up input.

    If you are using the event system with a PhysicsRaycaster, you can create a fake click as shown in the video.

    If you are using OnMouseDown then you call OnMouseDown directly.

    If you are using RayCasting against collider you can cast a 'fake' ray.
     
  10. DerDicke

    DerDicke

    Joined:
    Jun 30, 2015
    Posts:
    292
    here is a version that worked for me (Unity 5.5):
    Code (CSharp):
    1.    
    2.     IEnumerator CoClickButton(Button b)
    3.     {
    4.         // simulate a button click  
    5.         var pointer = new PointerEventData(EventSystem.current);
    6.  
    7.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerEnterHandler);
    8.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerDownHandler);
    9.         yield return new WaitForSeconds(0.1f);
    10.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerUpHandler);
    11.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerClickHandler);
    12.     }
    13.  
     
  11. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    393
    4 gold nuggets in this tread. Thanks!!
     
  12. Vosheck

    Vosheck

    Joined:
    Feb 29, 2016
    Posts:
    12
    Here's what worked for me in 2018.2:

    Code (CSharp):
    1.     IEnumerator ClickButton(Button b) {
    2.         var pointer = new PointerEventData(EventSystem.current);
    3.  
    4.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerEnterHandler);
    5.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.submitHandler);
    6.  
    7.         yield return new WaitForSeconds(0.1f);
    8.         ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerExitHandler);
    9.     }
     
  13. laessnb

    laessnb

    Joined:
    Jun 10, 2014
    Posts:
    101
    Wanted to mention that the above post from @Vosheck still works perfectly in 2019.4. Thank you.