File size: 3,963 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.InputSystem.Utilities;

namespace UnityEngine.InputSystem.LowLevel
{
    /// <summary>
    /// Partial state update for an input device.
    /// </summary>
    /// <remarks>
    /// Avoids having to send a full state memory snapshot when only a small
    /// part of the state has changed.
    /// </remarks>
    [StructLayout(LayoutKind.Explicit, Pack = 1, Size = InputEvent.kBaseEventSize + 9)]
    public unsafe struct DeltaStateEvent : IInputEventTypeInfo
    {
        public const int Type = 0x444C5441; // 'DLTA'

        [FieldOffset(0)]
        public InputEvent baseEvent;

        [FieldOffset(InputEvent.kBaseEventSize)]
        public FourCC stateFormat;

        [FieldOffset(InputEvent.kBaseEventSize + 4)]
        public uint stateOffset;

        [FieldOffset(InputEvent.kBaseEventSize + 8)]
        internal fixed byte stateData[1]; // Variable-sized.

        public uint deltaStateSizeInBytes => baseEvent.sizeInBytes - (InputEvent.kBaseEventSize + 8);

        public void* deltaState
        {
            get
            {
                fixed(byte* data = stateData)
                {
                    return data;
                }
            }
        }

        public FourCC typeStatic => Type;

        public InputEventPtr ToEventPtr()
        {
            fixed(DeltaStateEvent * ptr = &this)
            {
                return new InputEventPtr((InputEvent*)ptr);
            }
        }

        public static DeltaStateEvent* From(InputEventPtr ptr)
        {
            if (!ptr.valid)
                throw new ArgumentNullException(nameof(ptr));
            if (!ptr.IsA<DeltaStateEvent>())
                throw new InvalidCastException($"Cannot cast event with type '{ptr.type}' into DeltaStateEvent");

            return FromUnchecked(ptr);
        }

        internal static DeltaStateEvent* FromUnchecked(InputEventPtr ptr)
        {
            return (DeltaStateEvent*)ptr.data;
        }

        public static NativeArray<byte> From(InputControl control, out InputEventPtr eventPtr,  Allocator allocator = Allocator.Temp)
        {
            if (control == null)
                throw new ArgumentNullException(nameof(control));
            var device = control.device;
            if (!device.added)
                throw new ArgumentException($"Device for control '{control}' has not been added to system",
                    nameof(control));

            ref var deviceStateBlock = ref device.m_StateBlock;
            ref var controlStateBlock = ref control.m_StateBlock;

            var stateFormat = deviceStateBlock.format; // The event is sent against the *device* so that's the state format we use.
            var stateSize = 0u;
            if (controlStateBlock.bitOffset != 0)
                stateSize = (controlStateBlock.bitOffset + controlStateBlock.sizeInBits + 7) / 8;
            else
                stateSize = controlStateBlock.alignedSizeInBytes;
            var stateOffset = controlStateBlock.byteOffset;
            var statePtr = (byte*)control.currentStatePtr + (int)stateOffset;
            var eventSize = InputEvent.kBaseEventSize + sizeof(int) * 2 + stateSize;

            var buffer = new NativeArray<byte>((int)eventSize.AlignToMultipleOf(4), allocator);
            var stateEventPtr = (DeltaStateEvent*)buffer.GetUnsafePtr();

            stateEventPtr->baseEvent = new InputEvent(Type, (int)eventSize, device.deviceId, InputRuntime.s_Instance.currentTime);
            stateEventPtr->stateFormat = stateFormat;
            stateEventPtr->stateOffset = controlStateBlock.byteOffset - deviceStateBlock.byteOffset; // Make offset relative to device.
            UnsafeUtility.MemCpy(stateEventPtr->deltaState, statePtr, stateSize);

            eventPtr = stateEventPtr->ToEventPtr();
            return buffer;
        }
    }
}