- Home /
Simulate Button presses through code unity 4.6 GUI
I would like to simulate a uGUI button mouseclick or mousehover through code.
The objective is to have a keyboard key mapped to a uGUI button, and if the user HOLDS a keyboard button down, the 'onHover' on the uGUI button is activated. if the user RELEASES it, the 'onClick' on the button is activated.
I've spent the whole morning trying to find a proper solution but I can't seem to find one. Help please!
I think your explanation may include a typo which might confuse others. (holding and releasing both activate hover?)
Sorry, but I don't know how to invoke those callbacks through scripting. +1 for a good quesiton.
i updated the question to have references to triggers ins$$anonymous$$d, hopefully that would be more clear.
Sadly, the documentation doesn't mention a Click() method. I'm hoping it'll get added sometime. This is beta, after all.
In the meantime, I started playing around with using Transition: Animation on the button and then setting the animation controller's triggers from scripting. I don't know if I'll need to finish the work for the project I'm on, but I'll make a note to update this if I do.
Well i ran into a similar situation but this doesn't really solve your question, but the button.isOn variable actually calls the click events when you change it through code. $$anonymous$$aybe that helps a bit. Although I did it for the Toggle not the button.
well i ended up duplicating the code for the click and hover over to the keypress function. not efficient or pretty, but it does the job. two places to update stuff in the future, however.
Answer by CanisLupus · Nov 16, 2014 at 03:44 PM
I recommend that you check the ExecuteEvent class (I had a question similar to yours here). If you want to simulate a mouse hover on any object with a RectTransform, in this case named "button", you can do this:
var pointer = new PointerEventData(EventSystem.current);
ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerEnterHandler);
This will trigger the enter (hover) event, which listeners might be waiting for. For Buttons, you will see that it also triggers the visual hovered/highlighted state. Likewise, you can use other handlers defined in ExecuteEvents, such as pointerDownHandler, pointerUpHandler or submitHandler, triggering other events (down, up, click, etc).
Just know that, for a Button, Unity only visually changes it to its "down" or "up" state if it is hovered first, so using pointerEnterHandler is required beforehand. However, all events still trigger as normal, meaning that if you execute pointerDownHandler without pointerEnterHandler first, the OnPointerDown trigger will still be fired by the button object; only the Button will not change visually.
A test example, for the sake of completeness:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class ExecuteEventsOnButton : MonoBehaviour
{
public Button button;
void Update()
{
var pointer = new PointerEventData(EventSystem.current); // pointer event for Execute
if (Input.GetKeyDown(KeyCode.H)) // force hover
{
ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerEnterHandler);
}
if (Input.GetKeyDown(KeyCode.U)) // un-hover (end hovering)
{
ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerExitHandler);
}
if (Input.GetKeyDown(KeyCode.S)) // submit (~click)
{
ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.submitHandler);
}
if (Input.GetKeyDown(KeyCode.P)) // down: press
{
ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerDownHandler);
}
if (Input.GetKeyUp(KeyCode.P)) // up: release
{
ExecuteEvents.Execute(button.gameObject, pointer, ExecuteEvents.pointerUpHandler);
}
}
}
You can see what happens if button
is of class Button and you try to press P before pressing H (nothing happens). Press H to hover the button and then P to press it (keep P down for as long as you want, before releasing).
From this example and the documentation page, you should be able to do exactly what you want.
There is also a pointerClickHandler (I'm referring this as you also asked for a simulated "click" event), but I believe it doesn't trigger the visual changes in the Button by itself (even when using pointerEnterHandler first), so you might need to mix it with pointerDownHandler/pointerUpHandler, or simply use submitHandler (which works as if you pressed the Enter key with the button selected).
Finally, in case you or someone has tried, don't bother calling methods OnPointerEnter, OnPointerDown, etc on the Button (actually, Selectable) class, because these will affect the button visually but will do nothing else, as no events are triggered.
If the navigation of the selectable (in my case a button) was set to Automatic, calling pointDownHandler 2 times is calling a submit event even if I was calling pointerUpHandler and ExitHandler between the 2 pointDownHandler events. Now it works really fine thank you! $$anonymous$$y script was working fine with the navigation set to automatic with unity 4.6.1p1. It seems they changed something in the eventsystem in the 4.6.1.p2.
@CanisLupus If you don't $$anonymous$$d, could you help me out with a small problem related to this?
I have an UI in my game but it isn't possible to use mousepad to click on the buttons (because of special controllers). Ins$$anonymous$$d there is a game object that the player can move around and if a bool goes true i want it to emulated mouseclick, so I can click on stuff.
I tried to implement submitHandler(correct chocie for what i want to do?) in my code but I keep getting a shitload of errors and i'm really not that experienced in Unity or coding in general yet, so i don't really know what to do to make it work - pls help? (and pls c#)
all buttons in my UI are called Button
added my code if my explanation of what I wanted wasn't understandable.
public class simple$$anonymous$$ove : $$anonymous$$onoBehaviour {
bool checkani=false;
public void $$anonymous$$ovementHand (){
//$$anonymous$$akes so the gameobject can move around in the scene
}
public void Attack (){
//checks for a series of keyinput, and if player succed; checkani=true
}
public void OnClick(){
if (checkani) {
//If possible then I would like to emulate a mouseclick here so that i can use my gameobject to click on buttons in the UI
checkani = false;
}
}
}
Answer by zbalai · Jun 01, 2015 at 08:01 AM
I am running Unity version 5.0.2. (1 June 2015)
For me the above KeyButton.cs worked, but turned off mouse clicks in the editor.
So I made this minimalistic version of the KeyButton to just trigger the button without any color effects.
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
public class KeyButton2 : MonoBehaviour {
public KeyCode key;
public Button MyButton {get; private set;}
void Awake() {
MyButton = GetComponent<Button>();
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(key)) {
MyButton.onClick.Invoke();
}
}
}
Answer by Fattie · Mar 16, 2015 at 07:53 AM
Further to Canis answer, here's a script using his technique,
which provides an old-days style "pinball" keyboard or "steering wheel" keyboard. So, if the game is (say) a motorbike, the user uses the handlebars left-right to move over the keys and brake to select.
/*
Using CanisLupis code, http://answers.unity3d.com/questions/820599
here's a traditional "pinball machine style" keyboard
or "steering wheel keyboard". player can enter their initials
twitch the steering left-right to move over the keyboard,
brake to press a key.
simply have any working keyboard (it can be programmed
any way you want - so, when testing, you can click on the
keys, back key, and go button, with your mouse and all works)
drop this script on and it will "convert" the conventional input
keyboard to "pinball style" input
*/
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
namespace Smaaash
{
public class HandlebarKeyboard:MonoBehaviour
{
public bool keyboardTesting;
private string currentHover;
void Start()
{
if ( Input.mousePresent ) keyboardTesting = true;
currentHover = "";
}
private float pauseLeft;
private float pauseRight;
private bool clicked;
private void Update()
{
float steer;
bool brakePressed;
if (keyboardTesting)
{
steer = Input.GetAxis("Horizontal");
brakePressed = Input.GetKeyDown(KeyCode.DownArrow);
}
else
{
steer = your input systems.SteeringPlusMinusOne();
brakePressed = your input systems.BrakeYesNo();
}
if ( steer < -.5f )
{
Debug.Log("user is steering left");
if ( Time.time < pauseLeft ) return;
_Hover(PreviousKey());
pauseLeft = Time.time + .1f;
}
if ( steer > .5f )
{
Debug.Log("user is steering right");
if ( Time.time < pauseRight ) return;
_Hover(NextKey());
pauseRight = Time.time + .1f;
}
if ( brakePressed )
{
if ( clicked ) return;
_click();
clicked = true;
}
else
{
clicked = false;
}
}
private void _Unhover()
{
if ( currentHover == "" ) return;
GameObject thatKey = transform.Find(currentHover).gameObject;
var ptr = new PointerEventData(EventSystem.current);
ExecuteEvents.Execute( thatKey, ptr,
ExecuteEvents.pointerExitHandler );
}
private void _Hover(string keyName)
{
if ( currentHover == keyName ) return;
_Unhover();
GameObject thatKey = transform.Find(keyName).gameObject;
var ptr = new PointerEventData(EventSystem.current);
ExecuteEvents.Execute( thatKey, ptr,
ExecuteEvents.pointerEnterHandler );
currentHover = keyName;
}
private void _click()
{
if ( currentHover == "" ) return;
GameObject thatKey = transform.Find(currentHover).gameObject;
var ptr = new PointerEventData(EventSystem.current);
ExecuteEvents.Execute( thatKey, ptr,
ExecuteEvents.submitHandler );
}
// each Button underneath this game object, would simply have the
// relevant key letter as the .name of the game object
// heer using "<" for back key and "!" for the "ok" key.
string keys = "QWERTYUIOPASDFGHJKLZXCVBNM<!";
private string NextKey()
{
int kount = keys.Length;
for (int i=0; i<kount; ++i)
if ( ""+keys[i] == currentHover )
return ""+keys[ (i+1)%kount ];
return ""+keys[0];
}
private string PreviousKey()
{
int kount = keys.Length;
for (int i=0; i<kount; ++i)
if ( ""+keys[i] == currentHover )
return ""+keys[ (kount+i-1)%kount ];
return ""+keys[kount-1];
}
}
} // namespace
Answer by Kiwasi · May 19, 2015 at 09:56 PM
Worth mentioning this video if anyone is interested in a video tutorial of the same.