Esempio n. 1
0
        /// <summary>
        /// Set the control to the given value by sending a state event with the value to the
        /// control's device.
        /// </summary>
        /// <param name="control">An input control on a device that has been added to the system.</param>
        /// <param name="state">New value for the input control.</param>
        /// <typeparam name="TValue">Value type of the given control.</typeparam>
        /// <example>
        /// <code>
        /// var gamepad = InputSystem.AddDevice&lt;Gamepad&gt;();
        /// Set(gamepad.leftButton, 1);
        /// </code>
        /// </example>
        public void Set <TValue>(InputControl <TValue> control, TValue state, double time = -1, double timeOffset = 0, bool queueEventOnly = false)
            where TValue : struct
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }
            if (!control.device.added)
            {
                throw new ArgumentException(
                          $"Device of control '{control}' has not been added to the system", nameof(control));
            }

            void SetUpAndQueueEvent(InputEventPtr eventPtr)
            {
                ////REVIEW: should we by default take the time from the device here?
                if (time >= 0)
                {
                    eventPtr.time = time;
                }
                eventPtr.time += timeOffset;
                control.WriteValueIntoEvent(state, eventPtr);
                InputSystem.QueueEvent(eventPtr);
            }

            // Touchscreen does not support delta events involving TouchState.
            if (control is TouchControl)
            {
                using (StateEvent.From(control.device, out var eventPtr))
                    SetUpAndQueueEvent(eventPtr);
            }
            else
            {
                // We use delta state events rather than full state events here to mitigate the following problem:
                // Grabbing state from the device will preserve the current values of controls covered in the state.
                // However, running an update may alter the value of one or more of those controls. So with a full
                // state event, we may be writing outdated data back into the device. For example, in the case of delta
                // controls which will reset in OnBeforeUpdate().
                //
                // Using delta events, we may still grab state outside of just the one control in case we're looking at
                // bit-addressed controls but at least we can avoid the problem for the majority of controls.
                using (DeltaStateEvent.From(control, out var eventPtr))
                    SetUpAndQueueEvent(eventPtr);
            }

            if (!queueEventOnly)
            {
                InputSystem.Update();
            }
        }
Esempio n. 2
0
        private unsafe void ColumnGUI(Rect cellRect, InputEventPtr eventPtr, int column)
        {
            CenterRectUsingSingleLineHeight(ref cellRect);

            switch (column)
            {
            case (int)ColumnId.Id:
                GUI.Label(cellRect, eventPtr.id.ToString());
                break;

            case (int)ColumnId.Type:
                GUI.Label(cellRect, eventPtr.type.ToString());
                break;

            case (int)ColumnId.Device:
                GUI.Label(cellRect, eventPtr.deviceId.ToString());
                break;

            case (int)ColumnId.Size:
                GUI.Label(cellRect, eventPtr.sizeInBytes.ToString());
                break;

            case (int)ColumnId.Time:
                GUI.Label(cellRect, eventPtr.time.ToString("0.0000s"));
                break;

            case (int)ColumnId.Details:
                if (eventPtr.IsA <DeltaStateEvent>())
                {
                    var deltaEventPtr = DeltaStateEvent.From(eventPtr);
                    GUI.Label(cellRect, $"Format={deltaEventPtr->stateFormat}, Offset={deltaEventPtr->stateOffset}");
                }
                else if (eventPtr.IsA <StateEvent>())
                {
                    var stateEventPtr = StateEvent.From(eventPtr);
                    GUI.Label(cellRect, $"Format={stateEventPtr->stateFormat}");
                }
                else if (eventPtr.IsA <TextEvent>())
                {
                    var textEventPtr = TextEvent.From(eventPtr);
                    GUI.Label(cellRect, $"Character='{(char) textEventPtr->character}'");
                }
                break;
            }
        }
Esempio n. 3
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 HasValidData(InputDevice device, InputEventPtr inputEvent, uint offset, uint sizeInbytes)
        {
            if (elements.Length == 0)
            {
                return(true);
            }

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

            bool result = false;

            IntPtr noiseFilterPtr = InputStateBuffers.s_NoiseFilterBuffer;

            if (noiseFilterPtr != IntPtr.Zero)
            {
                IntPtr ptrToEventState = IntPtr.Zero;
                if (inputEvent.IsA <StateEvent>())
                {
                    StateEvent *stateEvent = StateEvent.From(inputEvent);
                    ptrToEventState = stateEvent->state;
                }
                else if (inputEvent.IsA <DeltaStateEvent>())
                {
                    DeltaStateEvent *stateEvent = DeltaStateEvent.From(inputEvent);
                    ptrToEventState = stateEvent->deltaState;
                }

                if (ptrToEventState != IntPtr.Zero)
                {
                    result = BitmaskHelpers.CheckForMaskedValues(ptrToEventState, noiseFilterPtr, offset, sizeInbytes * 8);
                    for (int i = 0; i < elements.Length && !result; i++)
                    {
                        result = elements[i].HasValidData(inputEvent, device);
                    }
                }
            }

            return(result);
        }
Esempio n. 4
0
    public void Events_CanCreateDeltaStateEventFromControl()
    {
        var gamepad = InputSystem.AddDevice <Gamepad>();

        Set(gamepad.buttonSouth, 1);
        Set(gamepad.buttonNorth, 1);
        Set(gamepad.leftTrigger, 0.123f);

        using (DeltaStateEvent.From(gamepad.buttonNorth, out var eventPtr))
        {
            Assert.That(gamepad.buttonNorth.ReadValueFromEvent(eventPtr, out var val), Is.True);
            Assert.That(val, Is.EqualTo(1).Within(0.00001));

            gamepad.buttonNorth.WriteValueIntoEvent(0f, eventPtr);

            InputSystem.QueueEvent(eventPtr);
            InputSystem.Update();

            Assert.That(gamepad.buttonNorth.ReadValue(), Is.Zero);
        }
    }
        private unsafe byte[] GetEventStateBuffer(InputEventPtr eventPtr, InputControl control)
        {
            // Must be an event carrying state.
            if (!eventPtr.IsA <StateEvent>() && !eventPtr.IsA <DeltaStateEvent>())
            {
                throw new ArgumentException("Event must be state or delta event", "eventPtr");
            }

            // Get state data.
            void *dataPtr;
            uint  dataSize;
            uint  stateSize;
            uint  stateOffset = 0;

            if (eventPtr.IsA <DeltaStateEvent>())
            {
                var deltaEventPtr = DeltaStateEvent.From(eventPtr);
                stateSize   = control.stateBlock.alignedSizeInBytes;
                stateOffset = deltaEventPtr->stateOffset;
                dataPtr     = deltaEventPtr->deltaState.ToPointer();
                dataSize    = deltaEventPtr->deltaStateSizeInBytes;
            }
            else
            {
                var stateEventPtr = StateEvent.From(eventPtr);
                dataSize = stateSize = stateEventPtr->stateSizeInBytes;
                dataPtr  = stateEventPtr->state.ToPointer();
            }

            // Copy event data.
            var buffer = new byte[stateSize];

            fixed(byte *bufferPtr = buffer)
            {
                UnsafeUtility.MemCpy(bufferPtr + stateOffset, dataPtr, dataSize);
            }

            return(buffer);
        }
Esempio n. 6
0
        internal unsafe IntPtr GetStatePtrFromStateEvent(InputEventPtr eventPtr)
        {
            if (!eventPtr.valid)
            {
                throw new ArgumentNullException("eventPtr");
            }
            if (!eventPtr.IsA <StateEvent>() && !eventPtr.IsA <DeltaStateEvent>())
            {
                throw new ArgumentException("Event must be a state or delta state event", "eventPtr");
            }

            uint   stateOffset;
            FourCC stateFormat;
            uint   stateSizeInBytes;
            IntPtr 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.
            if (stateFormat != device.m_StateBlock.format)
            {
                throw new InvalidOperationException(
                          string.Format(
                              "Cannot read control '{0}' from StateEvent with format {1}; device '{2}' expects format {3}",
                              path, stateFormat, device, 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;

            if (m_StateBlock.byteOffset - stateOffset + m_StateBlock.alignedSizeInBytes > stateSizeInBytes)
            {
                return(IntPtr.Zero);
            }

            return(new IntPtr(statePtr.ToInt64() - (int)stateOffset));
        }
        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;

            if (control.m_StateBlock.byteOffset - stateOffset + control.m_StateBlock.alignedSizeInBytes > stateSizeInBytes)
            {
                return(null);
            }

            return((byte *)statePtr - (int)stateOffset);
        }
Esempio n. 8
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);
        }