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

Trigger button click from code

Discussion in 'UI Toolkit' started by blisz, Jun 11, 2021.

  1. blisz

    blisz

    Joined:
    Jun 23, 2020
    Posts:
    5
    Hey,
    I have 4 buttons created with UI Toolkit. I want to 'bind' a keyboard key to each of the buttons and trigger click event when I press the correct keyboard key. Is there a way to 'simulate' button click from code?

    I use the same button for a few events. I am binding and unbinding events depending on what I click.


    ui toolkit.jpg
    My UI Toolkit

    1.jpg
    First batch of events.

    2.jpg
    After I click 'Stay' the second 'batch of events' is shown.

    Maybe, I am thinking about this whole scheme incorrectly, if so please let me know. :)


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Tilemaps;
    5. using UnityEngine.UIElements;
    6.  
    7. public class PlayerCharInteractionController : CharacterInteractionController
    8. {
    9.     private PlayerCharMovementController playerCharMovementController;
    10.     public InputMaster controls;
    11.     // Interaction UI elements
    12.     public UIDocument UIDocument;
    13.     private VisualElement CharacterAction;
    14.  
    15.     private Button WButton;
    16.     private Button AButton;
    17.     private Button SButton;
    18.     private Button DButton;
    19.  
    20.     private WorldTile charTile;
    21.     public bool inInteractionPrep = false;
    22.     public string interaction;
    23.  
    24.  
    25.     protected override void Awake()
    26.     {
    27.         base.Awake();
    28.  
    29.         playerCharMovementController = (PlayerCharMovementController)transform.GetComponent<PlayerCharMovementController>();
    30.  
    31.         // https://www.youtube.com/watch?v=Pzd8NhcRzVo
    32.         controls = new InputMaster();
    33.         controls.Player.WButtonClick.performed += ctx => WButtonClickInput();
    34.     }
    35.     void WButtonClickInput()
    36.     {
    37.        
    38.         // Code below does not work
    39.         // Is there a way to make it work?
    40.        
    41.         WButton.Click();
    42.         WButton.onClick.Invoke();
    43.  
    44.     }
    45.  
    46.  
    47.     void OnEnable()
    48.     {
    49.         controls.Enable();
    50.  
    51.         inInteractionPrep = true;
    52.         // getting ui elements
    53.         var rootVisualElement = UIDocument.rootVisualElement;
    54.  
    55.         // get interaction buttons
    56.         WButton = rootVisualElement.Q<Button>("WButton");
    57.         AButton = rootVisualElement.Q<Button>("AButton");
    58.         SButton = rootVisualElement.Q<Button>("SButton");
    59.         DButton = rootVisualElement.Q<Button>("DButton");
    60.  
    61.         // register interaction callbacks
    62.         WButton.text = "Persuade";
    63.         WButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 1.0f);
    64.         AButton.text = "Attack";
    65.         AButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 2.0f);
    66.         SButton.text = "Stay";
    67.         SButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 3.0f);
    68.         DButton.text = "useItem";
    69.         DButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 4.0f);
    70.  
    71.         //show char action el;
    72.         CharacterAction = rootVisualElement.Q<VisualElement>("CharacterAction");
    73.         CharacterAction.style.display = DisplayStyle.Flex;
    74.     }
    75.  
    76.     void OnDisable()
    77.     {
    78.         controls.Disable();
    79.  
    80.         // unregister callbacks
    81.         WButton.UnregisterCallback<ClickEvent, float>(ButtonClickEvent);
    82.         AButton.UnregisterCallback<ClickEvent, float>(ButtonClickEvent);
    83.         SButton.UnregisterCallback<ClickEvent, float>(ButtonClickEvent);
    84.         DButton.UnregisterCallback<ClickEvent, float>(ButtonClickEvent);
    85.     }
    86.  
    87.     // Update is called once per frame
    88.     void Update()
    89.     {
    90.         // TODO: I want to swap that to input system, that will 'invoke' clicks on my buttons
    91.         if (Input.GetKeyUp("w"))
    92.         {
    93.             //
    94.             InteractionPrep("persuade");
    95.  
    96.             //WButton.Invoke();
    97.         }
    98.         if (Input.GetKeyUp("a"))
    99.         {
    100.             InteractionPrep("attack");
    101.         }
    102.         if (Input.GetKeyUp("s"))
    103.         {
    104.             InteractionPrep("stay");
    105.         }
    106.         if (Input.GetKeyUp("d"))
    107.         {
    108.             InteractionPrep("useItem");
    109.         }
    110.  
    111.         // back functionality
    112.         if (Input.GetKeyUp("b"))
    113.         {
    114.             if (inInteractionPrep)
    115.             {
    116.                 BackFromInteractionPrep();
    117.             }
    118.             else
    119.             {
    120.                 Back();
    121.             }
    122.         }
    123.     }
    124.  
    125.  
    126.     /* Button click manager
    127.     * is it super stiupid?
    128.     */
    129.  
    130.     void ButtonClickEvent(ClickEvent clickEvent, float _interaction)
    131.     {
    132.         if (_interaction == 1.0f)
    133.         {
    134.             InteractionPrep("persuade");
    135.         }
    136.         else if (_interaction == 2.0f)
    137.         {
    138.             InteractionPrep("attack");
    139.         }
    140.  
    141.         else if (_interaction == 3.0f)
    142.         {
    143.             InteractionPrep("stay");
    144.         }
    145.         else if (_interaction == 3.1f)
    146.         {
    147.             FaceAndFinishInteraction(Vector2.up);
    148.         }
    149.         else if (_interaction == 3.2f)
    150.         {
    151.             FaceAndFinishInteraction(Vector2.left);
    152.         }
    153.         else if (_interaction == 3.3f)
    154.         {
    155.             FaceAndFinishInteraction(Vector2.down);
    156.         }
    157.         else if (_interaction == 3.4f)
    158.         {
    159.             FaceAndFinishInteraction(Vector2.right);
    160.         }
    161.  
    162.         else if (_interaction == 4.0f)
    163.         {
    164.             InteractionPrep("useItem");
    165.         }
    166.     }
    167.  
    168.     void FaceAndFinishInteraction(Vector2 direction)
    169.     {
    170.         Face(direction);
    171.         FinishInteraction();
    172.         // hide ui
    173.         CharacterAction.style.display = DisplayStyle.None;
    174.  
    175.     }
    176.  
    177.     void InteractionPrep(string _interaction)
    178.     {
    179.         inInteractionPrep = true;
    180.         interaction = _interaction;
    181.  
    182.         // highlight tiles in range
    183.         if (interaction == "attack")
    184.         {
    185.             ClearHighlight();
    186.             //    public void HighlightTiles(int range, Color col, bool diagonal, bool self)
    187.             HighlightTiles(2, Color.red, false, false);
    188.             // hide UI
    189.             CharacterAction.style.display = DisplayStyle.None;
    190.  
    191.         }
    192.         else if (interaction == "persuade")
    193.         {
    194.             ClearHighlight();
    195.             HighlightTiles(2, Color.green, true, false);
    196.             // hide UI
    197.             CharacterAction.style.display = DisplayStyle.None;
    198.  
    199.         }
    200.         else if (interaction == "useItem")
    201.         {
    202.             ClearHighlight();
    203.             HighlightTiles(1, Color.green, false, true);
    204.             // hide UI
    205.             CharacterAction.style.display = DisplayStyle.None;
    206.  
    207.         }
    208.         else if (interaction == "stay")
    209.         {
    210.             ClearHighlight();
    211.             inInteractionPrep = false;
    212.  
    213.             // change UI buttons
    214.             WButton.text = "Up";
    215.             WButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 3.1f);
    216.             AButton.text = "Left";
    217.             AButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 3.2f);
    218.             SButton.text = "Down";
    219.             SButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 3.3f);
    220.             DButton.text = "Right";
    221.             DButton.RegisterCallback<ClickEvent, float>(ButtonClickEvent, 3.4f);
    222.         }
    223.     }
    224. }
     
  2. griendeau_unity

    griendeau_unity

    Unity Technologies

    Joined:
    Aug 25, 2020
    Posts:
    230
    You can simulate a button click by sending a NavigationSubmitEvent with your button as the target.

    Code (CSharp):
    1.  
    2. using (var e = new NavigationSubmitEvent() { target = WButton } )
    3.     WButton.SendEvent(e);
    4. // etc..
    5.  
    This will trigger the active state to look like it was clicked. And will trigger the clicked event on the button, so instead of using RegisterCallback<ClickEvent>, you will need to use the
    WButton.clicked
    callback.
    I would suggest registering that event only once, and keeping a variable for the state of your view somewhere (a boolean or an enum value), instead of using float values.

    For key events, you'll probably want to look at KeyDownEvent or KeyUpEvent.
     
    Last edited: Jun 15, 2021
  3. blisz

    blisz

    Joined:
    Jun 23, 2020
    Posts:
    5
    Thank you so much for the answer!

    Code (CSharp):
    1. using (var e = new NavigationSubmitEvent() { target = WButton } )
    2.     WButton.SendEvent(e);
    3.  
    Is exactly what I was looking for. I have implemented changes to button callbacks and I am keeping information about state in booleans. It is less confusing now. Thanks! :)

    As for managing hotkeys I am using Unity's Input System and it works well.
     
  4. LarsLundh

    LarsLundh

    Joined:
    Sep 6, 2022
    Posts:
    20
    Why is there not an Activate() convenience method?
    can I request one somewhere?

    Would be great if it was possible:
    this.Q<Button>("Name").Activate();

    The SendEvent(ev) seems ok... but I have used RegisterCallback<ClickEvent> half the time and so that is awkward.
     
    yatyricky likes this.