StateEvent.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Unity.Collections;
  4. using UnityEngine.InputSystem.Utilities;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. namespace UnityEngine.InputSystem.LowLevel
  7. {
  8. /// <summary>
  9. /// A complete state snapshot for an entire input device.
  10. /// </summary>
  11. /// <remarks>
  12. /// This is a variable-sized event.
  13. /// </remarks>
  14. [StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize + 4 + kStateDataSizeToSubtract, Pack = 1)]
  15. public unsafe struct StateEvent : IInputEventTypeInfo
  16. {
  17. public const int Type = 0x53544154; // 'STAT'
  18. internal const int kStateDataSizeToSubtract = 1;
  19. [FieldOffset(0)]
  20. public InputEvent baseEvent;
  21. /// <summary>
  22. /// Type code for the state stored in the event.
  23. /// </summary>
  24. [FieldOffset(InputEvent.kBaseEventSize)]
  25. public FourCC stateFormat;
  26. [FieldOffset(InputEvent.kBaseEventSize + sizeof(int))]
  27. internal fixed byte stateData[kStateDataSizeToSubtract]; // Variable-sized.
  28. public uint stateSizeInBytes => baseEvent.sizeInBytes - (InputEvent.kBaseEventSize + sizeof(int));
  29. public void* state
  30. {
  31. get
  32. {
  33. fixed(byte* data = stateData)
  34. {
  35. return data;
  36. }
  37. }
  38. }
  39. public InputEventPtr ToEventPtr()
  40. {
  41. fixed(StateEvent * ptr = &this)
  42. {
  43. return new InputEventPtr((InputEvent*)ptr);
  44. }
  45. }
  46. public FourCC typeStatic => Type;
  47. public static int GetEventSizeWithPayload<TState>()
  48. where TState : struct
  49. {
  50. return UnsafeUtility.SizeOf<TState>() + InputEvent.kBaseEventSize + sizeof(int);
  51. }
  52. public static StateEvent* From(InputEventPtr ptr)
  53. {
  54. if (!ptr.valid)
  55. throw new ArgumentNullException(nameof(ptr));
  56. if (!ptr.IsA<StateEvent>())
  57. throw new InvalidCastException($"Cannot cast event with type '{ptr.type}' into StateEvent");
  58. return (StateEvent*)ptr.data;
  59. }
  60. /// <summary>
  61. /// Read the current state of <paramref name="device"/> and create a state event from it.
  62. /// </summary>
  63. /// <param name="device">Device to grab the state from. Must be a device that has been added to the system.</param>
  64. /// <param name="eventPtr">Receives a pointer to the newly created state event.</param>
  65. /// <param name="allocator">Which native allocator to allocate memory for the event from. By default, the buffer is
  66. /// allocated as temporary memory (<see cref="Allocator.Temp"/>. Note that this means the buffer will not be valid
  67. /// past the current frame. Use <see cref="Allocator.Persistent"/> if the buffer for the state event is meant to
  68. /// persist for longer.</param>
  69. /// <returns>Buffer of unmanaged memory allocated for the event.</returns>
  70. /// <exception cref="ArgumentException"><paramref name="device"/> has not been added to the system.</exception>
  71. /// <exception cref="ArgumentNullException"><paramref name="device"/> is <c>null</c>.</exception>
  72. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")]
  73. public static NativeArray<byte> From(InputDevice device, out InputEventPtr eventPtr, Allocator allocator = Allocator.Temp)
  74. {
  75. if (device == null)
  76. throw new ArgumentNullException(nameof(device));
  77. if (!device.added)
  78. throw new ArgumentException($"Device '{device}' has not been added to system",
  79. nameof(device));
  80. var stateFormat = device.m_StateBlock.format;
  81. var stateSize = device.m_StateBlock.alignedSizeInBytes;
  82. var stateOffset = device.m_StateBlock.byteOffset;
  83. var statePtr = (byte*)device.currentStatePtr + (int)stateOffset;
  84. var eventSize = InputEvent.kBaseEventSize + sizeof(int) + stateSize;
  85. var buffer = new NativeArray<byte>((int)eventSize, allocator);
  86. var stateEventPtr = (StateEvent*)buffer.GetUnsafePtr();
  87. stateEventPtr->baseEvent = new InputEvent(Type, (int)eventSize, device.deviceId, InputRuntime.s_Instance.currentTime);
  88. stateEventPtr->stateFormat = stateFormat;
  89. UnsafeUtility.MemCpy(stateEventPtr->state, statePtr, stateSize);
  90. eventPtr = stateEventPtr->ToEventPtr();
  91. return buffer;
  92. }
  93. }
  94. }