void DisableActionsForControl(InputControl control, InputActionsProcessor inputActionsProcessor)
        {
            foreach (var action in inputActionsProcessor.inputActions)
            {
                if (action == null)
                {
                    continue;
                }

                foreach (var otherControl in action.controls) //TODO Should use active control instead of all controls?
                {
                    if (!control.path.Contains(otherControl.path) && !otherControl.path.Contains(control.path))
                    {
                        continue;
                    }

                    // Disable will send a cancelled callback to started actions, but that will be consumed for our listeners. Manually invoke those callbacks now
                    action.Disable();
                    var startedOrPerformed = action.phase == InputActionPhase.Started || action.phase == InputActionPhase.Performed;
                    if (startedOrPerformed && m_ActionListeners.TryGetValue(action, out var listeners))
                    {
                        foreach (var listener in listeners.cancelledCallbacks)
                        {
                            try
                            {
                                listener.Invoke();
                            }
                            catch (Exception exception)
                            {
                                Debug.LogException(exception);
                            }
                        }
                    }

                    if (m_ConsumedActions.TryGetValue(control, out var list))
                    {
                        if (!list.Contains(action))
                        {
                            list.Add(action);
                        }
                    }
                    else
                    {
                        m_ConsumedActions.Add(control, new List <InputAction>()
                        {
                            action
                        });
                    }
                }
            }
        }
        InputActionAsset IProvidesInputActions.CreateActions(IUsesInputActions user, InputDevice device)
        {
            var actionsAsset = user.inputActionsAsset;

            if (actionsAsset == null)
            {
                return(null);
            }

            var inputActions = Instantiate(actionsAsset);

            if (inputActions == null)
            {
                return(null);
            }

            if (device != null)
            {
                inputActions.devices = new[] { device }
            }
            ;

            inputActions.Enable();

            var order = 0;

            var attributes            = user.GetType().GetCustomAttributes(typeof(ProcessInputAttribute), true);
            var processInputAttribute = attributes.Length > 0 ? (ProcessInputAttribute)attributes[0] : null;

            if (processInputAttribute != null)
            {
                order = processInputAttribute.order;
            }

            var inputActionsProcessor = new InputActionsProcessor {
                user = user, inputActions = inputActions, order = order, actionsAsset = actionsAsset
            };

            m_InputProcessors.Add(inputActionsProcessor);
            m_InputProcessors.Sort((a, b) => a.order.CompareTo(b.order)); //TODO Implicit ordering tool stack priority

            // New action map needs to disable any actions bound to currently locked controls
            foreach (var lockedControl in m_LockedControls)
            {
                DisableActionsForControl(lockedControl.Key, inputActionsProcessor);
            }

            user.OnActionsCreated(inputActions);

            return(inputActions);
        }
        void SendEventsToInputProcessor(InputActionsProcessor inputActionsProcessor)
        {
            if (m_AccumulatedStartedEvents.TryGetValue(inputActionsProcessor.user, out var startEvents))
            {
                foreach (var eventContext in startEvents)
                {
                    if (m_ActionListeners.TryGetValue(eventContext.action, out var listeners))
                    {
                        ExecuteActionListeners(eventContext, listeners.startedCallbacks);
                    }
                }

                startEvents.Clear(); //TODO  events that were consumed should be held onto in case a control wants to cancel a consumption and allow the past events to now be sent retroactively.
            }

            if (m_AccumulatedPerformedEvents.TryGetValue(inputActionsProcessor.user, out var performEvents))
            {
                foreach (var eventContext in performEvents)
                {
                    if (m_ActionListeners.TryGetValue(eventContext.action, out var listeners))
                    {
                        ExecuteActionListeners(eventContext, listeners.performedCallbacks);
                    }
                }

                performEvents.Clear();
            }

            if (m_AccumulatedCanceledEvents.TryGetValue(inputActionsProcessor.user, out var cancelEvents))
            {
                foreach (var eventContext in cancelEvents)
                {
                    if (m_ActionListeners.TryGetValue(eventContext.action, out var listeners))
                    {
                        ExecuteActionListeners(eventContext, listeners.cancelledCallbacks);
                    }
                }

                cancelEvents.Clear();
            }
        }