2

I'm working on a Unity project for Android TV and Fire TV that utilizes the new input system released in v2019.3.

Fire TV's button mappings in the old system were as follows:

Back                    KeyCode.Escape
Select (D-Pad Center)   KeyCode.JoystickButton0
Left (D-Pad)            KeyCode.LeftArrow
Right (D-Pad)           KeyCode.RightArrow
Up (D-Pad)              KeyCode.UpArrow
Down (D-Pad)            KeyCode.DownArrow

I've successfully mapped everything but Select/D-Pad Center with the following Binding Paths in the new system:

Escape [Keyboard]
Right Arrow [Keyboard]
Left Arrow [Keyboard]
Up Arrow [Keyboard]
Down Arrow [Keyboard]

If I map to Any Key [Keyboard] and implement the following code as the callback, it shows up as key: JoystickButton0, which matches Amazon's documentation, but doesn't exist as an option in the new system under keyboard binding paths:

public void DebugKey(InputAction.CallbackContext context)
{
    foreach(KeyCode vKey in System.Enum.GetValues(typeof(KeyCode))){
         if(Input.GetKey(vKey)){
             Debug.Log ("key: " + vKey);
         }
    }
}

I've tried various buttons under Gamepad, Android Gamepad, Joystick, and Android Joystick without any success. Another odd thing is that the Center/D-Pad works fine on UI Buttons without any binding.

What is the proper way to map to the legacy KeyCode.JoystickButtonX naming convention with the new input system?

Thanks!

stephenspann
  • 1,823
  • 1
  • 16
  • 31
  • the new system works with HID, so for stick, button0 doesnt exist, its begins at 1 and its name is Trigger..then button2 its name is "Button 2"....so what do you expected? i dont really understand your problem... – Frenchy May 22 '20 at 14:36
  • you want to trap a specific button of joystick with the new input system? – Frenchy May 22 '20 at 16:38
  • Did you manage to solve this? I only found that you need to use the Legacy Input to get the center button on the Fire TV. Input.GetKeyDown(KeyCode.Joystick1Button0). I check some test examples from the Input System Package it need the UnityEngine.Input. I think is better to override the Behavior of this controller via Android java, the back button it just return "Esc" from the keyboard, so maybe an Android plugin can solve this better. When the Fire TV press Center button we can change to "Enter" from the keyboard. This also make usable Backward, Forward and Play/Pause button usable. – OscarLeif Oct 02 '20 at 00:25

2 Answers2

1

In order to fully map the Amazon Fire Tv controller using Unity with the new input system you need a Custom device.

With this script you can get all the buttons work. It's also possible to get the volume up, volume down and Mute. But I don't think it's a good idea override this buttons.

using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Scripting;
 
#if UNITY_EDITOR
using UnityEditor;
#endif
 
[Preserve]
public struct AftvRemoteDeviceState : IInputStateTypeInfo
{
    public FourCC format => new FourCC('A', 'G', 'C');
 
    //Mapped Here
    [InputControl(name = "dPadUpButton", layout = "Button", bit = 19, displayName = "Dpad Up")]
    [InputControl(name = "dPadRightButton", layout = "Button", bit = 22, displayName = "Dpad Right")]
    [InputControl(name = "dPadDownButton", layout = "Button", bit = 20, displayName = "Dpad Down")]
    [InputControl(name = "dPadLeftButton", layout = "Button", bit = 21, displayName = "Dpad Left")]
    //[InputControl(name = "backButton", layout = "Button", bit = 4, displayName = "Back Button")]
    [InputControl(name = "menuButton", layout = "Button", bit = 82, displayName = "Menu Button")]
    //Non Maped
    [InputControl(name = "selectButton", layout = "Button", bit = 23, displayName = "Select Button")]
    [InputControl(name = "rewindButton", layout = "Button", bit = 89, displayName = "Rewind Button")]
    [InputControl(name = "playPauseButton", layout = "Button", bit = 85, displayName = "Play Pause Button")]
    [InputControl(name = "fastForwardButton", layout = "Button", bit = 90, displayName = "Fast Forward Button")]
    public uint buttons;
}
 
#if UNITY_EDITOR
[InitializeOnLoad] // Call static class constructor in editor.
#endif
[Preserve]
[InputControlLayout(displayName = "Aftv Remote", stateType = typeof(AftvRemoteDeviceState))]
public class AftvRemoteDevice : InputDevice
{
#if UNITY_EDITOR
    static AftvRemoteDevice()
    {
        Initialize();
    }
#endif
 
    [RuntimeInitializeOnLoadMethod]
    private static void Initialize()
    {
        InputSystem.RegisterLayout<AftvRemoteDevice>
            (
                matches: new InputDeviceMatcher()
                .WithInterface("Android")
                .WithDeviceClass("AndroidGameController")
                .WithProduct("Amazon Fire TV Remote")
            );
    }
 
    public ButtonControl dPadUpButton { get; private set; }
    public ButtonControl dPadRightButton { get; private set; }
    public ButtonControl dPadDownButton { get; private set; }
    public ButtonControl dPadLeftButton { get; private set; }
    public ButtonControl selectButton { get; private set; }
    public ButtonControl rewindButton { get; private set; }
    public ButtonControl playPauseButton { get; private set; }
    public ButtonControl fastForwardButton { get; private set; }
    //public ButtonControl backButton { get; private set; }
    public ButtonControl menuButton { get; private set; }
    public bool SelectButtonDown { get; set; }
    public bool RewindButtonDown { get; set; }
    public bool PlayPauseButtonDown { get; set; }
    public bool FastForwardButtonDown { get; set; }
 
    protected override void FinishSetup()
    {
        base.FinishSetup();
        dPadUpButton = GetChildControl<ButtonControl>("dPadUpButton");
        dPadRightButton = GetChildControl<ButtonControl>("dPadRightButton");
        dPadDownButton = GetChildControl<ButtonControl>("dPadDownButton");
        dPadLeftButton = GetChildControl<ButtonControl>("dPadLeftButton");
 
        rewindButton = GetChildControl<ButtonControl>("rewindButton");
        playPauseButton = GetChildControl<ButtonControl>("playPauseButton");
        fastForwardButton = GetChildControl<ButtonControl>("fastForwardButton");
 
        //backButton = GetChildControl<ButtonControl>("backButton");
        menuButton = GetChildControl<ButtonControl>("menuButton");
        selectButton = GetChildControl<ButtonControl>("selectButton");    
    }
 
    public static AftvRemoteDevice current { get; private set; }
 
    public override void MakeCurrent()
    {
        base.MakeCurrent();
        current = this;
    }
 
    protected override void OnRemoved()
    {
        base.OnRemoved();
        if (current == this)
            current = null;
    }
 
    #region Editor
#if UNITY_EDITOR
    [MenuItem("Tools/AftvRemote/Create Device")]
    private static void CreateDevice()
    {
        InputSystem.AddDevice<AftvRemoteDevice>();
    }
    [MenuItem("Tools/AftvRemote/Remove Device")]
    private static void RemoveDevice()
    {
        var customDevice = InputSystem.devices.FirstOrDefault(x => x is AftvRemoteDevice);
        if (customDevice != null)
            InputSystem.RemoveDevice(customDevice);
    }
#endif
    #endregion
}

The bit values are the same Constant values from the Android API. You can check the list Here You only need to Include this script in the project setup your Input Actions and Input Action map.

For some reason the Player Input component have issues. But for UI navigation this works nice also it works fine with the Input Debugger.

OscarLeif
  • 894
  • 1
  • 9
  • 17
0

In New system, the devices are read as HID, the KeyCode is not useful, so if you want to read the status of button of joystick, you could do that:

using UnityEngine.InputSystem;


public Joystick joy;

void Start()
{
     joy = Joystick.current;
}

void FixedUpdate()
{
    var button2 = joy.allControls[2].IsPressed();
    if (button2)
    {
        Debug.Log("Button2 of current joystick is pushed");
    }
}

If you want to map the button0 (in old inputsystem), its now the button1 or trigger

var button1 = joy.allControls[1].IsPressed();

or

var button1 = joy.trigger.IsPressed();

And you could test buttons of more sticks..

void Start()
{
    var ListOfJoys = Joystick.all;
     joy = Joystick.current;//here current joy is ListOfJoys[1]
     otherjoy = ListOfJoys[0];
}


    var Buttons = joy.allControls;


    if ((Buttons[2] as ButtonControl).wasPressedThisFrame)
    {
        Debug.Log("b2 pressed during this frame");
    }
    if ((Buttons[2] as ButtonControl).wasReleasedThisFrame)
    {
        Debug.Log("b2 released during this frame");
    }
    if (joy.trigger.wasPressedThisFrame)
    {
        Debug.Log("trig or button1 pressed during this frame");
    }
    if (joy.trigger.wasReleasedThisFrame)
    {
        Debug.Log("trig or button1 released during this fram");
    }
    if (otherjoy.trigger.wasPressedThisFrame)
    {
        Debug.Log("otherjoy trigger");
    }

the other way is to use the mapping of new system, i have mapped the action press Only Test1 to button3 of stick

enter image description here

that simplify the code and you could mix event and direct test:

//Newinputsystem is a name of class generated 
private Newinputsystem playerAction;

void Awake()
{
    playerAction = new Newinputsystem();
    playerAction.Player.Test1.performed += ctx => FireTest();
}

void FixedUpdate()
{
    if (playerAction.Player.Test1.triggered)
    {
        Debug.Log("fire!!!");
    }
}

public void FireTest()
{
    Debug.Log("i am in firetest");
}

private void OnEnable()
{
    playerAction.Enable();
}
private void OnDisable()
{
    playerAction.Disable();
}

so you could add new action test2 which will be triggered with action release only for button3...

TO display the HID device, go to menu Window/analysis/input debbugger

you have to see your device (here mine is hotas)

enter image description here

and you click on it and in the tab item HID Descriptor

enter image description here

so i suppose you have selected your device in project setting:

enter image description here

Frenchy
  • 16,386
  • 3
  • 16
  • 39
  • I am trying to use mapping like your screenshot - the main issue is there is not a Path option that syncs up with the Fire TV remote's center button (where your screenshot says 'Button 3 [Joystick - HOTAS Warthog]')... I can get the back button (keyboard escape works) and the direction buttons (keyboard arrows work) but the center select button doesn't seem to map up with anything available to me under 'Path'. – stephenspann Sep 01 '20 at 18:51
  • could you display the hid definition of your device? – Frenchy Sep 02 '20 at 15:03
  • I wasn't able to get the HID definition from Unity (don't know how?). I was able to output the Joystick Name "Amazon Fire TV Remote" and loop through `allControls` which makes it look like a button is missing (verified trigger is the back button): Button:/AndroidJoystick1/trigger, Stick:/AndroidJoystick1/stick, Button:/AndroidJoystick1/stick/up, Axis:/AndroidJoystick1/stick/x, Axis:/AndroidJoystick1/stick/y, Button:/AndroidJoystick1/stick/down, Button:/AndroidJoystick1/stick/left, Button:/AndroidJoystick1/stick/right – stephenspann Sep 02 '20 at 19:18
  • to display the HID of your device, i have updated my answer – Frenchy Sep 04 '20 at 13:54