在新的 Unity 输入系统中如何映射到 KeyCode.JoystickButton0?

Posted

技术标签:

【中文标题】在新的 Unity 输入系统中如何映射到 KeyCode.JoystickButton0?【英文标题】:How do you map to KeyCode.JoystickButton0 in the new Unity Input System? 【发布时间】:2020-08-30 02:38:27 【问题描述】:

我正在为 android TV 和 Fire TV 开发一个 Unity 项目,该项目利用 v2019.3 中发布的新输入系统。

Fire TV's button mappings在旧系统中如下:

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

我已经成功地在新系统中使用以下绑定路径映射了除 Select/D-Pad Center 之外的所有内容:

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

如果我映射到Any Key [Keyboard] 并实现以下代码作为回调,它将显示为key: JoystickButton0,这与亚马逊的文档相匹配,但在新系统中的键盘绑定路径下不作为选项存在:

public void DebugKey(InputAction.CallbackContext context)

    foreach(KeyCode vKey in System.Enum.GetValues(typeof(KeyCode)))
         if(Input.GetKey(vKey))
             Debug.Log ("key: " + vKey);
         
    

我尝试过Gamepad、Android Gamepad、Joystick和Android Joystick下的各种按钮,但均未成功。另一个奇怪的事情是,中心/方向键在没有任何绑定的 UI 按钮上工作正常。

使用新输入系统映射到旧版 KeyCode.JoystickButtonX 命名约定的正确方法是什么?

谢谢!

【问题讨论】:

新系统与HID一起工作,所以对于stick,button0不存在,它从1开始,它的名字是Trigger..然后button2它的名字是“Button 2”......所以怎么办你期待吗?我真的不明白你的问题... 您想用新的输入系统来捕捉操纵杆的特定按钮吗? 你解决了吗?我只发现您需要使用旧版输入来获取 Fire TV 上的中心按钮。 Input.GetKeyDown(KeyCode.Joystick1Button0)。我从需要 UnityEngine.Input 的输入系统包中检查了一些测试示例。我认为最好通过Android java覆盖这个控制器的行为,它只是从键盘返回“Esc”的后退按钮,所以也许Android插件可以更好地解决这个问题。当 Fire TV 按下中心按钮时,我们可以从键盘更改为“Enter”。这也使可用的后退、前进和播放/暂停按钮可用。 【参考方案1】:

要使用 Unity 将 Amazon Fire Tv 控制器与新输入系统完全映射,您需要一个自定义设备。

使用此脚本,您可以使所有按钮正常工作。 也可以提高音量、降低音量和静音。但我认为覆盖此按钮不是一个好主意。

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

位值是相同的来自 Android API 的常量值。 您可以查看列表Here 您只需在项目设置中包含此脚本即可设置您的输入操作和输入操作映射。

由于某些原因,播放器输入组件存在问题。 但是对于 UI 导航,这很好用,它也适用于 Input Debugger。

【讨论】:

【参考方案2】:

在新系统中,设备被读取为HID,KeyCode没有用,所以如果你想读取摇杆按钮的状态,你可以这样做:

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");
    

如果你想映射 button0(在旧的输入系统中),它现在是 button1 或触发器

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

var button1 = joy.trigger.IsPressed();

你可以测试更多棒的按钮..

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");
    

另一种方法是使用新系统的映射,我已经将动作press OnlyTest1映射到了stick的button3

简化代码,您可以混合使用事件和直接测试:

//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();

这样您就可以添加新的动作 test2,该动作将由动作 release only for button3 触发...

要显示 HID 设备,请转到菜单窗口/分析/输入调试器

您必须查看您的设备(这里我的是 hotas)

然后单击它并在选项卡项 HID 描述符中

所以我想你已经在项目设置中选择了你的设备:

【讨论】:

我正在尝试像您的屏幕截图一样使用映射 - 主要问题是没有与 Fire TV 遥控器的中心按钮同步的路径选项(您的屏幕截图显示“按钮 3 [操纵杆 - HOTAS Warthog]')...我可以得到后退按钮(键盘转义有效)和方向按钮(键盘箭头有效),但中心选择按钮似乎没有映射到“路径”下我可用的任何东西。 你能显示你设备的隐藏定义吗? 我无法从 Unity 获取 HID 定义(不知道如何?)。我能够输出操纵杆名称“Amazon Fire TV Remote”并循环通过allControls,这使得它看起来像缺少一个按钮(已验证触发器是后退按钮):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 显示您设备的 HID,我已经更新了我的答案

以上是关于在新的 Unity 输入系统中如何映射到 KeyCode.JoystickButton0?的主要内容,如果未能解决你的问题,请参考以下文章

在新的 Unity 网络中进行“直接”RPC 样式调用?

编辑器中的 Unity 触摸事件? (新的输入系统)

如何使用新的输入系统访问点击(桌面)/点击(移动)位置?

Unity新的输入系统没有被触发

Unity Visual Effect Graph入门与实践

如何在新的 AppDomain 中运行从加载到引用的程序集的方法