示例#1
0
 public static void QueueEvent(InputEventPtr eventPtr)
 {
     NativeInputSystem.QueueInputEvent(eventPtr.data);
 }
        public static unsafe void WriteValueFromObjectIntoEvent(this InputControl control, InputEventPtr eventPtr, object value)
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }

            var statePtr = control.GetStatePtrFromStateEvent(eventPtr);

            if (statePtr == null)
            {
                return;
            }

            control.WriteValueFromObjectIntoState(value, statePtr);
        }
        public static unsafe void WriteValueIntoEvent <TValue>(this InputControl <TValue> control, TValue value, InputEventPtr eventPtr)
            where TValue : struct
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }
            if (!eventPtr.valid)
            {
                throw new ArgumentNullException(nameof(eventPtr));
            }

            var statePtr = control.GetStatePtrFromStateEvent(eventPtr);

            if (statePtr == null)
            {
                return;
            }

            control.WriteValueIntoState(value, statePtr);
        }
 void QueueEvent(InputEventPtr iep)
 {
     InputSystem.QueueEvent(iep);
 }
        public static TValue ReadUnprocessedValueFromEvent <TValue>(this InputControl <TValue> control, InputEventPtr eventPtr)
            where TValue : struct
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }

            var result = default(TValue);

            control.ReadUnprocessedValueFromEvent(eventPtr, out result);
            return(result);
        }
示例#6
0
 /// <summary>
 /// Implements <see cref="IInputStateCallbackReceiver.OnStateEvent"/> for the mouse.
 /// </summary>
 /// <param name="eventPtr"></param>
 protected new unsafe void OnStateEvent(InputEventPtr eventPtr)
 {
     scroll.AccumulateValueInEvent(currentStatePtr, eventPtr);
     base.OnStateEvent(eventPtr);
 }
示例#7
0
 bool IInputStateCallbackReceiver.GetStateOffsetForEvent(InputControl control, InputEventPtr eventPtr, ref uint offset)
 {
     return(false);
 }
示例#8
0
 public void OnEventFormatMismatch(InputEventPtr eventPtr, InputDevice device)
 {
     Debug.LogError(string.Format("'{0}' input event for device '{1}' has incorrect format (event format: '{2}', device format: '{3}')",
                                  eventPtr.type, device, eventPtr.type, device.stateBlock.format));
 }
示例#9
0
 public void OnEventForDisabledDevice(InputEventPtr eventPtr, InputDevice device)
 {
     Debug.LogError(string.Format("Device '{1}' received input event '{0}' but the device is disabled",
                                  eventPtr, device));
 }
            private unsafe void OnEvent(InputEventPtr eventPtr)
            {
                // Ignore if not a state event.
                if (!eventPtr.IsA <StateEvent>() && !eventPtr.IsA <DeltaStateEvent>())
                {
                    return;
                }

                // Fetch device.
                var device = InputSystem.GetDeviceById(eventPtr.deviceId);

                if (device == null)
                {
                    return;
                }

                // Go through controls and see if there's anything interesting in the event.
                var controls              = device.allControls;
                var controlCount          = controls.Count;
                var haveChangedCandidates = false;

                for (var i = 0; i < controlCount; ++i)
                {
                    var control = controls[i];

                    // Skip controls that have no state in the event.
                    var statePtr = control.GetStatePtrFromStateEvent(eventPtr);
                    if (statePtr == null)
                    {
                        continue;
                    }

                    // If the control that cancels has been actuated, abort the operation now.
                    if (!string.IsNullOrEmpty(m_CancelBinding) && InputControlPath.Matches(m_CancelBinding, control) &&
                        !control.CheckStateIsAtDefault(statePtr) && control.HasValueChangeInState(statePtr))
                    {
                        OnCancel();
                        break;
                    }

                    // Skip noisy controls.
                    if (control.noisy && (m_Flags & Flags.DontIgnoreNoisyControls) == 0)
                    {
                        continue;
                    }

                    // If controls have to match a certain path, check if this one does.
                    if (m_IncludePathCount > 0 && !HavePathMatch(control, m_IncludePaths, m_IncludePathCount))
                    {
                        continue;
                    }

                    // If controls must not match certain path, make sure the control doesn't.
                    if (m_ExcludePathCount > 0 && HavePathMatch(control, m_ExcludePaths, m_ExcludePathCount))
                    {
                        continue;
                    }

                    // If we're expecting controls of a certain type, skip if control isn't of
                    // the right type.
                    if (m_ControlType != null && !m_ControlType.IsInstanceOfType(control))
                    {
                        continue;
                    }

                    // If we're expecting controls to be based on a specific layout, skip if control
                    // isn't based on that layout.
                    if (!m_ExpectedLayout.IsEmpty() &&
                        m_ExpectedLayout != control.m_Layout &&
                        !InputControlLayout.s_Layouts.IsBasedOn(m_ExpectedLayout, control.m_Layout))
                    {
                        continue;
                    }

                    // Skip controls that are in their default state.
                    // NOTE: This is the cheapest check with respect to looking at actual state. So
                    //       do this first before looking further at the state.
                    if (control.CheckStateIsAtDefault(statePtr))
                    {
                        continue;
                    }

                    // Skip controls that have no effective value change.
                    // NOTE: This will run the full processor stack and is more involved.
                    if (!control.HasValueChangeInState(statePtr))
                    {
                        continue;
                    }

                    // If we have a magnitude threshold, see if control passes it.
                    var magnitude = -1f;
                    if (m_MagnitudeThreshold >= 0f)
                    {
                        magnitude = control.EvaluateMagnitude(statePtr);
                        if (magnitude >= 0 && magnitude < m_MagnitudeThreshold)
                        {
                            continue; // No, so skip.
                        }
                    }

                    // Compute score.
                    float score;
                    if (m_OnComputeScore != null)
                    {
                        score = m_OnComputeScore(control, eventPtr);
                    }
                    else
                    {
                        score = magnitude;

                        // We don't want synthetic controls to not be bindable at all but they should
                        // generally cede priority to controls that aren't synthetic. So we bump all
                        // scores of controls that aren't synthetic.
                        if (!control.synthetic)
                        {
                            score += 1f;
                        }
                    }

                    // Control is a candidate.
                    // See if we already singled the control out as a potential candidate.
                    var candidateIndex = m_Candidates.IndexOf(control);
                    if (candidateIndex != -1)
                    {
                        // Yes, we did. So just check whether it became a better candidate than before.
                        if (m_Scores[candidateIndex] < score)
                        {
                            haveChangedCandidates    = true;
                            m_Scores[candidateIndex] = score;

                            if (m_WaitSecondsAfterMatch > 0)
                            {
                                m_LastMatchTime = InputRuntime.s_Instance.currentTime;
                            }
                        }
                    }
                    else
                    {
                        // No, so add it.
                        var candidateCount = m_Candidates.Count;
                        m_Candidates.Add(control);
                        ArrayHelpers.AppendWithCapacity(ref m_Scores, ref candidateCount, score);
                        haveChangedCandidates = true;

                        if (m_WaitSecondsAfterMatch > 0)
                        {
                            m_LastMatchTime = InputRuntime.s_Instance.currentTime;
                        }
                    }
                }

                if (haveChangedCandidates && !canceled)
                {
                    // If we have a callback that wants to control matching, leave it to the callback to decide
                    // whether the rebind is complete or not. Otherwise, just complete.
                    if (m_OnPotentialMatch != null)
                    {
                        SortCandidatesByScore();
                        m_OnPotentialMatch(this);
                    }
                    else if (m_WaitSecondsAfterMatch <= 0)
                    {
                        OnComplete();
                    }
                    else
                    {
                        SortCandidatesByScore();
                    }
                }
            }
示例#11
0
 public void OnEventTimestampOutdated(InputEventPtr eventPtr, InputDevice device)
 {
     Debug.LogError(string.Format("'{0}' input event for device '{1}' is outdated (event time: {2}, device time: {3})", eventPtr.type, device, eventPtr.time, device.lastUpdateTime));
 }
示例#12
0
        private void SetupInputControl()
        {
            Debug.Assert(m_Control == null);
            Debug.Assert(m_NextControlOnDevice == null);
            Debug.Assert(!m_InputEventPtr.valid);

            // Nothing to do if we don't have a control path.
            if (string.IsNullOrEmpty(m_ControlPath))
            {
                return;
            }

            // Determine what type of device to work with.
            var layoutName = InputControlPath.TryGetDeviceLayout(m_ControlPath);

            if (layoutName == null)
            {
                Debug.LogError(
                    string.Format(
                        "Cannot determine device layout to use based on control path '{0}' used in {1} component",
                        m_ControlPath, GetType().Name), this);
                return;
            }

            // Try to find existing on-screen device that matches.
            var internedLayoutName = new InternedString(layoutName);
            var deviceInfoIndex    = -1;

            for (var i = 0; i < s_OnScreenDevices.length; ++i)
            {
                if (s_OnScreenDevices[i].device.m_Layout == internedLayoutName)
                {
                    deviceInfoIndex = i;
                    break;
                }
            }

            // If we don't have a matching one, create a new one.
            InputDevice device;

            if (deviceInfoIndex == -1)
            {
                // Try to create device.
                try
                {
                    device = InputSystem.AddDevice(layoutName);
                }
                catch (Exception exception)
                {
                    Debug.LogError(string.Format("Could not create device with layout '{0}' used in '{1}' component", layoutName,
                                                 GetType().Name));
                    Debug.LogException(exception);
                    return;
                }

                // Create event buffer.
                InputEventPtr eventPtr;
                var           buffer = StateEvent.From(device, out eventPtr, Allocator.Persistent);

                // Add to list.
                deviceInfoIndex = s_OnScreenDevices.Append(new OnScreenDeviceInfo
                {
                    eventPtr = eventPtr,
                    buffer   = buffer,
                    device   = device,
                });
            }
            else
            {
                device = s_OnScreenDevices[deviceInfoIndex].device;
            }

            // Try to find control on device.
            m_Control = InputControlPath.TryFindControl(device, m_ControlPath);
            if (m_Control == null)
            {
                Debug.LogError(
                    string.Format(
                        "Cannot find control with path '{0}' on device of type '{1}' referenced by component '{2}'",
                        m_ControlPath, layoutName, GetType().Name), this);

                // Remove the device, if we just created one.
                if (s_OnScreenDevices[deviceInfoIndex].firstControl == null)
                {
                    s_OnScreenDevices[deviceInfoIndex].Destroy();
                    s_OnScreenDevices.RemoveAt(deviceInfoIndex);
                }

                return;
            }
            m_InputEventPtr = s_OnScreenDevices[deviceInfoIndex].eventPtr;

            // We have all we need. Permanently add us.
            s_OnScreenDevices[deviceInfoIndex] =
                s_OnScreenDevices[deviceInfoIndex].AddControl(this);
        }
示例#13
0
 bool IEventMerger.MergeForward(InputEventPtr currentEventPtr, InputEventPtr nextEventPtr)
 {
     return(MergeForward(currentEventPtr, nextEventPtr));
 }
        public static void WriteValueIntoEvent <TValue>(this InputControl control, TValue value, InputEventPtr eventPtr)
            where TValue : struct
        {
            if (control == null)
            {
                throw new ArgumentNullException("control");
            }
            if (!eventPtr.valid)
            {
                throw new ArgumentNullException("eventPtr");
            }

            var controlOfType = control as InputControl <TValue>;

            if (controlOfType == null)
            {
                throw new ArgumentException(string.Format("Expecting control of type '{0}' but got '{1}'",
                                                          typeof(TValue).Name, control.GetType().Name));
            }

            controlOfType.WriteValueIntoEvent(value, eventPtr);
        }
示例#15
0
 public void OnEventForDisabledDevice(InputEventPtr eventPtr, InputDevice device)
 {
     Debug.LogError($"Device '{device}' received input event '{eventPtr}' but the device is disabled");
 }
 /// <summary>
 /// Read the value for the given control from the given event.
 /// </summary>
 /// <param name="control">Control to read value for.</param>
 /// <param name="inputEvent">Event to read value from. Must be a <see cref="StateEvent"/> or <see cref="DeltaStateEvent"/>.</param>
 /// <typeparam name="TValue">Type of value to read.</typeparam>
 /// <exception cref="ArgumentNullException"><paramref name="control"/> is <c>null</c>.</exception>
 /// <exception cref="ArgumentException"><paramref name="inputEvent"/> is not a <see cref="StateEvent"/> or <see cref="DeltaStateEvent"/>.</exception>
 /// <returns>The value for the given control as read out from the given event or <c>default(TValue)</c> if the given
 /// event does not contain a value for the control (e.g. if it is a <see cref="DeltaStateEvent"/> not containing the relevant
 /// portion of the device's state memory).</returns>
 public static TValue ReadValueFromEvent <TValue>(this InputControl <TValue> control, InputEventPtr inputEvent)
     where TValue : struct
 {
     if (control == null)
     {
         throw new ArgumentNullException(nameof(control));
     }
     if (!ReadValueFromEvent(control, inputEvent, out var value))
     {
         return(default);
示例#17
0
 public void OnCannotFindDeviceForEvent(InputEventPtr eventPtr)
 {
     Debug.LogError("Cannot find device for input event: " + eventPtr);
 }
示例#18
0
        protected static unsafe void Accumulate(InputControl <float> control, void *oldStatePtr, InputEventPtr newState)
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }

            if (!control.ReadUnprocessedValueFromEvent(newState, out var newDelta))
            {
                return; // Value for the control not contained in the given event.
            }
            var oldDelta = control.ReadUnprocessedValueFromState(oldStatePtr);

            control.WriteValueIntoEvent(oldDelta + newDelta, newState);
        }
示例#19
0
 /// <summary>
 /// Called when the pointer receives a state event.
 /// </summary>
 /// <param name="eventPtr">The input event.</param>
 protected unsafe void OnStateEvent(InputEventPtr eventPtr)
 {
     ////FIXME: This stuff makes pointer events too expensive; find a better way.
     delta.AccumulateValueInEvent(currentStatePtr, eventPtr);
     InputState.Change(this, eventPtr);
 }
示例#20
0
        /// <summary>
        /// Checks an Input Event for any significant changes that would be considered user activity.
        /// </summary>
        /// <param name="inputEvent">The input event being checked for changes</param>
        /// <param name="device">The input device being checked against </param>
        /// <param name="offset">The offset into the device that the event is placed</param>
        /// <param name="sizeInBytes">The size of the event in bytes</param>
        /// <returns>True if any changes exist in the event once the device has been filtered through for noise and non-significant changes.  False otherwise.</returns>
        public unsafe bool EventHasValidData(InputDevice device, InputEventPtr inputEvent, uint offset, uint sizeInBytes)
        {
            if (!inputEvent.valid)
            {
                throw new ArgumentException("Invalid or unset event being checked.", "inputEvent");
            }

            if (device == null)
            {
                throw new ArgumentNullException("device");
            }

            if (IsEmpty())
            {
                return(true);
            }

            if ((offset + sizeInBytes) * 8 > device.stateBlock.sizeInBits)
            {
                return(false);
            }

            var noiseFilterPtr = InputStateBuffers.s_NoiseBitmaskBuffer;

            if (noiseFilterPtr == IntPtr.Zero)
            {
                throw new Exception("Noise Filter Buffer is uninitialized while trying to check state events for data.");
            }

            var ptrToEventState = IntPtr.Zero;

            if (inputEvent.IsA <StateEvent>())
            {
                var stateEvent = StateEvent.From(inputEvent);
                ptrToEventState = stateEvent->state;
            }
            else if (inputEvent.IsA <DeltaStateEvent>())
            {
                var stateEvent = DeltaStateEvent.From(inputEvent);
                ptrToEventState = stateEvent->deltaState;
            }
            else
            {
                throw new ArgumentException(string.Format(
                                                "Invalid event type '{0}', we can only check for valid data on StateEvents and DeltaStateEvents.",
                                                inputEvent.type),
                                            "inputEvent");
            }

            if (MemoryHelpers.HasAnyNonZeroBitsAfterMaskingWithBuffer(ptrToEventState, noiseFilterPtr, offset, sizeInBytes * 8))
            {
                return(true);
            }

            for (var i = 0; i < elements.Length; i++)
            {
                if (elements[i].EventHasValidData(inputEvent, device))
                {
                    return(true);
                }
            }

            return(false);
        }
示例#21
0
 void IInputStateCallbackReceiver.OnStateEvent(InputEventPtr eventPtr)
 {
     OnStateEvent(eventPtr);
 }
示例#22
0
        protected void OnSourceControlChangedValue(InputControl control, double time, InputEventPtr eventPtr, long sourceDeviceAndButtonIndex)
        {
            var sourceDeviceIndex = sourceDeviceAndButtonIndex & 0xffffffff;

            if (sourceDeviceIndex < 0 && sourceDeviceIndex >= m_NumSources)
            {
                throw new ArgumentOutOfRangeException(nameof(sourceDeviceIndex), $"Index {sourceDeviceIndex} out of range; have {m_NumSources} sources");
            }

            ////TODO: this can be simplified a lot if we use events instead of InputState.Change() but doing so requires work on buffering events while processing; also
            ////       needs extra handling to not lag into the next frame

            if (control is ButtonControl button)
            {
                var buttonIndex = (int)(sourceDeviceAndButtonIndex >> 32);
                var isPressed   = button.isPressed;
                if (isPressed)
                {
                    // Start new touch.
                    for (var i = 0; i < m_Touches.Length; ++i)
                    {
                        // Find unused touch.
                        if (m_Touches[i].touchId != 0)
                        {
                            continue;
                        }

                        var touchId = ++m_LastTouchId;
                        m_Touches[i] = new SimulatedTouch
                        {
                            touchId     = touchId,
                            buttonIndex = buttonIndex,
                            sourceIndex = (int)sourceDeviceIndex,
                        };

                        var isPrimary = m_PrimaryTouchIndex == -1;
                        var position  = m_CurrentPositions[sourceDeviceIndex];
                        var oldTouch  = simulatedTouchscreen.touches[i].ReadValue();

                        var touch = new TouchState
                        {
                            touchId        = touchId,
                            position       = position,
                            phase          = TouchPhase.Began,
                            startTime      = time,
                            startPosition  = position,
                            isPrimaryTouch = isPrimary,
                            tapCount       = oldTouch.tapCount,
                        };

                        if (isPrimary)
                        {
                            InputState.Change(simulatedTouchscreen.primaryTouch, touch, eventPtr: eventPtr);
                            m_PrimaryTouchIndex = i;
                        }
                        InputState.Change(simulatedTouchscreen.touches[i], touch, eventPtr: eventPtr);

                        break;
                    }
                }
                else
                {
                    // End ongoing touch.
                    for (var i = 0; i < m_Touches.Length; ++i)
                    {
                        if (m_Touches[i].buttonIndex != buttonIndex || m_Touches[i].sourceIndex != sourceDeviceIndex ||
                            m_Touches[i].touchId == 0)
                        {
                            continue;
                        }

                        // Detect taps.
                        var position = m_CurrentPositions[sourceDeviceIndex];
                        var oldTouch = simulatedTouchscreen.touches[i].ReadValue();
                        var isTap    = time - oldTouch.startTime <= Touchscreen.s_TapTime &&
                                       (position - oldTouch.startPosition).sqrMagnitude <= Touchscreen.s_TapRadiusSquared;

                        var touch = new TouchState
                        {
                            touchId       = m_Touches[i].touchId,
                            phase         = TouchPhase.Ended,
                            position      = position,
                            tapCount      = (byte)(oldTouch.tapCount + (isTap ? 1 : 0)),
                            isTap         = isTap,
                            startPosition = oldTouch.startPosition,
                            startTime     = oldTouch.startTime,
                        };

                        if (m_PrimaryTouchIndex == i)
                        {
                            InputState.Change(simulatedTouchscreen.primaryTouch, touch, eventPtr: eventPtr);
                            ////TODO: check if there's an ongoing touch that can take over
                            m_PrimaryTouchIndex = -1;
                        }
                        InputState.Change(simulatedTouchscreen.touches[i], touch, eventPtr: eventPtr);

                        m_Touches[i].touchId = 0;
                        break;
                    }
                }
            }
            else
            {
                Debug.Assert(control is InputControl <Vector2>, "Expecting control to be either a button or a position");
                var positionControl = (InputControl <Vector2>)control;

                // Update recorded position.
                var position = positionControl.ReadValue();
                var delta    = position - m_CurrentPositions[sourceDeviceIndex];
                m_CurrentPositions[sourceDeviceIndex] = position;

                // Update position of ongoing touches from this pointer.
                for (var i = 0; i < m_Touches.Length; ++i)
                {
                    if (m_Touches[i].sourceIndex != sourceDeviceIndex || m_Touches[i].touchId == 0)
                    {
                        continue;
                    }

                    var oldTouch  = simulatedTouchscreen.touches[i].ReadValue();
                    var isPrimary = m_PrimaryTouchIndex == i;
                    var touch     = new TouchState
                    {
                        touchId        = m_Touches[i].touchId,
                        phase          = TouchPhase.Moved,
                        position       = position,
                        delta          = delta,
                        isPrimaryTouch = isPrimary,
                        tapCount       = oldTouch.tapCount,
                        isTap          = false, // Can't be tap as it's a move.
                        startPosition  = oldTouch.startPosition,
                        startTime      = oldTouch.startTime,
                    };

                    if (isPrimary)
                    {
                        InputState.Change(simulatedTouchscreen.primaryTouch, touch, eventPtr: eventPtr);
                    }
                    InputState.Change(simulatedTouchscreen.touches[i], touch, eventPtr: eventPtr);
                }
            }
        }
示例#23
0
 /// <inheritdoc cref="IRLActionInputAdaptor.WriteToInputEventForAction"/>
 public void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
示例#24
0
 void IInputStateChangeMonitor.NotifyControlStateChanged(InputControl control, double time, InputEventPtr eventPtr, long monitorIndex)
 {
     OnSourceControlChangedValue(control, time, eventPtr, monitorIndex);
 }
        public static unsafe bool ReadUnprocessedValueFromEvent <TValue>(this InputControl <TValue> control, InputEventPtr inputEvent, out TValue value)
            where TValue : struct
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }

            var statePtr = control.GetStatePtrFromStateEvent(inputEvent);

            if (statePtr == null)
            {
                value = control.ReadDefaultValue();
                return(false);
            }

            value = control.ReadUnprocessedValueFromState(statePtr);
            return(true);
        }
示例#26
0
 public void OnEventTimestampOutdated(InputEventPtr eventPtr, InputDevice device)
 {
     Debug.LogError(
         $"'{eventPtr.type}' input event for device '{device}' is outdated (event time: {eventPtr.time}, device time: {device.lastUpdateTime})");
 }
        public static void WriteValueIntoEvent <TValue>(this InputControl control, TValue value, InputEventPtr eventPtr)
            where TValue : struct
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }
            if (!eventPtr.valid)
            {
                throw new ArgumentNullException(nameof(eventPtr));
            }

            if (!(control is InputControl <TValue> controlOfType))
            {
                throw new ArgumentException(
                          $"Expecting control of type '{typeof(TValue).Name}' but got '{control.GetType().Name}'");
            }

            controlOfType.WriteValueIntoEvent(value, eventPtr);
        }
示例#28
0
 public void OnEventFormatMismatch(InputEventPtr eventPtr, InputDevice device)
 {
     Debug.LogError(
         $"'{eventPtr.type}' input event for device '{device}' has incorrect format (event format: '{eventPtr.type}', device format: '{device.stateBlock.format}')");
 }
        public static unsafe void *GetStatePtrFromStateEvent(this InputControl control, InputEventPtr eventPtr)
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }
            if (!eventPtr.valid)
            {
                throw new ArgumentNullException(nameof(eventPtr));
            }

            uint   stateOffset;
            FourCC stateFormat;
            uint   stateSizeInBytes;
            void * statePtr;

            if (eventPtr.IsA <DeltaStateEvent>())
            {
                var deltaEvent = DeltaStateEvent.From(eventPtr);

                // If it's a delta event, we need to subtract the delta state offset if it's not set to the root of the device
                stateOffset      = deltaEvent->stateOffset;
                stateFormat      = deltaEvent->stateFormat;
                stateSizeInBytes = deltaEvent->deltaStateSizeInBytes;
                statePtr         = deltaEvent->deltaState;
            }
            else if (eventPtr.IsA <StateEvent>())
            {
                var stateEvent = StateEvent.From(eventPtr);

                stateOffset      = 0;
                stateFormat      = stateEvent->stateFormat;
                stateSizeInBytes = stateEvent->stateSizeInBytes;
                statePtr         = stateEvent->state;
            }
            else
            {
                throw new ArgumentException("Event must be a state or delta state event", "eventPtr");
            }

            // Make sure we have a state event compatible with our device. The event doesn't
            // have to be specifically for our device (we don't require device IDs to match) but
            // the formats have to match and the size must be within range of what we're trying
            // to read.
            var device = control.device;

            if (stateFormat != device.m_StateBlock.format)
            {
                throw new InvalidOperationException(
                          $"Cannot read control '{control.path}' from {eventPtr.type} with format {stateFormat}; device '{device}' expects format {device.m_StateBlock.format}");
            }

            // Once a device has been added, global state buffer offsets are baked into control hierarchies.
            // We need to unsubtract those offsets here.
            stateOffset += device.m_StateBlock.byteOffset;

            // Return null if state is out of range.
            var controlOffset = (int)control.m_StateBlock.byteOffset - stateOffset;

            if (controlOffset < 0 || controlOffset + control.m_StateBlock.alignedSizeInBytes > stateSizeInBytes)
            {
                return(null);
            }

            return((byte *)statePtr - (int)stateOffset);
        }
    private void UnpairedDeviceUsed(InputControl control, InputEventPtr eventPtr)
    {
        if (!(control is ButtonControl) || control.device.displayName == "Keyboard" || control.device.displayName == "Mouse")
        {
            return;
        }
        Debug.Log("Device: " + control.device.displayName);

        InputUser user = InputUser.PerformPairingWithDevice(control.device);

        PlayerControls controlsForUser = new PlayerControls();

        user.AssociateActionsWithUser(controlsForUser);

        controlsForUser.Enable();

        if (players.Count == 0)
        {
            player1.GetComponent <Movement>().BindControls(controlsForUser);
            player1.SetActive(true);
            player1.transform.position = spawnPoint1.transform.position;
            players.Add(player1.GetComponent <Movement>());
            GetComponent <Deathcount>().player1Deaths = 0;
        }
        else if (players.Count == 1)
        {
            player2.GetComponent <Movement>().BindControls(controlsForUser);
            player2.SetActive(true);
            player2.transform.position = spawnPoint2.transform.position;
            players.Add(player2.GetComponent <Movement>());
            GetComponent <Deathcount>().player2Deaths = 0;
        }
        else if (players.Count == 2)
        {
            player3.GetComponent <Movement>().BindControls(controlsForUser);
            player3.SetActive(true);
            player3.transform.position = spawnPoint3.transform.position;
            players.Add(player3.GetComponent <Movement>());
            GetComponent <Deathcount>().player3Deaths = 0;
        }
        else if (players.Count == 3)
        {
            player4.GetComponent <Movement>().BindControls(controlsForUser);
            player4.SetActive(true);
            player4.transform.position = spawnPoint4.transform.position;
            players.Add(player4.GetComponent <Movement>());
            GetComponent <Deathcount>().player4Deaths = 0;
        }

        List <GameObject> tempPlayers = new List <GameObject>();

        foreach (var item in players)
        {
            tempPlayers.Add(item.gameObject);
        }

        InputUser.listenForUnpairedDeviceActivity--;
        if (InputUser.listenForUnpairedDeviceActivity == 0)
        {
            StopJoining();
        }
    }