How do I override or place inputs in the input object for automation?

Hey everyone!

I’m working within a company that is building Unity games and I’m responsible for generating an in-house solution that will provide us with a way to be able to automate testing of a running instance of Unity. The intention is to build a Silenium for Unity.

The diversity of types of games that Unity can help build makes it hard to be generic though. The only game that is close to completion is a client-server game, and largely handles input on the client by pulling data from the Input global during the update cycle, and sends commands accordingly. I can see our other games in development being objects that operate off of specific commands, such as swiping and clicking on game objects with listeners.

What I really want to be able to do here is to be able to have a suite run without a mouse driven by a human, meaning I’d like to be able to say mouseRightClick and move the mouse to a particular location. Otherwise I have to have the framework try to autodiscover components that read from the input and try to invoke the (sometimes private) functions that they invoke to simulate clicks through reflection and event messaging.

Is there any alternative to this larger task available? Does anyone know of any plugins that would be available to handle input conversion from a mouse, touch, keyboard, etc?

I know that generally speaking, the Input global is read only for things like mousePosition for a reason, as it would enable serious cheating if it went out with a production build, but the idea is that we wouldn’t include it within the build. This is always the difficult part with automation (because it is contained cheating, really)

I would suggest writing a wrapper for Unity’s input system, and have your games get all their input from the wrapper, rather than from Unity directly. Once you have your own wrapper you have control over all the code and can automate to your heart’s content.

The mobile guys may feel different, but for PC I would recommend just rewriting the entire input system. This was the easier choice for me when I started trying to use an xBoX controller. The XBox controller support is just terrible.

Update:
It looks like you really don’t want to rebase, so I would recommend doing what Yoyo said. There is no way to start mucking with the Unity3D input system, so you really have no other choice. Make a wrapper around the Unity input system. It wont be nearly as hard as you think. A simple text search will find you all the references to “Input.” For the wrapper itself, ill post a some of the code I used to use when I was trying to use Unity for Xbox input.

Note: This is NOT a static class. Statics are evil, so the only place I use them is in a single “Globals” class that has an accessor to the one and only instantiation of this “InputProcessor” script. Accessing it then looks like:

"Globals.InputProcessor."

Remember that if you want to use touch input, your going to have to write a wrapper no matter what. Unity’s raw touch input will not be sufficient for much of anything but feeding data to a wrapper.

public class ButtonState
{
    public bool Fire;
    public bool Scope;
    public bool SelectFire;
    public bool Reload;

    public bool Jump;
    public bool Sprint;
    public bool Crouch;
    public bool Prone;

    public bool CycleWeapon;
    public bool Weapon1;
    public bool Weapon2;
    public bool Weapon3;
    public bool Weapon4;
}
...

public class InputProcessor : MonoBehaviour {

    public SensitivityState[] SensitiviyLevels = new SensitivityState[1];

    public Vector2 Look
    {
        get { return new Vector2(LookHorizontal, LookVertical); }
    }
    public float LookHorizontal
    {
        get 
        {
            if (!enabled)
                return 0f;

            return Input.GetAxis("Horizontal") * mouseLevel + Mathf.Pow(Input.GetAxis("XBoxHorizontal"), 3f) * xBoxlevel; 
        } 
    }
    public float LookVertical
    {
        get 
        {
            if (!enabled)
                return 0f;

            return Input.GetAxis("Vertical") * mouseLevel + Mathf.Pow(Input.GetAxis("XBoxVertical"), 3f) * xBoxlevel; 
        } 
    }

    // These values are clamped to a unit circle
    public Vector2 Movement
    {
        get
        {
            Vector2 Vec2 = Vector2.zero;

            if (!enabled)
                return Vec2;

            Vec2.y = Input.GetAxis("Forward") + Input.GetAxis("XBoxForward");
            Vec2.x = Input.GetAxis("Strafe") + Input.GetAxis("XBoxStrafe");

            return Vector2.ClampMagnitude(Vec2, 1.0f);
        }
    }
    public float MoveForward    { get { return Movement.y; } }
    public float MoveStrafe     { get { return Movement.x; } }

    public ButtonState ButtonDown = new ButtonState();
    public ButtonState ButtonUp = new ButtonState();
    public ButtonState Button = new ButtonState();

    ...
	
	void Update () 
    {

        // Button Downs

        ButtonDown.Fire = Input.GetButtonDown("Fire") || fireTracker.Down;
        ButtonDown.Scope = Input.GetButtonDown("Scope") || scopeTracker.Down;
        ButtonDown.SelectFire = Input.GetButtonDown("SelectFire");
        ButtonDown.Reload = Input.GetButtonDown("Reload");
        ...


        // Button Ups

        ButtonUp.Fire = Input.GetButtonUp("Fire") || fireTracker.Up;
        ButtonUp.Scope = Input.GetButtonUp("Scope") || scopeTracker.Up;
        ButtonUp.SelectFire = Input.GetButtonUp("SelectFire");
        ButtonUp.Reload = Input.GetButtonUp("Reload");
        ...


        // Buttons

        Button.Fire = Input.GetButton("Fire") || fireTracker.Depressed;
        Button.Scope = Input.GetButton("Scope") || scopeTracker.Depressed;
        Button.SelectFire = Input.GetButton("SelectFire");
        Button.Reload = Input.GetButton("Reload");
  ...

For games using UI event system, using BaseInputModule.inputOverride might be a solution.