public void Actions_CanApplyBindingOverridesToMap_WhenEnabled() { var keyboard = InputSystem.AddDevice <Keyboard>(); var gamepad = InputSystem.AddDevice <Gamepad>(); var map = new InputActionMap(); var action = map.AddAction("action1", binding: "<Keyboard>/enter"); map.Enable(); Assert.That(action.controls, Is.EquivalentTo(new[] { keyboard.enterKey })); map.ApplyBindingOverrides(new List <InputBinding> { new InputBinding { action = "action1", overridePath = "<Gamepad>/leftTrigger" } }); Assert.That(action.bindings[0].overridePath, Is.EqualTo("<Gamepad>/leftTrigger")); Assert.That(action.controls, Is.EquivalentTo(new[] { gamepad.leftTrigger })); }
/// <summary> /// Create an action map with the given name and add it to the asset. /// </summary> /// <param name="asset">Asset to add the action map to</param> /// <param name="name">Name to assign to the </param> /// <returns>The newly added action map.</returns> /// <exception cref="ArgumentNullException"><paramref name="asset"/> is <c>null</c> or /// <exception cref="InvalidOperationException">An action map with the given <paramref name="name"/> /// already exists in <paramref name="asset"/>.</exception> /// <paramref name="name"/> is <c>null</c> or empty.</exception> public static InputActionMap AddActionMap(this InputActionAsset asset, string name) { if (asset == null) { throw new ArgumentNullException(nameof(asset)); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } if (asset.FindActionMap(name) != null) { throw new InvalidOperationException( $"An action map called '{name}' already exists in the asset"); } var map = new InputActionMap(name); map.GenerateId(); asset.AddActionMap(map); return(map); }
public void Editor_RenamingAction_WillAutomaticallyEnsureUniqueNames() { var map = new InputActionMap("set1"); map.AddAction("actionA", binding: "<Gamepad>/leftStick"); map.AddAction("actionB"); var asset = ScriptableObject.CreateInstance <InputActionAsset>(); asset.AddActionMap(map); var obj = new SerializedObject(asset); var mapProperty = obj.FindProperty("m_ActionMaps").GetArrayElementAtIndex(0); var action1Property = mapProperty.FindPropertyRelative("m_Actions").GetArrayElementAtIndex(0); InputActionSerializationHelpers.RenameAction(action1Property, mapProperty, "actionB"); obj.ApplyModifiedPropertiesWithoutUndo(); Assert.That(map.actions[1].name, Is.EqualTo("actionB")); Assert.That(map.actions[0].name, Is.EqualTo("actionB1")); Assert.That(map.actions[0].bindings, Has.Count.EqualTo(1)); Assert.That(map.actions[0].bindings[0].action, Is.EqualTo("actionB1")); }
/// <summary> /// Apply the given binding override to all bindings in the map that are matched by the override. /// </summary> /// <param name="actionMap"></param> /// <param name="bindingOverride"></param> /// <returns>The number of bindings overridden in the given map.</returns> /// <exception cref="ArgumentNullException"><paramref name="actionMap"/> is <c>null</c>.</exception> /// <exception cref="InvalidOperationException"><paramref name="actionMap"/> is currently enabled.</exception> /// <remarks> /// </remarks> public static int ApplyBindingOverride(this InputActionMap actionMap, InputBinding bindingOverride) { if (actionMap == null) { throw new ArgumentNullException(nameof(actionMap)); } actionMap.ThrowIfModifyingBindingsIsNotAllowed(); var bindings = actionMap.m_Bindings; if (bindings == null) { return(0); } // Go through all bindings in the map and match them to the override. var bindingCount = bindings.Length; var matchCount = 0; for (var i = 0; i < bindingCount; ++i) { if (!bindingOverride.Matches(ref bindings[i])) { continue; } // Set overrides on binding. bindings[i].overridePath = bindingOverride.overridePath; bindings[i].overrideInteractions = bindingOverride.overrideInteractions; ++matchCount; } if (matchCount > 0) { actionMap.LazyResolveBindings(); } return(matchCount); }
public void Editor_InputAsset_CanAddAndRemoveBindingThroughSerialization() { var map = new InputActionMap("set"); map.AddAction(name: "action1", binding: "/gamepad/leftStick"); map.AddAction(name: "action2", binding: "/gamepad/rightStick"); var asset = ScriptableObject.CreateInstance <InputActionAsset>(); asset.AddActionMap(map); var obj = new SerializedObject(asset); var mapProperty = obj.FindProperty("m_ActionMaps").GetArrayElementAtIndex(0); var action1Property = mapProperty.FindPropertyRelative("m_Actions").GetArrayElementAtIndex(0); InputActionSerializationHelpers.AppendBinding(action1Property, mapProperty); obj.ApplyModifiedPropertiesWithoutUndo(); // Maps and actions aren't UnityEngine.Objects so the modifications will not // be in-place. Look up the actions after each apply. var action1 = asset.actionMaps[0].TryGetAction("action1"); var action2 = asset.actionMaps[0].TryGetAction("action2"); Assert.That(action1.bindings, Has.Count.EqualTo(2)); Assert.That(action1.bindings[0].path, Is.EqualTo("/gamepad/leftStick")); Assert.That(action1.bindings[1].path, Is.EqualTo("")); Assert.That(action1.bindings[1].interactions, Is.EqualTo("")); Assert.That(action1.bindings[1].groups, Is.EqualTo("")); Assert.That(action2.bindings[0].path, Is.EqualTo("/gamepad/rightStick")); InputActionSerializationHelpers.RemoveBinding(action1Property, 1, mapProperty); obj.ApplyModifiedPropertiesWithoutUndo(); action1 = asset.actionMaps[0].TryGetAction("action1"); action2 = asset.actionMaps[0].TryGetAction("action2"); Assert.That(action1.bindings, Has.Count.EqualTo(1)); Assert.That(action1.bindings[0].path, Is.EqualTo("/gamepad/leftStick")); Assert.That(action2.bindings[0].path, Is.EqualTo("/gamepad/rightStick")); }
public void Actions_CanPerformPressInteraction_AndTriggerInteractionResetInCallback() { var keyboard = InputSystem.AddDevice <Keyboard>(); var asset = ScriptableObject.CreateInstance <InputActionAsset>(); var map1 = new InputActionMap("map1"); var map2 = new InputActionMap("map2"); asset.AddActionMap(map1); asset.AddActionMap(map2); var action1 = map1.AddAction("action1"); var action2 = map2.AddAction("action2"); // PressInteraction used to set some local state *after* trigger callbacks. This meant that if the // callback triggered a Reset() call, PressInteraction would then overwrite state from the reset. action1.AddBinding("<Keyboard>/a", interactions: "press(behavior=0)"); action2.AddBinding("<Keyboard>/b", interactions: "press(behavior=0)"); action1.performed += _ => { map1.Disable(); map2.Enable(); }; action2.performed += _ => { map2.Disable(); map1.Enable(); }; map1.Enable(); PressAndRelease(keyboard.aKey); Assert.That(map1.enabled, Is.False); Assert.That(map2.enabled, Is.True); PressAndRelease(keyboard.bKey); Assert.That(map1.enabled, Is.True); Assert.That(map2.enabled, Is.False); PressAndRelease(keyboard.aKey); Assert.That(map1.enabled, Is.False); Assert.That(map2.enabled, Is.True); }
void Awake() { if (Instance == null) { Instance = this; } else { Destroy(this); } _inputs = GetComponent <PlayerInput>(); playerActions = _inputs.actions.FindActionMap("Player", true); uiActions = _inputs.actions.FindActionMap("UI", true); playerMove = playerActions.FindAction("Move"); playerLook = playerActions.FindAction("Look"); playerJump = playerActions.FindAction("Jump"); playerRoll = playerActions.FindAction("Roll"); playerDash = playerActions.FindAction("Dash"); cycleTarget = playerActions.FindAction("CycleTarget"); playerAttack = playerActions.FindAction("Attack"); mousePosition = uiActions.FindAction("MousePosition"); playerActions.Disable(); playerJump.performed += OnJump_Pressed; playerJump.canceled += OnJump_Released; playerRoll.performed += OnRoll_Pressed; playerRoll.canceled += OnRoll_Released; playerDash.performed += OnDash_Pressed; playerDash.canceled += OnDash_Released; playerAttack.performed += OnAttack_Pressed; playerAttack.canceled += OnAttack_Released; cycleTarget.performed += OnCycleTarget_Pressed; }
public void Editor_CanPrettyPrintJSON() { var map = new InputActionMap("map"); map.AddAction("action", binding: "<Gamepad>/leftStick"); var json = InputActionMap.ToJson(new[] { map }); var prettyJson = StringHelpers.PrettyPrintJSON(json); Assert.That(prettyJson, Does.StartWith( @"{ ""maps"" : [ { ""name"" : ""map"", ""actions"" : [ { ""name"" : ""action"", ""expectedControlLayout"" : """", ""bindings"" : [ ] ")); // Doing it again should not result in a difference. prettyJson = StringHelpers.PrettyPrintJSON(prettyJson); Assert.That(prettyJson, Does.StartWith( @"{ ""maps"" : [ { ""name"" : ""map"", ""actions"" : [ { ""name"" : ""action"", ""expectedControlLayout"" : """", ""bindings"" : [ ] ")); }
public static void AddActionMapFromObject(SerializedObject asset, InputActionMap map) { var mapArrayProperty = asset.FindProperty("m_ActionMaps"); var mapCount = mapArrayProperty.arraySize; var index = mapCount; var name = FindUniqueName(mapArrayProperty, map.name); mapArrayProperty.InsertArrayElementAtIndex(index); var mapProperty = mapArrayProperty.GetArrayElementAtIndex(index); mapProperty.FindPropertyRelative("m_Actions").ClearArray(); mapProperty.FindPropertyRelative("m_Bindings").ClearArray(); mapProperty.FindPropertyRelative("m_Name").stringValue = name; for (var i = 0; i < map.actions.Count; i++) { var newActionProperty = AddActionFromObject(map.actions[i], mapProperty); for (var j = 0; j < map.actions[i].bindings.Count; j++) { AppendBindingFromObject(map.actions[i].bindings[j], newActionProperty, mapProperty); } } }
public void Editor_InputAsset_CanAddActionMapFromObject() { var map = new InputActionMap("set"); var binding = new InputBinding(); binding.path = "some path"; var action = map.AddAction("action"); action.AppendBinding(binding); var asset = ScriptableObject.CreateInstance <InputActionAsset>(); var obj = new SerializedObject(asset); Assert.That(asset.actionMaps, Has.Count.EqualTo(0)); InputActionSerializationHelpers.AddActionMapFromObject(obj, map); obj.ApplyModifiedPropertiesWithoutUndo(); Assert.That(asset.actionMaps, Has.Count.EqualTo(1)); Assert.That(asset.actionMaps[0].name, Is.EqualTo("set")); Assert.That(asset.actionMaps[0].actions[0].name, Is.EqualTo("action")); Assert.That(asset.actionMaps[0].actions[0].bindings[0].path, Is.EqualTo("some path")); }
public static int ApplyBindingOverridesOnMatchingControls(this InputActionMap actionMap, InputControl control) { if (actionMap == null) { throw new ArgumentNullException(nameof(actionMap)); } if (control == null) { throw new ArgumentNullException(nameof(control)); } var actions = actionMap.actions; var actionCount = actions.Count; var numMatchingControls = 0; for (var i = 0; i < actionCount; ++i) { var action = actions[i]; numMatchingControls = action.ApplyBindingOverridesOnMatchingControls(control); } return(numMatchingControls); }
public void Init(string name, InputActionMap map) { if (hasInit) { return; } title.text = name; actionMap = map; foreach (InputAction action in actionMap.actions) { if (action.name.StartsWith("+")) { continue; //Filter keybinds that should not be modified (Designated with + prefix) } //Spawn a copy of the keybind object, and init them with input action data. OptionsInputActionController keybind = Instantiate(keybindPrefab.gameObject, transform) .GetComponent <OptionsInputActionController>(); keybind.Init(action); } keybindPrefab.gameObject.SetActive(false); layoutGroup.spacing = layoutGroup.spacing; hasInit = true; }
public void Actions_CanRemoveBindingOverridesFromMaps() { var map = new InputActionMap(); var action1 = map.AddAction("action1", binding: "/<keyboard>/enter"); var action2 = map.AddAction("action2", binding: "/<gamepad>/buttonSouth"); var overrides = new List <InputBinding> { new InputBinding { action = "action2", overridePath = "/gamepad/rightTrigger" }, new InputBinding { action = "action1", overridePath = "/gamepad/leftTrigger" } }; map.ApplyBindingOverrides(overrides); overrides.RemoveAt(1); // Leave only override for action2. map.RemoveBindingOverrides(overrides); Assert.That(action1.bindings[0].overridePath, Is.EqualTo("/gamepad/leftTrigger")); Assert.That(action2.bindings[0].overridePath, Is.Null); // Should have been removed. }
internal static IActuator[] CreateActuatorsFromMap(InputActionMap inputActionMap, BehaviorParameters behaviorParameters, InputDevice inputDevice) { var actuators = new IActuator[inputActionMap.actions.Count]; for (var i = 0; i < inputActionMap.actions.Count; i++) { var action = inputActionMap.actions[i]; var actionLayout = InputSystem.LoadLayout(action.expectedControlType); var adaptor = (IRLActionInputAdaptor)Activator.CreateInstance(controlTypeToAdaptorType[actionLayout.type]); actuators[i] = new InputActionActuator(inputDevice, behaviorParameters, action, adaptor); // Reasonably, the input system starts adding numbers after the first none numbered name // is added. So for device ID of 0, we use the empty string in the path. var path = $"{inputDevice?.path}{InputControlPath.Separator}{action.name}"; action.AddBinding(path, action.interactions, action.processors, mlAgentsControlSchemeName); } return(actuators); }
public void Action_WithMultipleInteractions_DoesNotThrowWhenUsingMultipleMaps() { var gamepad = InputSystem.AddDevice <Gamepad>(); var map1 = new InputActionMap("map1"); var map2 = new InputActionMap("map2"); map1.AddAction(name: "action1", type: InputActionType.Button, binding: "<Gamepad>/buttonSouth"); map2.AddAction(name: "action2", type: InputActionType.Button, binding: "<Gamepad>/buttonNorth", interactions: "press,hold(duration=0.4)"); var asset = ScriptableObject.CreateInstance <InputActionAsset>(); asset.AddActionMap(map1); asset.AddActionMap(map2); map2.Enable(); Assert.DoesNotThrow(() => { Press(gamepad.buttonNorth); Release(gamepad.buttonNorth); }); }
// Start is called before the first frame update void Start() { das = PlayerPrefs.GetInt("DAS"); arr = PlayerPrefs.GetInt("ARR"); sdg = PlayerPrefs.GetFloat("SDG"); rotateDCD = PlayerPrefs.GetInt("rotateDCD"); harddropDCD = PlayerPrefs.GetInt("harddropDCD"); holdDCD = PlayerPrefs.GetInt("holdDCD"); DASinterruption = PlayerPrefs.GetInt("interruptDAS") == 1; //A somewhat odd way of typcasting an int to a bool... //Set player keybinds into a mapping. This mapping's actions aren't linked to any method calls; it's just used as a way to store bindings. map = ref_PlayerInput.actions.FindActionMap("BindStorage"); map.FindAction("Shift left").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyLeft")); map.FindAction("Shift right").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyRight")); map.FindAction("Soft drop").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keySoftDrop")); map.FindAction("Hard drop").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyHardDrop")); map.FindAction("Rotate CW").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyCW")); map.FindAction("Rotate CCW").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyCCW")); map.FindAction("Rotate 180").ChangeBinding(0).WithPath(PlayerPrefs.GetString("key180")); map.FindAction("Hold").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyHold")); map.FindAction("Pause").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyPause")); map.FindAction("Reset").ChangeBinding(0).WithPath(PlayerPrefs.GetString("keyReset")); //Debug.Log(map.actions[0].bindings[0].path); totalBindings = map.actions.Count; }
void chagebind() { InputActionMap iam = input.input.Get(); InputAction[] ia = iam.actions.ToArray(); input.Disable(); for (int i = 0; i < ia.Length; i++) { if (PlayerPrefs.HasKey(ia[i].name + "0")) { int pref0 = PlayerPrefs.GetInt(ia[i].name + "0"); if (KeyCodes[pref0] == null) { ia[i].ApplyBindingOverride(0, "<>/"); } else { string[] path = KeyCodes[pref0].path.Split('/'); ia[i].ApplyBindingOverride(0, "<" + path[1] + ">/" + path[2]); } int pref1 = PlayerPrefs.GetInt(ia[i].name + "1"); if (KeyCodes[pref1] == null) { ia[i].ApplyBindingOverride(1, "<>/"); } else { string[] path = KeyCodes[PlayerPrefs.GetInt(ia[i].name + "1")].path.Split('/'); ia[i].ApplyBindingOverride(1, "<" + path[1] + ">/" + path[2]); } } } input.Enable(); }
private void LoadPlayerTwoBinds(InputActionMap inputMap) { List <UserData.BindingSerializable> playerTwoBindingList; if (userData.GetKeyboardBindingList(out playerTwoBindingList)) { Dictionary <System.Guid, string> overrides = new Dictionary <System.Guid, string>(); foreach (var item in playerTwoBindingList) { overrides.Add(new System.Guid(item.id), item.path); } var bindings = inputMap.bindings; for (int i = 0; i < bindings.Count; ++i) { if (overrides.TryGetValue(bindings[i].id, out string overridePath)) { inputMap.ApplyBindingOverride(i, new InputBinding { overridePath = overridePath }); } } } }
/// <summary> /// Remove the given action map from the asset. /// </summary> /// <param name="asset">Asset to add the action map to.</param> /// <param name="map">An action map. If the given map is not part of the asset, the method /// does nothing.</param> /// <exception cref="ArgumentNullException"><paramref name="asset"/> or <paramref name="map"/> is <c>null</c>.</exception> /// <exception cref="InvalidOperationException"><paramref name="map"/> is currently enabled (see <see /// cref="InputActionMap.enabled"/>).</exception> /// <seealso cref="RemoveActionMap(InputActionAsset,string)"/> /// <seealso cref="InputActionAsset.actionMaps"/> public static void RemoveActionMap(this InputActionAsset asset, InputActionMap map) { if (asset == null) { throw new ArgumentNullException(nameof(asset)); } if (map == null) { throw new ArgumentNullException(nameof(map)); } if (map.enabled) { throw new InvalidOperationException("Cannot remove an action map from the asset while it is enabled"); } // Ignore if not part of this asset. if (map.m_Asset != asset) { return; } ArrayHelpers.Erase(ref asset.m_ActionMaps, map); map.m_Asset = null; }
// Start is called before the first frame update void Start() { // Pjum = JumpAmount; gravity = Physics.gravity; onFootMap = actionsAssests.FindActionMap("OnFoot"); onFootMap.Enable(); moveAction = onFootMap.FindAction("Move"); jumpAction = onFootMap.FindAction("Jump"); crouchAction = onFootMap.FindAction("Crouch"); moveAction.performed += context => OnMove(context); moveAction.canceled += ctx => OnMove(ctx); jumpAction.performed += context => OnJump(context); jumpAction.canceled += ctx => OnJump(ctx); crouchAction.performed += context => OnCrouch(context); crouchAction.canceled += ctx => OnCrouch(ctx); }
private void Awake() { mPlayerActionMap = mActionAsset.FindActionMap("Key"); RegisterInputAction(); mPlayerActionMap.Enable(); }
internal BindingSyntax(InputActionMap map, InputAction action, int bindingIndex) { m_ActionMap = map; m_Action = action; m_BindingIndex = bindingIndex; }
internal CompositeSyntax(InputActionMap map, InputAction action, int compositeIndex) { m_Action = action; m_ActionMap = map; m_CompositeIndex = compositeIndex; }
void RegisterInputs() { #if USE_INPUT_SYSTEM var map = new InputActionMap("Free Camera"); lookAction = map.AddAction("look", binding: "<Mouse>/delta"); moveAction = map.AddAction("move", binding: "<Gamepad>/leftStick"); speedAction = map.AddAction("speed", binding: "<Gamepad>/dpad"); yMoveAction = map.AddAction("yMove"); lookAction.AddBinding("<Gamepad>/rightStick").WithProcessor("scaleVector2(x=15, y=15)"); moveAction.AddCompositeBinding("Dpad") .With("Up", "<Keyboard>/w") .With("Up", "<Keyboard>/upArrow") .With("Down", "<Keyboard>/s") .With("Down", "<Keyboard>/downArrow") .With("Left", "<Keyboard>/a") .With("Left", "<Keyboard>/leftArrow") .With("Right", "<Keyboard>/d") .With("Right", "<Keyboard>/rightArrow"); speedAction.AddCompositeBinding("Dpad") .With("Up", "<Keyboard>/home") .With("Down", "<Keyboard>/end"); yMoveAction.AddCompositeBinding("Dpad") .With("Up", "<Keyboard>/pageUp") .With("Down", "<Keyboard>/pageDown") .With("Up", "<Keyboard>/e") .With("Down", "<Keyboard>/q") .With("Up", "<Gamepad>/rightshoulder") .With("Down", "<Gamepad>/leftshoulder"); moveAction.Enable(); lookAction.Enable(); speedAction.Enable(); fireAction.Enable(); yMoveAction.Enable(); #endif #if UNITY_EDITOR && !USE_INPUT_SYSTEM List <InputManagerEntry> inputEntries = new List <InputManagerEntry>(); // Add new bindings inputEntries.Add(new InputManagerEntry { name = kRightStickX, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Fourth, sensitivity = 1.0f, gravity = 1.0f, deadZone = 0.2f }); inputEntries.Add(new InputManagerEntry { name = kRightStickY, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Fifth, sensitivity = 1.0f, gravity = 1.0f, deadZone = 0.2f, invert = true }); inputEntries.Add(new InputManagerEntry { name = kYAxis, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "page up", altBtnPositive = "joystick button 5", btnNegative = "page down", altBtnNegative = "joystick button 4", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }); inputEntries.Add(new InputManagerEntry { name = kYAxis, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "q", btnNegative = "e", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }); inputEntries.Add(new InputManagerEntry { name = kSpeedAxis, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "home", btnNegative = "end", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }); inputEntries.Add(new InputManagerEntry { name = kSpeedAxis, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Seventh, gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }); InputRegistering.RegisterInputs(inputEntries); #endif }
public PlayerInputActions() { asset = InputActionAsset.FromJson(@"{ ""name"": ""PlayerInputActions"", ""maps"": [ { ""name"": ""Player"", ""id"": ""de43ca36-e2cd-4353-adc4-cfdfc8a92147"", ""actions"": [ { ""name"": ""FireAction"", ""type"": ""Button"", ""id"": ""ec20e427-03da-46bd-ad88-661d5c69f632"", ""expectedControlType"": ""Button"", ""processors"": """", ""interactions"": """" }, { ""name"": ""SkillAction"", ""type"": ""Button"", ""id"": ""8fd1c5db-a516-4a29-8168-2dfa7fc7705f"", ""expectedControlType"": ""Button"", ""processors"": """", ""interactions"": """" }, { ""name"": ""Horizontal"", ""type"": ""Button"", ""id"": ""aa60f257-41b9-4395-9936-0b2f2f0f3928"", ""expectedControlType"": ""Button"", ""processors"": """", ""interactions"": """" }, { ""name"": ""MousePos"", ""type"": ""Value"", ""id"": ""84c74cb1-73d5-4238-a3c5-ec2fb6404ef6"", ""expectedControlType"": ""Vector2"", ""processors"": """", ""interactions"": """" } ], ""bindings"": [ { ""name"": """", ""id"": ""af8acf16-1664-4f60-af13-fbc605ec1e4a"", ""path"": ""<Keyboard>/q"", ""interactions"": """", ""processors"": """", ""groups"": """", ""action"": ""FireAction"", ""isComposite"": false, ""isPartOfComposite"": false }, { ""name"": """", ""id"": ""31743faa-f932-47d1-8ab0-4fb5d437f98b"", ""path"": ""<Keyboard>/e"", ""interactions"": """", ""processors"": """", ""groups"": """", ""action"": ""SkillAction"", ""isComposite"": false, ""isPartOfComposite"": false }, { ""name"": ""1D Axis"", ""id"": ""c94d57a3-675a-4e86-a90c-ed0da0977c09"", ""path"": ""1DAxis"", ""interactions"": ""Press(behavior=2)"", ""processors"": """", ""groups"": """", ""action"": ""Horizontal"", ""isComposite"": true, ""isPartOfComposite"": false }, { ""name"": ""negative"", ""id"": ""89596dc3-dce4-4e21-94dd-bbaf072fc604"", ""path"": ""<Keyboard>/a"", ""interactions"": """", ""processors"": """", ""groups"": """", ""action"": ""Horizontal"", ""isComposite"": false, ""isPartOfComposite"": true }, { ""name"": ""positive"", ""id"": ""ca8383a4-13c5-478e-87dd-bb95c680d7a1"", ""path"": ""<Keyboard>/d"", ""interactions"": """", ""processors"": """", ""groups"": """", ""action"": ""Horizontal"", ""isComposite"": false, ""isPartOfComposite"": true }, { ""name"": """", ""id"": ""fa7d9de7-c891-4967-9ff7-890b449019bb"", ""path"": ""<Mouse>/position"", ""interactions"": """", ""processors"": """", ""groups"": """", ""action"": ""MousePos"", ""isComposite"": false, ""isPartOfComposite"": false } ] } ], ""controlSchemes"": [] }"); // Player m_Player = asset.FindActionMap("Player", true); m_Player_FireAction = m_Player.FindAction("FireAction", true); m_Player_SkillAction = m_Player.FindAction("SkillAction", true); m_Player_Horizontal = m_Player.FindAction("Horizontal", true); m_Player_MousePos = m_Player.FindAction("MousePos", true); }
public void Editor_CanConvertInputActionsToSteamIGAFormat() { var asset = ScriptableObject.CreateInstance <InputActionAsset>(); var actionMap1 = new InputActionMap("map1"); var actionMap2 = new InputActionMap("map2"); actionMap1.AddAction("buttonAction", expectedControlLayout: "Button"); actionMap1.AddAction("axisAction", expectedControlLayout: "Axis"); actionMap1.AddAction("stickAction", expectedControlLayout: "Stick"); actionMap2.AddAction("vector2Action", expectedControlLayout: "Vector2"); asset.AddActionMap(actionMap1); asset.AddActionMap(actionMap2); var vdf = SteamIGAConverter.ConvertInputActionsToSteamIGA(asset); var dictionary = SteamIGAConverter.ParseVDF(vdf); // Top-level key "In Game Actions". Assert.That(dictionary.Count, Is.EqualTo(1)); Assert.That(dictionary, Contains.Key("In Game Actions").With.TypeOf <Dictionary <string, object> >()); // "actions" and "localization" inside "In Game Actions". var inGameActions = (Dictionary <string, object>)dictionary["In Game Actions"]; Assert.That(inGameActions, Contains.Key("actions")); Assert.That(inGameActions["actions"], Is.TypeOf <Dictionary <string, object> >()); Assert.That(inGameActions, Contains.Key("localization")); Assert.That(inGameActions["localization"], Is.TypeOf <Dictionary <string, object> >()); Assert.That(inGameActions.Count, Is.EqualTo(2)); // Two action maps inside "actions". var actions = (Dictionary <string, object>)inGameActions["actions"]; Assert.That(actions, Contains.Key("map1")); Assert.That(actions["map1"], Is.TypeOf <Dictionary <string, object> >()); Assert.That(actions, Contains.Key("map2")); Assert.That(actions["map2"], Is.TypeOf <Dictionary <string, object> >()); Assert.That(actions.Count, Is.EqualTo(2)); // Three actions inside "map1". var map1 = (Dictionary <string, object>)actions["map1"]; Assert.That(map1, Contains.Key("title")); Assert.That(map1, Contains.Key("StickPadGyro")); Assert.That(map1, Contains.Key("AnalogTrigger")); Assert.That(map1, Contains.Key("Button")); Assert.That(map1.Count, Is.EqualTo(4)); Assert.That(map1["title"], Is.EqualTo("#Set_map1")); Assert.That(map1["StickPadGyro"], Is.TypeOf <Dictionary <string, object> >()); Assert.That(map1["AnalogTrigger"], Is.TypeOf <Dictionary <string, object> >()); Assert.That(map1["Button"], Is.TypeOf <Dictionary <string, object> >()); var stickPadGyro1 = (Dictionary <string, object>)map1["StickPadGyro"]; Assert.That(stickPadGyro1, Has.Count.EqualTo(1)); Assert.That(stickPadGyro1, Contains.Key("stickAction")); Assert.That(stickPadGyro1["stickAction"], Is.TypeOf <Dictionary <string, object> >()); var stickAction = (Dictionary <string, object>)stickPadGyro1["stickAction"]; Assert.That(stickAction, Contains.Key("title")); Assert.That(stickAction, Contains.Key("input_mode")); Assert.That(stickAction.Count, Is.EqualTo(2)); Assert.That(stickAction["title"], Is.EqualTo("#Action_map1_stickAction")); Assert.That(stickAction["input_mode"], Is.EqualTo("joystick_move")); // One action inside "map2". var map2 = (Dictionary <string, object>)actions["map2"]; Assert.That(map2, Contains.Key("title")); Assert.That(map2["title"], Is.EqualTo("#Set_map2")); // Localization strings. var localization = (Dictionary <string, object>)inGameActions["localization"]; Assert.That(localization.Count, Is.EqualTo(1)); Assert.That(localization, Contains.Key("english")); Assert.That(localization["english"], Is.TypeOf <Dictionary <string, object> >()); var english = (Dictionary <string, object>)localization["english"]; Assert.That(english, Contains.Key("Set_map1")); Assert.That(english, Contains.Key("Set_map2")); Assert.That(english, Contains.Key("Action_map1_buttonAction")); Assert.That(english, Contains.Key("Action_map1_axisAction")); Assert.That(english, Contains.Key("Action_map1_stickAction")); Assert.That(english, Contains.Key("Action_map2_vector2Action")); Assert.That(english["Set_map1"], Is.EqualTo("map1")); Assert.That(english["Set_map2"], Is.EqualTo("map2")); Assert.That(english["Action_map1_buttonAction"], Is.EqualTo("buttonAction")); Assert.That(english["Action_map1_axisAction"], Is.EqualTo("axisAction")); Assert.That(english["Action_map1_stickAction"], Is.EqualTo("stickAction")); Assert.That(english["Action_map2_vector2Action"], Is.EqualTo("vector2Action")); Assert.That(english.Count, Is.EqualTo(6)); }
public ActionMapTreeItem(InputActionMap actionMap, SerializedProperty actionMapProperty, int index) : base(actionMapProperty, index) { m_ActionMap = actionMap; displayName = elementProperty.FindPropertyRelative("m_Name").stringValue; id = displayName.GetHashCode(); }
public IEnumerator Actions_CanDriveUI() { // Create devices. var gamepad = InputSystem.AddDevice <Gamepad>(); var mouse = InputSystem.AddDevice <Mouse>(); // Set up GameObject with EventSystem. var systemObject = new GameObject("System"); var eventSystem = systemObject.AddComponent <TestEventSystem>(); var uiModule = systemObject.AddComponent <UIActionInputModule>(); eventSystem.UpdateModules(); eventSystem.InvokeUpdate(); // Initial update only sets current module. // Set up canvas on which we can perform raycasts. var canvasObject = new GameObject("Canvas"); var canvas = canvasObject.AddComponent <Canvas>(); canvas.renderMode = RenderMode.ScreenSpaceCamera; canvasObject.AddComponent <GraphicRaycaster>(); var cameraObject = new GameObject("Camera"); var camera = cameraObject.AddComponent <Camera>(); canvas.worldCamera = camera; camera.pixelRect = new Rect(0, 0, 640, 480); // Set up a GameObject hierarchy that we send events to. In a real setup, // this would be a hierarchy involving UI components. var parentGameObject = new GameObject("Parent"); var parentTransform = parentGameObject.AddComponent <RectTransform>(); parentGameObject.AddComponent <UICallbackReceiver>(); var leftChildGameObject = new GameObject("Left Child"); var leftChildTransform = leftChildGameObject.AddComponent <RectTransform>(); leftChildGameObject.AddComponent <Image>(); var leftChildReceiver = leftChildGameObject.AddComponent <UICallbackReceiver>(); var rightChildGameObject = new GameObject("Right Child"); var rightChildTransform = rightChildGameObject.AddComponent <RectTransform>(); rightChildGameObject.AddComponent <Image>(); var rightChildReceiver = rightChildGameObject.AddComponent <UICallbackReceiver>(); parentTransform.SetParent(canvas.transform, worldPositionStays: false); leftChildTransform.SetParent(parentTransform, worldPositionStays: false); rightChildTransform.SetParent(parentTransform, worldPositionStays: false); // Parent occupies full space of canvas. parentTransform.sizeDelta = new Vector2(640, 480); // Left child occupies left half of parent. leftChildTransform.anchoredPosition = new Vector2(-(640 / 4), 0); leftChildTransform.sizeDelta = new Vector2(320, 480); // Right child occupies right half of parent. rightChildTransform.anchoredPosition = new Vector2(640 / 4, 0); rightChildTransform.sizeDelta = new Vector2(320, 480); // Create actions. var map = new InputActionMap(); var pointAction = map.AddAction("point"); var moveAction = map.AddAction("move"); var submitAction = map.AddAction("submit"); var cancelAction = map.AddAction("cancel"); var leftClickAction = map.AddAction("leftClick"); var rightClickAction = map.AddAction("rightClick"); var middleClickAction = map.AddAction("middleClick"); var scrollAction = map.AddAction("scroll"); // Create bindings. pointAction.AddBinding(mouse.position); leftClickAction.AddBinding(mouse.leftButton); rightClickAction.AddBinding(mouse.rightButton); middleClickAction.AddBinding(mouse.middleButton); scrollAction.AddBinding(mouse.scroll); moveAction.AddBinding(gamepad.leftStick); submitAction.AddBinding(gamepad.buttonSouth); cancelAction.AddBinding(gamepad.buttonEast); // Wire up actions. // NOTE: In a normal usage scenario, the user would wire these up in the inspector. uiModule.point = new InputActionProperty(pointAction); uiModule.move = new InputActionProperty(moveAction); uiModule.submit = new InputActionProperty(submitAction); uiModule.cancel = new InputActionProperty(cancelAction); uiModule.leftClick = new InputActionProperty(leftClickAction); uiModule.middleClick = new InputActionProperty(middleClickAction); uiModule.rightClick = new InputActionProperty(rightClickAction); uiModule.scrollWheel = new InputActionProperty(scrollAction); // Enable the whole thing. map.Enable(); // We need to wait a frame to let the underlying canvas update and properly order the graphics images for raycasting. yield return(null); // Move mouse over left child. InputSystem.QueueStateEvent(mouse, new MouseState { position = new Vector2(100, 100) }); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Enter)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Check basic down/up InputSystem.QueueStateEvent(mouse, new MouseState { position = new Vector2(100, 100), buttons = (ushort)(1 << (int)MouseState.Button.Left) }); InputSystem.QueueStateEvent(mouse, new MouseState { position = new Vector2(100, 100), buttons = (ushort)0 }); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(4)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Down)); Assert.That(leftChildReceiver.events[1].type, Is.EqualTo(EventType.PotentialDrag)); Assert.That(leftChildReceiver.events[2].type, Is.EqualTo(EventType.Up)); Assert.That(leftChildReceiver.events[3].type, Is.EqualTo(EventType.Click)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Check down and drag InputSystem.QueueStateEvent(mouse, new MouseState { position = new Vector2(100, 100), buttons = (ushort)(1 << (int)MouseState.Button.Right) }); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(2)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Down)); Assert.That(leftChildReceiver.events[1].type, Is.EqualTo(EventType.PotentialDrag)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Move to new location on left child InputSystem.QueueDeltaStateEvent(mouse.position, new Vector2(100, 200)); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(2)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.BeginDrag)); Assert.That(leftChildReceiver.events[1].type, Is.EqualTo(EventType.Dragging)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Move children InputSystem.QueueDeltaStateEvent(mouse.position, new Vector2(400, 200)); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(2)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Exit)); Assert.That(leftChildReceiver.events[1].type, Is.EqualTo(EventType.Dragging)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(rightChildReceiver.events[0].type, Is.EqualTo(EventType.Enter)); rightChildReceiver.Reset(); // Release button InputSystem.QueueStateEvent(mouse, new MouseState { position = new Vector2(400, 200), buttons = (ushort)0 }); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(2)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Up)); Assert.That(leftChildReceiver.events[1].type, Is.EqualTo(EventType.EndDrag)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(rightChildReceiver.events[0].type, Is.EqualTo(EventType.Drop)); rightChildReceiver.Reset(); // Check Scroll InputSystem.QueueDeltaStateEvent(mouse.scroll, Vector2.one); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(0)); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(rightChildReceiver.events[0].type, Is.EqualTo(EventType.Scroll)); rightChildReceiver.Reset(); // Reset Scroll InputSystem.QueueDeltaStateEvent(mouse.scroll, Vector2.zero); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(0)); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(rightChildReceiver.events[0].type, Is.EqualTo(EventType.Scroll)); rightChildReceiver.Reset(); // Test Selection eventSystem.SetSelectedGameObject(leftChildGameObject); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Select)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Check Move Axes InputSystem.QueueDeltaStateEvent(gamepad.leftStick, new Vector2(1.0f, 0.0f)); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Move)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Check Submit InputSystem.QueueStateEvent(gamepad, new GamepadState { buttons = (uint)(1 << (int)GamepadState.Button.South) }); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Submit)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Check Cancel InputSystem.QueueStateEvent(gamepad, new GamepadState { buttons = (uint)(1 << (int)GamepadState.Button.East) }); InputSystem.Update(); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Cancel)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(0)); // Check Selection Swap eventSystem.SetSelectedGameObject(rightChildGameObject); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(leftChildReceiver.events[0].type, Is.EqualTo(EventType.Deselect)); leftChildReceiver.Reset(); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(rightChildReceiver.events[0].type, Is.EqualTo(EventType.Select)); rightChildReceiver.Reset(); // Check Deselect eventSystem.SetSelectedGameObject(null); eventSystem.InvokeUpdate(); Assert.That(leftChildReceiver.events, Has.Count.EqualTo(0)); Assert.That(rightChildReceiver.events, Has.Count.EqualTo(1)); Assert.That(rightChildReceiver.events[0].type, Is.EqualTo(EventType.Deselect)); rightChildReceiver.Reset(); }
public unsafe void AddActionMap(InputActionMap map) { Debug.Assert(map != null, "Received null map"); var actionsInThisMap = map.m_Actions; var bindingsInThisMap = map.m_Bindings; var bindingCountInThisMap = bindingsInThisMap?.Length ?? 0; var actionCountInThisMap = actionsInThisMap?.Length ?? 0; var mapIndex = totalMapCount; // Keep track of indices for this map. var actionStartIndex = totalActionCount; var bindingStartIndex = totalBindingCount; var controlStartIndex = totalControlCount; var interactionStartIndex = totalInteractionCount; var processorStartIndex = totalProcessorCount; var compositeStartIndex = totalCompositeCount; // Allocate an initial block of memory. We probably will have to re-allocate once // at the end to accommodate interactions and controls added from the map. var newMemory = new InputActionState.UnmanagedMemory(); newMemory.Allocate( mapCount: totalMapCount + 1, actionCount: totalActionCount + actionCountInThisMap, bindingCount: totalBindingCount + bindingCountInThisMap, // We reallocate for the following once we know the final count. interactionCount: totalInteractionCount, compositeCount: totalCompositeCount, controlCount: totalControlCount); if (memory.isAllocated) { newMemory.CopyDataFrom(memory); } ////TODO: make sure composite objects get all the bindings they need ////TODO: handle case where we have bindings resolving to the same control //// (not so clear cut what to do there; each binding may have a different interaction setup, for example) var currentCompositeBindingIndex = InputActionState.kInvalidIndex; var currentCompositeIndex = InputActionState.kInvalidIndex; var currentCompositePartCount = 0; var currentCompositeActionIndexInMap = InputActionState.kInvalidIndex; InputAction currentCompositeAction = null; var bindingMaskOnThisMap = map.m_BindingMask; var devicesForThisMap = map.devices; // Can't use `using` as we need to use it with `ref`. var resolvedControls = new InputControlList <InputControl>(Allocator.Temp); // We gather all controls in temporary memory and then move them over into newMemory once // we're done resolving. try { for (var n = 0; n < bindingCountInThisMap; ++n) { var bindingStatesPtr = newMemory.bindingStates; ref var unresolvedBinding = ref bindingsInThisMap[n]; var bindingIndex = bindingStartIndex + n; var isComposite = unresolvedBinding.isComposite; var isPartOfComposite = !isComposite && unresolvedBinding.isPartOfComposite; var bindingState = &bindingStatesPtr[bindingIndex]; try { ////TODO: if it's a composite, check if any of the children matches our binding masks (if any) and skip composite if none do var firstControlIndex = 0; // numControls dictates whether this is a valid index or not. var firstInteractionIndex = InputActionState.kInvalidIndex; var firstProcessorIndex = InputActionState.kInvalidIndex; var actionIndexForBinding = InputActionState.kInvalidIndex; var partIndex = InputActionState.kInvalidIndex; var numControls = 0; var numInteractions = 0; var numProcessors = 0; // Make sure that if it's part of a composite, we are actually part of a composite. if (isPartOfComposite && currentCompositeBindingIndex == InputActionState.kInvalidIndex) { throw new InvalidOperationException( $"Binding '{unresolvedBinding}' is marked as being part of a composite but the preceding binding is not a composite"); } // Try to find action. // // NOTE: We ignore actions on bindings that are part of composites. We only allow // actions to be triggered from the composite itself. var actionIndexInMap = InputActionState.kInvalidIndex; var actionName = unresolvedBinding.action; InputAction action = null; if (!isPartOfComposite) { if (!string.IsNullOrEmpty(actionName)) { ////REVIEW: should we fail here if we don't manage to find the action actionIndexInMap = map.FindActionIndex(actionName); } else if (map.m_SingletonAction != null) { // Special-case for singleton actions that don't have names. actionIndexInMap = 0; } if (actionIndexInMap != InputActionState.kInvalidIndex) { action = actionsInThisMap[actionIndexInMap]; } } else { actionIndexInMap = currentCompositeActionIndexInMap; action = currentCompositeAction; } // If it's a composite, start a chain. if (isComposite) { currentCompositeBindingIndex = bindingIndex; currentCompositeAction = action; currentCompositeActionIndexInMap = actionIndexInMap; } // Determine if the binding is disabled. // Disabled if path is empty. var path = unresolvedBinding.effectivePath; var bindingIsDisabled = string.IsNullOrEmpty(path) // Also, if we can't find the action to trigger for the binding, we just go and disable // the binding. || action == null // Also, disabled if binding doesn't match with our binding mask (might be empty). || (!isComposite && bindingMask != null && !bindingMask.Value.Matches(ref unresolvedBinding, InputBinding.MatchOptions.EmptyGroupMatchesAny)) // Also, disabled if binding doesn't match the binding mask on the map (might be empty). || (!isComposite && bindingMaskOnThisMap != null && !bindingMaskOnThisMap.Value.Matches(ref unresolvedBinding, InputBinding.MatchOptions.EmptyGroupMatchesAny)) // Finally, also disabled if binding doesn't match the binding mask on the action (might be empty). || (!isComposite && action?.m_BindingMask != null && !action.m_BindingMask.Value.Matches(ref unresolvedBinding, InputBinding.MatchOptions.EmptyGroupMatchesAny)); // If the binding isn't disabled, resolve its controls, processors, and interactions. if (!bindingIsDisabled) { // Instantiate processors. var processorString = unresolvedBinding.effectiveProcessors; if (!string.IsNullOrEmpty(processorString)) { // Add processors from binding. firstProcessorIndex = ResolveProcessors(processorString); if (firstProcessorIndex != InputActionState.kInvalidIndex) { numProcessors = totalProcessorCount - firstProcessorIndex; } } if (!string.IsNullOrEmpty(action.m_Processors)) { // Add processors from action. var index = ResolveProcessors(action.m_Processors); if (index != InputActionState.kInvalidIndex) { if (firstProcessorIndex == InputActionState.kInvalidIndex) { firstProcessorIndex = index; } numProcessors += totalProcessorCount - index; } } // Instantiate interactions. var interactionString = unresolvedBinding.effectiveInteractions; if (!string.IsNullOrEmpty(interactionString)) { // Add interactions from binding. firstInteractionIndex = ResolveInteractions(interactionString); if (firstInteractionIndex != InputActionState.kInvalidIndex) { numInteractions = totalInteractionCount - firstInteractionIndex; } } if (!string.IsNullOrEmpty(action.m_Interactions)) { // Add interactions from action. var index = ResolveInteractions(action.m_Interactions); if (index != InputActionState.kInvalidIndex) { if (firstInteractionIndex == InputActionState.kInvalidIndex) { firstInteractionIndex = index; } numInteractions += totalInteractionCount - index; } } // If it's the start of a composite chain, create the composite. Otherwise, go and // resolve controls for the binding. if (isComposite) { // The composite binding entry itself does not resolve to any controls. // It creates a composite binding object which is then populated from // subsequent bindings. // Instantiate. For composites, the path is the name of the composite. var composite = InstantiateBindingComposite(unresolvedBinding.path); currentCompositeIndex = ArrayHelpers.AppendWithCapacity(ref composites, ref totalCompositeCount, composite); // Record where the controls for parts of the composite start. firstControlIndex = memory.controlCount + resolvedControls.Count; } else { // If we've reached the end of a composite chain, finish // off the current composite. if (!isPartOfComposite && currentCompositeBindingIndex != InputActionState.kInvalidIndex) { currentCompositePartCount = 0; currentCompositeBindingIndex = InputActionState.kInvalidIndex; currentCompositeIndex = InputActionState.kInvalidIndex; currentCompositeAction = null; currentCompositeActionIndexInMap = InputActionState.kInvalidIndex; } // Look up controls. // // NOTE: We continuously add controls here to `resolvedControls`. Once we've completed our // pass over the bindings in the map, `resolvedControls` will have all the controls for // the current map. firstControlIndex = memory.controlCount + resolvedControls.Count; if (devicesForThisMap != null) { // Search in devices for only this map. var list = devicesForThisMap.Value; for (var i = 0; i < list.Count; ++i) { var device = list[i]; if (!device.added) { continue; // Skip devices that have been removed. } numControls += InputControlPath.TryFindControls(device, path, 0, ref resolvedControls); } } else { // Search globally. numControls = InputSystem.FindControls(path, ref resolvedControls); } } } // If the binding is part of a composite, pass the resolved controls // on to the composite. if (isPartOfComposite && currentCompositeBindingIndex != InputActionState.kInvalidIndex && numControls > 0) { // Make sure the binding is named. The name determines what in the composite // to bind to. if (string.IsNullOrEmpty(unresolvedBinding.name)) { throw new InvalidOperationException( $"Binding '{unresolvedBinding}' that is part of composite '{composites[currentCompositeIndex]}' is missing a name"); } // Give a part index for the partIndex = AssignCompositePartIndex(composites[currentCompositeIndex], unresolvedBinding.name, ref currentCompositePartCount); // Keep track of total number of controls bound in the composite. bindingStatesPtr[currentCompositeBindingIndex].controlCount += numControls; // Force action index on part binding to be same as that of composite. actionIndexForBinding = bindingStatesPtr[currentCompositeBindingIndex].actionIndex; } else if (actionIndexInMap != InputActionState.kInvalidIndex) { actionIndexForBinding = actionStartIndex + actionIndexInMap; } // Store resolved binding. *bindingState = new InputActionState.BindingState { controlStartIndex = firstControlIndex, // For composites, this will be adjusted as we add each part. controlCount = numControls, interactionStartIndex = firstInteractionIndex, interactionCount = numInteractions, processorStartIndex = firstProcessorIndex, processorCount = numProcessors, isComposite = isComposite, isPartOfComposite = unresolvedBinding.isPartOfComposite, partIndex = partIndex, actionIndex = actionIndexForBinding, compositeOrCompositeBindingIndex = isComposite ? currentCompositeIndex : currentCompositeBindingIndex, mapIndex = totalMapCount, wantsInitialStateCheck = action?.wantsInitialStateCheck ?? false }; } catch (Exception exception) { Debug.LogError( $"{exception.GetType().Name} while resolving binding '{unresolvedBinding}' in action map '{map}'"); Debug.LogException(exception); // Don't swallow exceptions that indicate something is wrong in the code rather than // in the data. if (exception.IsExceptionIndicatingBugInCode()) { throw; } } } // Re-allocate memory to accommodate controls and interaction states. The count for those // we only know once we've completed all resolution. var controlCountInThisMap = resolvedControls.Count; var newTotalControlCount = memory.controlCount + controlCountInThisMap; if (newMemory.interactionCount != totalInteractionCount || newMemory.compositeCount != totalCompositeCount || newMemory.controlCount != newTotalControlCount) { var finalMemory = new InputActionState.UnmanagedMemory(); finalMemory.Allocate( mapCount: newMemory.mapCount, actionCount: newMemory.actionCount, bindingCount: newMemory.bindingCount, controlCount: newTotalControlCount, interactionCount: totalInteractionCount, compositeCount: totalCompositeCount); finalMemory.CopyDataFrom(newMemory); newMemory.Dispose(); newMemory = finalMemory; } // Add controls to array. var controlCountInArray = memory.controlCount; ArrayHelpers.AppendListWithCapacity(ref controls, ref controlCountInArray, resolvedControls); Debug.Assert(controlCountInArray == newTotalControlCount, "Control array should have combined count of old and new controls"); // Set up control to binding index mapping. for (var i = 0; i < bindingCountInThisMap; ++i) { var bindingStatesPtr = newMemory.bindingStates; var bindingState = &bindingStatesPtr[bindingStartIndex + i]; var numControls = bindingState->controlCount; var startIndex = bindingState->controlStartIndex; for (var n = 0; n < numControls; ++n) { newMemory.controlIndexToBindingIndex[startIndex + n] = bindingStartIndex + i; } } // Initialize initial interaction states. for (var i = memory.interactionCount; i < newMemory.interactionCount; ++i) { newMemory.interactionStates[i].phase = InputActionPhase.Waiting; } // Initialize action data. var runningIndexInBindingIndices = memory.bindingCount; for (var i = 0; i < actionCountInThisMap; ++i) { var action = actionsInThisMap[i]; var actionIndex = actionStartIndex + i; // Correlate action with its trigger state. action.m_ActionIndexInState = actionIndex; // Collect bindings for action. var bindingStartIndexForAction = runningIndexInBindingIndices; var bindingCountForAction = 0; var numPossibleConcurrentActuations = 0; for (var n = 0; n < bindingCountInThisMap; ++n) { var bindingIndex = bindingStartIndex + n; var bindingState = &newMemory.bindingStates[bindingIndex]; if (bindingState->actionIndex != actionIndex) { continue; } if (bindingState->isPartOfComposite) { continue; } Debug.Assert(bindingIndex <= ushort.MaxValue, "Binding index exceeds limit"); newMemory.actionBindingIndices[runningIndexInBindingIndices] = (ushort)bindingIndex; ++runningIndexInBindingIndices; ++bindingCountForAction; // Keep track of how many concurrent actuations we may be seeing on the action so that // we know whether we need to enable conflict resolution or not. if (bindingState->isComposite) { // Composite binding. Actuates as a whole. Check if the composite has successfully // resolved any controls. If so, it adds one possible actuation. if (bindingState->controlCount > 0) { ++numPossibleConcurrentActuations; } } else { // Normal binding. Every successfully resolved control results in one possible actuation. numPossibleConcurrentActuations += bindingState->controlCount; } } Debug.Assert(bindingStartIndexForAction < ushort.MaxValue, "Binding start index on action exceeds limit"); Debug.Assert(bindingCountForAction < ushort.MaxValue, "Binding count on action exceeds limit"); newMemory.actionBindingIndicesAndCounts[actionIndex * 2] = (ushort)bindingStartIndexForAction; newMemory.actionBindingIndicesAndCounts[actionIndex * 2 + 1] = (ushort)bindingCountForAction; // See if we may need conflict resolution on this action. Never needed for pass-through actions. // Otherwise, if we have more than one bound control or have several bindings and one of them // is a composite, we enable it. var isPassThroughAction = action.type == InputActionType.PassThrough; var isButtonAction = action.type == InputActionType.Button; var mayNeedConflictResolution = !isPassThroughAction && numPossibleConcurrentActuations > 1; // Initialize initial trigger state. newMemory.actionStates[actionIndex] = new InputActionState.TriggerState { phase = InputActionPhase.Disabled, mapIndex = mapIndex, controlIndex = InputActionState.kInvalidIndex, interactionIndex = InputActionState.kInvalidIndex, isPassThrough = isPassThroughAction, isButton = isButtonAction, mayNeedConflictResolution = mayNeedConflictResolution, }; } // Store indices for map. newMemory.mapIndices[mapIndex] = new InputActionState.ActionMapIndices { actionStartIndex = actionStartIndex, actionCount = actionCountInThisMap, controlStartIndex = controlStartIndex, controlCount = controlCountInThisMap, bindingStartIndex = bindingStartIndex, bindingCount = bindingCountInThisMap, interactionStartIndex = interactionStartIndex, interactionCount = totalInteractionCount - interactionStartIndex, processorStartIndex = processorStartIndex, processorCount = totalProcessorCount - processorStartIndex, compositeStartIndex = compositeStartIndex, compositeCount = totalCompositeCount - compositeStartIndex, }; map.m_MapIndexInState = mapIndex; var finalActionMapCount = memory.mapCount; ArrayHelpers.AppendWithCapacity(ref maps, ref finalActionMapCount, map, capacityIncrement: 4); Debug.Assert(finalActionMapCount == newMemory.mapCount, "Final action map count should match old action map count plus one"); // As a final act, swap the new memory in. memory.Dispose(); memory = newMemory; }
public bool UsesActionMap(InputActionMap actionMap) { return(actionMap == mouseActionMap || actionMap == keyboardActionMap); }