public unsafe void QueueEvent(InputEvent *eventPtr)
        {
            var eventSize        = eventPtr->sizeInBytes;
            var alignedEventSize = eventSize.AlignToMultipleOf(4);

            lock (m_Lock)
            {
                eventPtr->eventId = m_NextEventId;
                eventPtr->handled = false;
                ++m_NextEventId;

                // Enlarge buffer, if we have to.
                if ((m_EventWritePosition + alignedEventSize) > m_EventBuffer.Length)
                {
                    var newBufferSize = m_EventBuffer.Length + Mathf.Max((int)alignedEventSize, 1024);
                    var newBuffer     = new NativeArray <byte>(newBufferSize, Allocator.Persistent);
                    UnsafeUtility.MemCpy(newBuffer.GetUnsafePtr(), m_EventBuffer.GetUnsafePtr(), m_EventWritePosition);
                    m_EventBuffer.Dispose();
                    m_EventBuffer = newBuffer;
                }

                // Copy event.
                UnsafeUtility.MemCpy((byte *)m_EventBuffer.GetUnsafePtr() + m_EventWritePosition, eventPtr, eventSize);
                m_EventWritePosition += (int)alignedEventSize;
                ++m_EventCount;
            }
        }
Esempio n. 2
0
        public void Write(InputEvent *eventPtr)
        {
            var wasAlreadyCreated = m_AppendBuffer.data.IsCreated;
            var oldBufferPtr      = (byte *)m_AppendBuffer.bufferPtr.data;

            m_AppendBuffer.AppendEvent(eventPtr, allocator: Allocator.Temp);

            if (!wasAlreadyCreated)
            {
                m_CurrentAppendEventWritePtr = m_CurrentAppendEventReadPtr =
                    (InputEvent *)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_AppendBuffer.data);
            }
            else
            {
                // AppendEvent can reallocate the buffer if it needs more space, so make sure the read and write pointers
                // point to the equivalent places in the new buffer.
                var newBufferPtr = (byte *)m_AppendBuffer.bufferPtr.data;
                if (oldBufferPtr != newBufferPtr)
                {
                    var currentWriteOffset = (byte *)m_CurrentAppendEventWritePtr - oldBufferPtr;
                    var currentReadOffset  = (byte *)m_CurrentAppendEventReadPtr - oldBufferPtr;
                    m_CurrentAppendEventWritePtr = (InputEvent *)(newBufferPtr + currentWriteOffset);
                    m_CurrentAppendEventReadPtr  = (InputEvent *)(newBufferPtr + currentReadOffset);
                }
            }

            m_RemainingAppendEventCount++;
        }
Esempio n. 3
0
        /// <summary>
        /// Advance the read position to the next event in the buffer, preserving or not preserving the
        /// current event depending on <paramref name="leaveEventInBuffer"/>.
        /// </summary>
        /// <param name="currentReadPos"></param>
        /// <param name="currentWritePos"></param>
        /// <param name="numEventsRetainedInBuffer"></param>
        /// <param name="numRemainingEvents"></param>
        /// <param name="leaveEventInBuffer"></param>
        /// <remarks>
        /// This method MUST ONLY BE CALLED if the current event has been fully processed. If the at <paramref name="currentWritePos"/>
        /// is smaller than the current event, then this method will OVERWRITE parts or all of the current event.
        /// </remarks>
        internal void AdvanceToNextEvent(ref InputEvent *currentReadPos,
                                         ref InputEvent *currentWritePos, ref int numEventsRetainedInBuffer,
                                         ref int numRemainingEvents, bool leaveEventInBuffer)
        {
            Debug.Assert(Contains(currentReadPos), "Current read position should be contained in buffer");
            Debug.Assert(Contains(currentWritePos), "Current write position should be contained in buffer");
            Debug.Assert(currentReadPos >= currentWritePos, "Current write position is beyond read position");

            // Get new read position *before* potentially moving the current event so that we don't
            // end up overwriting the data we need to find the next event in memory.
            var newReadPos = currentReadPos;

            if (numRemainingEvents > 1)
            {
                newReadPos = InputEvent.GetNextInMemoryChecked(currentReadPos, ref this);
            }

            // If the current event should be left in the buffer, advance write position.
            if (leaveEventInBuffer)
            {
                // Move down in buffer if read and write pos have deviated from each other.
                var numBytes = currentReadPos->sizeInBytes;
                if (currentReadPos != currentWritePos)
                {
                    UnsafeUtility.MemMove(currentWritePos, currentReadPos, numBytes);
                }
                currentWritePos = (InputEvent *)((byte *)currentWritePos + numBytes.AlignToMultipleOf(4));
                ++numEventsRetainedInBuffer;
            }

            currentReadPos = newReadPos;
            --numRemainingEvents;
        }
Esempio n. 4
0
            public static unsafe Message Create(InputRemoting sender, InputEvent *events, int eventCount)
            {
                // Find total size of event buffer we need.
                var totalSize = 0u;
                var eventPtr  = new InputEventPtr(events);

                for (var i = 0; i < eventCount; ++i, eventPtr = eventPtr.Next())
                {
                    totalSize += eventPtr.sizeInBytes;
                }

                // Copy event data to buffer. Would be nice if we didn't have to do that
                // but unfortunately we need a byte[] and can't just pass the 'events' IntPtr
                // directly.
                var data = new byte[totalSize];

                fixed(byte *dataPtr = data)
                {
                    UnsafeUtility.MemCpy(dataPtr, events, totalSize);
                }

                // Done.
                return(new Message
                {
                    type = MessageType.NewEvents,
                    data = data
                });
            }
Esempio n. 5
0
 public Enumerator(InputEventBuffer buffer)
 {
     m_Buffer       = buffer.bufferPtr;
     m_EventCount   = buffer.m_EventCount;
     m_CurrentEvent = null;
     m_CurrentIndex = 0;
 }
Esempio n. 6
0
        /// <summary>
        /// Get the next event after the given one.
        /// </summary>
        /// <param name="currentPtr">A valid event pointer.</param>
        /// <returns>Pointer to the next event in memory.</returns>
        /// <remarks>
        /// This method applies no checks and must only be called if there is an event following the
        /// given one. Also, the size of the given event must be 100% as the method will simply
        /// take the size and advance the given pointer by it (and aligning it to <see cref="kAlignment"/>).
        /// </remarks>
        /// <seealso cref="GetNextInMemoryChecked"/>
        internal static unsafe InputEvent *GetNextInMemory(InputEvent *currentPtr)
        {
            Debug.Assert(currentPtr != null);
            var alignedSizeInBytes = NumberHelpers.AlignToMultiple(currentPtr->sizeInBytes, kAlignment);

            return((InputEvent *)((byte *)currentPtr + alignedSizeInBytes));
        }
Esempio n. 7
0
        /// <summary>
        /// Whether the given event pointer refers to data within the event buffer.
        /// </summary>
        /// <param name="eventPtr"></param>
        /// <returns></returns>
        /// <remarks>
        /// Note that this method does NOT check whether the given pointer points to an actual
        /// event in the buffer. It solely performs a pointer out-of-bounds check.
        ///
        /// Also note that if the size of the memory buffer is unknown (<see cref="BufferSizeUnknown"/>,
        /// only a lower-bounds check is performed.
        /// </remarks>
        public bool Contains(InputEvent *eventPtr)
        {
            if (eventPtr == null)
            {
                return(false);
            }

            if (sizeInBytes == 0)
            {
                return(false);
            }

            var bufferPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(data);

            if (eventPtr < bufferPtr)
            {
                return(false);
            }

            if (sizeInBytes != BufferSizeUnknown && eventPtr >= (byte *)bufferPtr + sizeInBytes)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 8
0
        /// <summary>
        /// Construct an event buffer using the given memory block containing <see cref="InputEvent"/>s.
        /// </summary>
        /// <param name="eventPtr">A buffer containing <paramref name="eventCount"/> number of input events. The
        /// individual events in the buffer are variable-sized (depending on the type of each event).</param>
        /// <param name="eventCount">The number of events in <paramref name="eventPtr"/>. Can be zero.</param>
        /// <param name="sizeInBytes">Total number of bytes of event data in the memory block pointed to by <paramref name="eventPtr"/>.
        /// If -1 (default), the size of the actual event data in the buffer is considered unknown and has to be determined by walking
        /// <paramref name="eventCount"/> number of events (due to the variable size of each event).</param>
        /// <param name="capacityInBytes">The total size of the memory block allocated at <paramref name="eventPtr"/>. If this
        /// is larger than <paramref name="sizeInBytes"/>, additional events can be appended to the buffer until the capacity
        /// is exhausted. If this is -1 (default), the capacity is considered unknown and no additional events can be
        /// appended to the buffer.</param>
        /// <exception cref="ArgumentException"><paramref name="eventPtr"/> is <c>null</c> and <paramref name="eventCount"/> is not zero
        /// -or- <paramref name="capacityInBytes"/> is less than <paramref name="sizeInBytes"/>.</exception>
        public InputEventBuffer(InputEvent *eventPtr, int eventCount, int sizeInBytes = -1, int capacityInBytes = -1)
            : this()
        {
            if (eventPtr == null && eventCount != 0)
            {
                throw new ArgumentException("eventPtr is NULL but eventCount is != 0", nameof(eventCount));
            }
            if (capacityInBytes != 0 && capacityInBytes < sizeInBytes)
            {
                throw new ArgumentException($"capacity({capacityInBytes}) cannot be smaller than size({sizeInBytes})",
                                            nameof(capacityInBytes));
            }

            if (eventPtr != null)
            {
                if (capacityInBytes < 0)
                {
                    capacityInBytes = sizeInBytes;
                }

                m_Buffer = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(eventPtr,
                                                                                            capacityInBytes > 0 ? capacityInBytes : 0, Allocator.None);
                m_SizeInBytes    = sizeInBytes >= 0 ? sizeInBytes : BufferSizeUnknown;
                m_EventCount     = eventCount;
                m_WeOwnTheBuffer = false;
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Append a new event to the end of the buffer by copying the event from <paramref name="eventPtr"/>.
        /// </summary>
        /// <param name="eventPtr">Data of the event to store in the buffer. This will be copied in full as
        /// per <see cref="InputEvent.sizeInBytes"/> found in the event's header.</param>
        /// <param name="capacityIncrementInBytes">If the buffer needs to be reallocated to accommodate the event, number of
        /// bytes to grow the buffer by.</param>
        /// <param name="allocator">If the buffer needs to be reallocated to accommodate the event, the type of allocation to
        /// use.</param>
        /// <exception cref="ArgumentNullException"><paramref name="eventPtr"/> is <c>null</c>.</exception>
        /// <remarks>
        /// If the buffer's current capacity (see <see cref="capacityInBytes"/>) is smaller than <see cref="InputEvent.sizeInBytes"/>
        /// of the given event, the buffer will be reallocated.
        /// </remarks>
        public void AppendEvent(InputEvent *eventPtr, int capacityIncrementInBytes = 2048, Allocator allocator = Allocator.Persistent)
        {
            if (eventPtr == null)
            {
                throw new ArgumentNullException(nameof(eventPtr));
            }

            // Allocate space.
            var eventSizeInBytes = eventPtr->sizeInBytes;
            var destinationPtr   = AllocateEvent((int)eventSizeInBytes, capacityIncrementInBytes, allocator);

            // Copy event.
            UnsafeUtility.MemCpy(destinationPtr, eventPtr, eventSizeInBytes);
        }
Esempio n. 10
0
        public InputEventBuffer(InputEvent *eventPtr, int eventCount)
            : this()
        {
            if (eventPtr == null && eventCount != 0)
            {
                throw new ArgumentException("eventPtr is NULL but eventCount is != 0", "eventCount");
            }

            if (eventPtr != null)
            {
                m_Buffer         = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(eventPtr, 0, Allocator.None);
                m_BufferEnd      = kBufferSizeUnknown;
                m_EventCount     = eventCount;
                m_WeOwnTheBuffer = false;
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Get the next event after the given one. Throw if that would point to invalid memory as indicated
        /// by the given memory buffer.
        /// </summary>
        /// <param name="currentPtr">A valid event pointer to an event inside <paramref name="buffer"/>.</param>
        /// <param name="buffer">Event buffer in which to advance to the next event.</param>
        /// <returns>Pointer to the next event.</returns>
        /// <exception cref="InvalidOperationException">There are no more events in the given buffer.</exception>
        internal static unsafe InputEvent *GetNextInMemoryChecked(InputEvent *currentPtr, ref InputEventBuffer buffer)
        {
            Debug.Assert(currentPtr != null);
            Debug.Assert(buffer.Contains(currentPtr), "Given event is not contained in given event buffer");

            var alignedSizeInBytes = NumberHelpers.AlignToMultiple(currentPtr->sizeInBytes, kAlignment);
            var nextPtr            = (InputEvent *)((byte *)currentPtr + alignedSizeInBytes);

            if (!buffer.Contains(nextPtr))
            {
                throw new InvalidOperationException(string.Format(
                                                        "Event '{0}' is last event in given buffer with size {1}", new InputEventPtr(currentPtr),
                                                        buffer.sizeInBytes));
            }

            return(nextPtr);
        }
Esempio n. 12
0
        private unsafe void pollEvents()
        {
            List <Event> events = null;

            fixed(byte *evBytePtr = eventBytes)
            {
                // Read input events until no more are left:
                while (Read(fd, evBytePtr, (UIntPtr)sizeOfInputEvent) != IntPtr.Zero)
                {
                    Event ev;

                    // Copy values out of byte[] directly:
                    InputEvent *iev = (InputEvent *)evBytePtr;
                    ev.Type = iev->Type;

                    // We're done reading on an EV_SYN event type:
                    if (ev.Type == EV_SYN)
                    {
                        break;
                    }

                    ev.Code  = iev->Code;
                    ev.Value = iev->Value;

                    // Add the event to the collection:
                    if (events == null)
                    {
                        events = new List <Event>();
                    }
                    events.Add(ev);
                }
            }

            if (events != null)
            {
                // Fire event listener with the collection of events read in:
                EventListener(events);
            }
        }
Esempio n. 13
0
            public bool MoveNext()
            {
                if (m_CurrentIndex == m_EventCount)
                {
                    return(false);
                }

                if (m_CurrentEvent == null)
                {
                    m_CurrentEvent = m_Buffer;
                    return(m_CurrentEvent != null);
                }

                Debug.Assert(m_CurrentEvent != null, "Current event must not be null");

                ++m_CurrentIndex;
                if (m_CurrentIndex == m_EventCount)
                {
                    return(false);
                }

                m_CurrentEvent = InputEvent.GetNextInMemory(m_CurrentEvent);
                return(true);
            }
Esempio n. 14
0
        public void Write(InputEvent *eventPtr)
        {
            if (m_AppendBuffer.eventCount >= m_MaxAppendedEvents)
            {
                Debug.LogError($"Maximum number of queued events exceeded. Set the '{nameof(InputSettings.maxQueuedEventsPerUpdate)}' " +
                               $"setting to a higher value if you need to queue more events than this. " +
                               $"Current limit is '{m_MaxAppendedEvents}'.");
                return;
            }

            var wasAlreadyCreated = m_AppendBuffer.data.IsCreated;
            var oldBufferPtr      = (byte *)m_AppendBuffer.bufferPtr.data;

            m_AppendBuffer.AppendEvent(eventPtr, allocator: Allocator.Temp);

            if (!wasAlreadyCreated)
            {
                m_CurrentAppendEventWritePtr = m_CurrentAppendEventReadPtr =
                    (InputEvent *)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_AppendBuffer.data);
            }
            else
            {
                // AppendEvent can reallocate the buffer if it needs more space, so make sure the read and write pointers
                // point to the equivalent places in the new buffer.
                var newBufferPtr = (byte *)m_AppendBuffer.bufferPtr.data;
                if (oldBufferPtr != newBufferPtr)
                {
                    var currentWriteOffset = (byte *)m_CurrentAppendEventWritePtr - oldBufferPtr;
                    var currentReadOffset  = (byte *)m_CurrentAppendEventReadPtr - oldBufferPtr;
                    m_CurrentAppendEventWritePtr = (InputEvent *)(newBufferPtr + currentWriteOffset);
                    m_CurrentAppendEventReadPtr  = (InputEvent *)(newBufferPtr + currentReadOffset);
                }
            }

            m_RemainingAppendEventCount++;
        }
Esempio n. 15
0
 public void Reset()
 {
     m_CurrentEvent = null;
     m_CurrentIndex = 0;
 }
Esempio n. 16
0
 /// <summary>
 /// Initialize the pointer to refer to the given event.
 /// </summary>
 /// <param name="eventPtr">Pointer to an event. Can be <c>null</c>.</param>
 public InputEventPtr(InputEvent *eventPtr)
 {
     m_EventPtr = eventPtr;
 }
Esempio n. 17
0
        private void PollJoystick(LinuxJoystickDetails js)
        {
            unsafe
            {
                const int   EventCount = 32;
                InputEvent *events     = stackalloc InputEvent[EventCount];

                long length = 0;
                while (true)
                {
                    length = (long)Libc.read(js.FileDescriptor, (void *)events, (UIntPtr)(sizeof(InputEvent) * EventCount));
                    if (length <= 0)
                    {
                        break;
                    }
                    //As we've received an event, this must be connected!
                    js.Caps.SetIsConnected(true);
                    js.State.SetIsConnected(true);

                    length /= sizeof(InputEvent);
                    for (int i = 0; i < length; i++)
                    {
                        InputEvent *e = events + i;
                        switch (e->Type)
                        {
                        case EvdevType.ABS:
                        {
                            AxisInfo axis;
                            if (js.AxisMap.TryGetValue((EvdevAxis)e->Code, out axis))
                            {
                                if (axis.Info.Maximum > axis.Info.Minimum)
                                {
                                    if (e->Code >= (int)EvdevAxis.HAT0X && e->Code <= (int)EvdevAxis.HAT3Y)
                                    {
                                        // We currently treat analogue hats as digital hats
                                        // to maintain compatibility with SDL2. We can do
                                        // better than this, however.
                                        int hat     = (e->Code - (int)EvdevAxis.HAT0X) / 2;
                                        int xy_axis = (int)axis.Axis & 0x1;
                                        int value   = e->Value.CompareTo(0) + 1;
                                        switch (xy_axis)
                                        {
                                        case 0:
                                            // X-axis
                                            js.hatStates[hat, 1] = value;
                                            break;

                                        case 1:
                                            // Y-axis
                                            js.hatStates[hat, 0] = value;
                                            break;
                                        }
                                        js.State.SetHat((JoystickHat)hat, TranslateHat(js.hatStates[hat, 0], js.hatStates[hat, 1]));
                                    }
                                    else
                                    {
                                        // This axis represents a regular axis or trigger
                                        js.State.SetAxis(
                                            axis.Axis,
                                            (short)Common.HidHelper.ScaleValue(e->Value,
                                                                               axis.Info.Minimum, axis.Info.Maximum,
                                                                               short.MinValue, short.MaxValue));
                                    }
                                }
                            }
                            break;
                        }

                        case EvdevType.KEY:
                        {
                            int button;
                            if (js.ButtonMap.TryGetValue((EvdevButton)e->Code, out button))
                            {
                                js.State.SetButton(button, e->Value != 0);
                            }
                            break;
                        }
                        }

                        // Create a serial number (total seconds in 24.8 fixed point format)
                        int sec    = (int)((long)e->Time.Seconds & 0xffffffff);
                        int msec   = (int)e->Time.MicroSeconds / 1000;
                        int packet =
                            ((sec & 0x00ffffff) << 24) |
                            Common.HidHelper.ScaleValue(msec, 0, 1000, 0, 255);
                        js.State.SetPacketNumber(packet);
                    }
                }
            }
        }
Esempio n. 18
0
        void PollJoystick(LinuxJoystickDetails js)
        {
            unsafe
            {
                const int   EventCount = 32;
                InputEvent *events     = stackalloc InputEvent[EventCount];

                long length = 0;
                while (true)
                {
                    length = (long)Libc.read(js.FileDescriptor, (void *)events, (UIntPtr)(sizeof(InputEvent) * EventCount));
                    if (length <= 0)
                    {
                        break;
                    }

                    // Only mark the joystick as connected when we actually start receiving events.
                    // Otherwise, the Xbox wireless receiver will register 4 joysticks even if no
                    // actual joystick is connected to the receiver.
                    js.Caps.SetIsConnected(true);
                    js.State.SetIsConnected(true);

                    length /= sizeof(InputEvent);
                    for (int i = 0; i < length; i++)
                    {
                        InputEvent *e = events + i;
                        switch (e->Type)
                        {
                        case EvdevType.ABS:
                        {
                            AxisInfo axis;
                            if (js.AxisMap.TryGetValue((EvdevAxis)e->Code, out axis))
                            {
                                if (axis.Info.Maximum > axis.Info.Minimum)
                                {
                                    if (e->Code >= (int)EvdevAxis.HAT0X && e->Code <= (int)EvdevAxis.HAT3Y)
                                    {
                                        // We currently treat analogue hats as digital hats
                                        // to maintain compatibility with SDL2. We can do
                                        // better than this, however.
                                        JoystickHat      hat = JoystickHat.Hat0 + (e->Code - (int)EvdevAxis.HAT0X) / 2;
                                        JoystickHatState pos = js.State.GetHat(hat);
                                        int xy_axis          = (int)axis.Axis & 0x1;
                                        switch (xy_axis)
                                        {
                                        case 0:
                                            // X-axis
                                            pos = TranslateHat(
                                                e->Value.CompareTo(0) + 1,
                                                pos.IsUp ? 0 : pos.IsDown ? 2 : 1);
                                            break;

                                        case 1:
                                            // Y-axis
                                            pos = TranslateHat(
                                                pos.IsLeft ? 0 : pos.IsRight ? 2 : 1,
                                                e->Value.CompareTo(0) + 1);
                                            break;
                                        }

                                        js.State.SetHat(hat, pos);
                                    }
                                    else
                                    {
                                        // This axis represents a regular axis or trigger
                                        js.State.SetAxis(
                                            axis.Axis,
                                            (short)Common.HidHelper.ScaleValue(e->Value,
                                                                               axis.Info.Minimum, axis.Info.Maximum,
                                                                               short.MinValue, short.MaxValue));
                                    }
                                }
                            }
                            break;
                        }

                        case EvdevType.KEY:
                        {
                            JoystickButton button;
                            if (js.ButtonMap.TryGetValue((EvdevButton)e->Code, out button))
                            {
                                js.State.SetButton(button, e->Value != 0);
                            }
                            break;
                        }
                        }

                        // Create a serial number (total seconds in 24.8 fixed point format)
                        int sec    = (int)((long)e->Time.Seconds & 0xffffffff);
                        int msec   = (int)e->Time.MicroSeconds / 1000;
                        int packet =
                            ((sec & 0x00ffffff) << 24) |
                            Common.HidHelper.ScaleValue(msec, 0, 1000, 0, 255);
                        js.State.SetPacketNumber(packet);
                    }
                }
            }
        }
Esempio n. 19
0
 internal static unsafe InputEvent *GetNextInMemory(InputEvent *current)
 {
     return((InputEvent *)((byte *)current + current->sizeInBytes));
 }
Esempio n. 20
0
        internal static unsafe InputEvent *GetNextInMemory(InputEvent *current)
        {
            var alignedSizeInBytes = NumberHelpers.AlignToMultiple(current->sizeInBytes, kAlignment);

            return((InputEvent *)((byte *)current + alignedSizeInBytes));
        }
Esempio n. 21
0
 public unsafe void QueueEvent(InputEvent *ptr)
 {
     NativeInputSystem.QueueInputEvent((IntPtr)ptr);
 }