InputEvent.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Unity.Collections.LowLevel.Unsafe;
  4. using UnityEngine.InputSystem.Utilities;
  5. using UnityEngineInternal.Input;
  6. ////REVIEW: can we get rid of the timestamp offsetting in the player and leave that complication for the editor only?
  7. #if !UNITY_2019_2_OR_NEWER
  8. // NativeInputEventType/NativeInputEvent are marked obsolete in 19.1, because they are becoming internal in 19.2
  9. #pragma warning disable 618
  10. #endif
  11. namespace UnityEngine.InputSystem.LowLevel
  12. {
  13. /// <summary>
  14. /// A chunk of memory signaling a data transfer in the input system.
  15. /// </summary>
  16. /// <remarks>
  17. /// Input events are raw memory buffers akin to a byte array. For most uses of the input
  18. /// system, it is not necessary to be aware of the event stream in the background. Events
  19. /// are written to the internal event buffer by producers -- usually by the platform-specific
  20. /// backends sitting in the Unity runtime. Once per fixed or dynamic update (depending on
  21. /// what <see cref="InputSettings.updateMode"/> is set to), the input system then goes and
  22. /// flushes out the internal event buffer to process pending events.
  23. ///
  24. /// Events may signal general device-related occurrences (such as <see cref="DeviceConfigurationEvent"/>
  25. /// or <see cref="DeviceRemoveEvent"/>) or they may signal input activity. The latter kind of
  26. /// event is called "state events". In particular, these events are either <see cref="StateEvent"/>,
  27. /// only.
  28. ///
  29. /// Events are solely focused on input. To effect output on an input device (e.g. haptics
  30. /// effects), "commands" (see <see cref="InputDeviceCommand"/>) are used.
  31. ///
  32. /// Event processing can be listened to using <see cref="InputSystem.onEvent"/>. This callback
  33. /// will get triggered for each event as it is processed by the input system.
  34. ///
  35. /// Note that there is no "routing" mechanism for events, i.e. no mechanism by which the input
  36. /// system looks for a handler for a specific event. Instead, events represent low-level activity
  37. /// that the input system directly integrates into the state of its <see cref="InputDevice"/>
  38. /// instances.
  39. ///
  40. /// Each type of event is distinguished by its own <see cref="FourCC"/> type tag. The tag can
  41. /// be queried from the <see cref="type"/> property.
  42. ///
  43. /// Each event will receive a unique ID when queued to the internal event buffer. The ID can
  44. /// be queried using the <see cref="eventId"/> property. Over the lifetime of the input system,
  45. /// no two events will receive the same ID. If you repeatedly queue an event from the same
  46. /// memory buffer, each individual call of <see cref="InputSystem.QueueEvent"/> will result in
  47. /// its own unique event ID.
  48. ///
  49. /// All events are device-specific meaning that <see cref="deviceId"/> will always reference
  50. /// some device (which, however, may or may not translate to an <see cref="InputDevice"/>; that
  51. /// part depends on whether the input system was able to create an <see cref="InputDevice"/>
  52. /// based on the information received from the backend).
  53. ///
  54. /// To implement your own type of event, TODO (manual?)
  55. /// </remarks>
  56. /// <seealso cref="InputEventPtr"/>
  57. // NOTE: This has to be layout compatible with native events.
  58. [StructLayout(LayoutKind.Explicit, Size = kBaseEventSize, Pack = 1)]
  59. public struct InputEvent
  60. {
  61. private const uint kHandledMask = 0x80000000;
  62. private const uint kIdMask = 0x7FFFFFFF;
  63. #if UNITY_2019_2_OR_NEWER
  64. internal const int kBaseEventSize = NativeInputEvent.structSize;
  65. #else
  66. internal const int kBaseEventSize = 20;
  67. #endif
  68. /// <summary>
  69. /// Default, invalid value for <see cref="eventId"/>. Upon being queued with
  70. /// <see cref="InputSystem.QueueEvent"/>, no event will receive this ID.
  71. /// </summary>
  72. public const int InvalidEventId = 0;
  73. internal const int kAlignment = 4;
  74. [FieldOffset(0)]
  75. private NativeInputEvent m_Event;
  76. /// <summary>
  77. /// Type code for the event.
  78. /// </summary>
  79. /// <remarks>
  80. /// Each type of event has its own unique FourCC tag. For example, state events (see <see cref="StateEvent"/>)
  81. /// are tagged with "STAT". The type tag for a specific type of event can be queried from its <c>Type</c>
  82. /// property (for example, <see cref="StateEvent.Type"/>).
  83. ///
  84. /// To check whether an event has a specific type tag, you can use <see cref="InputEventPtr.IsA{T}"/>.
  85. /// </remarks>
  86. public FourCC type
  87. {
  88. get => new FourCC((int)m_Event.type);
  89. set => m_Event.type = (NativeInputEventType)(int)value;
  90. }
  91. /// <summary>
  92. /// Total size of the event in bytes.
  93. /// </summary>
  94. /// <value>Size of the event in bytes.</value>
  95. /// <remarks>
  96. /// Events are variable-size structs. This field denotes the total size of the event
  97. /// as stored in memory. This includes the full size of this struct and not just the
  98. /// "payload" of the event.
  99. ///
  100. /// <example>
  101. /// <code>
  102. /// // Store event in private buffer:
  103. /// unsafe byte[] CopyEventData(InputEventPtr eventPtr)
  104. /// {
  105. /// var sizeInBytes = eventPtr.sizeInBytes;
  106. /// var buffer = new byte[sizeInBytes];
  107. /// fixed (byte* bufferPtr = buffer)
  108. /// {
  109. /// UnsafeUtility.MemCpy(new IntPtr(bufferPtr), eventPtr.data, sizeInBytes);
  110. /// }
  111. /// return buffer;
  112. /// }
  113. /// </code>
  114. /// </example>
  115. ///
  116. /// The maximum supported size of events is <c>ushort.MaxValue</c>, i.e. events cannot
  117. /// be larger than 64KB.
  118. /// </remarks>
  119. /// <exception cref="ArgumentException"><paramref name="value"/> exceeds <c>ushort.MaxValue</c>.</exception>
  120. public uint sizeInBytes
  121. {
  122. get => m_Event.sizeInBytes;
  123. set
  124. {
  125. if (value > ushort.MaxValue)
  126. throw new ArgumentException("Maximum event size is " + ushort.MaxValue, nameof(value));
  127. m_Event.sizeInBytes = (ushort)value;
  128. }
  129. }
  130. /// <summary>
  131. /// Unique serial ID of the event.
  132. /// </summary>
  133. /// <remarks>
  134. /// Events are assigned running IDs when they are put on an event queue (see
  135. /// <see cref="InputSystem.QueueEvent"/>).
  136. /// </remarks>
  137. /// <seealso cref="InvalidEventId"/>
  138. public int eventId
  139. {
  140. get => (int)(m_Event.eventId & kIdMask);
  141. set => m_Event.eventId = value | (int)(m_Event.eventId & ~kIdMask);
  142. }
  143. /// <summary>
  144. /// ID of the device that the event is for.
  145. /// </summary>
  146. /// <remarks>
  147. /// Device IDs are allocated by the <see cref="IInputRuntime">runtime</see>. No two devices
  148. /// will receive the same ID over an application lifecycle regardless of whether the devices
  149. /// existed at the same time or not.
  150. /// </remarks>
  151. /// <seealso cref="InputDevice.deviceId"/>
  152. /// <seealso cref="InputSystem.GetDeviceById"/>
  153. /// <seealso cref="InputDevice.InvalidDeviceId"/>
  154. public int deviceId
  155. {
  156. get => m_Event.deviceId;
  157. set => m_Event.deviceId = (ushort)value;
  158. }
  159. /// <summary>
  160. /// Time that the event was generated at.
  161. /// </summary>
  162. /// <remarks>
  163. /// Times are in seconds and progress linearly in real-time. The timeline is the
  164. /// same as for <see cref="Time.realtimeSinceStartup"/>.
  165. ///
  166. /// Note that this implies that event times will reset in the editor every time you
  167. /// go into play mode. In effect, this can result in events appearing with negative
  168. /// timestamps (i.e. the event was generated before the current zero point for
  169. /// <see cref="Time.realtimeSinceStartup"/>).
  170. /// </remarks>
  171. public double time
  172. {
  173. get => m_Event.time - InputRuntime.s_CurrentTimeOffsetToRealtimeSinceStartup;
  174. set => m_Event.time = value + InputRuntime.s_CurrentTimeOffsetToRealtimeSinceStartup;
  175. }
  176. /// <summary>
  177. /// This is the raw input timestamp without the offset to <see cref="Time.realtimeSinceStartup"/>.
  178. /// </summary>
  179. /// <remarks>
  180. /// Internally, we always store all timestamps in "input time" which is relative to the native
  181. /// function GetTimeSinceStartup(). <see cref="IInputRuntime.currentTime"/> yields the current
  182. /// time on this timeline.
  183. /// </remarks>
  184. internal double internalTime
  185. {
  186. get => m_Event.time;
  187. set => m_Event.time = value;
  188. }
  189. ////FIXME: this API isn't consistent; time seems to be internalTime whereas time property is external time
  190. public InputEvent(FourCC type, int sizeInBytes, int deviceId, double time = -1)
  191. {
  192. if (time < 0)
  193. time = InputRuntime.s_Instance.currentTime;
  194. m_Event.type = (NativeInputEventType)(int)type;
  195. m_Event.sizeInBytes = (ushort)sizeInBytes;
  196. m_Event.deviceId = (ushort)deviceId;
  197. m_Event.time = time;
  198. m_Event.eventId = InvalidEventId;
  199. }
  200. // We internally use bits inside m_EventId as flags. IDs are linearly counted up by the
  201. // native input system starting at 1 so we have plenty room.
  202. // NOTE: The native system assigns IDs when events are queued so if our handled flag
  203. // will implicitly get overwritten. Having events go back to unhandled state
  204. // when they go on the queue makes sense in itself, though, so this is fine.
  205. public bool handled
  206. {
  207. get => (m_Event.eventId & kHandledMask) == kHandledMask;
  208. set
  209. {
  210. if (value)
  211. m_Event.eventId = (int)(m_Event.eventId | kHandledMask);
  212. else
  213. m_Event.eventId = (int)(m_Event.eventId & ~kHandledMask);
  214. }
  215. }
  216. public override string ToString()
  217. {
  218. return $"id={eventId} type={type} device={deviceId} size={sizeInBytes} time={time}";
  219. }
  220. /// <summary>
  221. /// Get the next event after the given one.
  222. /// </summary>
  223. /// <param name="currentPtr">A valid event pointer.</param>
  224. /// <returns>Pointer to the next event in memory.</returns>
  225. /// <remarks>
  226. /// This method applies no checks and must only be called if there is an event following the
  227. /// given one. Also, the size of the given event must be 100% as the method will simply
  228. /// take the size and advance the given pointer by it (and aligning it to <see cref="kAlignment"/>).
  229. /// </remarks>
  230. /// <seealso cref="GetNextInMemoryChecked"/>
  231. internal static unsafe InputEvent* GetNextInMemory(InputEvent* currentPtr)
  232. {
  233. Debug.Assert(currentPtr != null, "Event pointer must not be NULL");
  234. var alignedSizeInBytes = currentPtr->sizeInBytes.AlignToMultipleOf(kAlignment);
  235. return (InputEvent*)((byte*)currentPtr + alignedSizeInBytes);
  236. }
  237. /// <summary>
  238. /// Get the next event after the given one. Throw if that would point to invalid memory as indicated
  239. /// by the given memory buffer.
  240. /// </summary>
  241. /// <param name="currentPtr">A valid event pointer to an event inside <paramref name="buffer"/>.</param>
  242. /// <param name="buffer">Event buffer in which to advance to the next event.</param>
  243. /// <returns>Pointer to the next event.</returns>
  244. /// <exception cref="InvalidOperationException">There are no more events in the given buffer.</exception>
  245. internal static unsafe InputEvent* GetNextInMemoryChecked(InputEvent* currentPtr, ref InputEventBuffer buffer)
  246. {
  247. Debug.Assert(currentPtr != null, "Event pointer must not be NULL");
  248. Debug.Assert(buffer.Contains(currentPtr), "Given event is not contained in given event buffer");
  249. var alignedSizeInBytes = currentPtr->sizeInBytes.AlignToMultipleOf(kAlignment);
  250. var nextPtr = (InputEvent*)((byte*)currentPtr + alignedSizeInBytes);
  251. if (!buffer.Contains(nextPtr))
  252. throw new InvalidOperationException(
  253. $"Event '{new InputEventPtr(currentPtr)}' is last event in given buffer with size {buffer.sizeInBytes}");
  254. return nextPtr;
  255. }
  256. public static unsafe bool Equals(InputEvent* first, InputEvent* second)
  257. {
  258. if (first == second)
  259. return true;
  260. if (first == null || second == null)
  261. return false;
  262. if (first->m_Event.sizeInBytes != second->m_Event.sizeInBytes)
  263. return false;
  264. return UnsafeUtility.MemCmp(first, second, first->m_Event.sizeInBytes) == 0;
  265. }
  266. }
  267. }