Newer
Older
HoloAnatomy / Assets / HoloToolkit / Input / Scripts / InputSources / RawInteractionInputSource.cs
SURFACEBOOK2\jackwynne on 25 May 2018 10 KB v1
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See LICENSE in the project root for license information.
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7.  
  8. #if UNITY_WSA && !UNITY_2017_2_OR_NEWER
  9. using UnityEngine.VR.WSA.Input;
  10. #endif
  11.  
  12. namespace HoloToolkit.Unity.InputModule
  13. {
  14. /// <summary>
  15. /// Input source for raw interactions sources information, which gives finer details about current source state and position
  16. /// than the standard GestureRecognizer.
  17. /// This mostly allows users to access the source up/down and detected/lost events,
  18. /// which are not communicated as part of standard Windows gestures.
  19. /// </summary>
  20. /// <remarks>
  21. /// This input source only triggers SourceUp/SourceDown and SourceDetected/SourceLost.
  22. /// Everything else is handled by InteractionInputSource.
  23. /// </remarks>
  24. [Obsolete("Will be removed in a future release")]
  25. public class RawInteractionInputSource : BaseInputSource
  26. {
  27. /// <summary>
  28. /// Data for an interaction source.
  29. /// </summary>
  30. private class SourceData
  31. {
  32. public SourceData(uint sourceId)
  33. {
  34. SourceId = sourceId;
  35. HasPosition = false;
  36. SourcePosition = Vector3.zero;
  37. IsSourceDown = false;
  38. IsSourceDownPending = false;
  39. SourceStateChanged = false;
  40. SourceStateUpdateTimer = -1;
  41. }
  42.  
  43. public readonly uint SourceId;
  44. public bool HasPosition;
  45. public Vector3 SourcePosition;
  46. public bool IsSourceDown;
  47. public bool IsSourceDownPending;
  48. public bool SourceStateChanged;
  49. public float SourceStateUpdateTimer;
  50. }
  51.  
  52. /// <summary>
  53. /// Delay before a source press is considered.
  54. /// This mitigates fake source taps that can sometimes be detected while the input source is moving.
  55. /// </summary>
  56. private const float SourcePressDelay = 0.07f;
  57.  
  58. [Tooltip("Use unscaled time. This is useful for games that have a pause mechanism or otherwise adjust the game timescale.")]
  59. public bool UseUnscaledTime = true;
  60.  
  61. /// <summary>
  62. /// Dictionary linking each source ID to its data.
  63. /// </summary>
  64. private readonly Dictionary<uint, SourceData> sourceIdToData = new Dictionary<uint, SourceData>(4);
  65. private readonly List<uint> pendingSourceIdDeletes = new List<uint>();
  66.  
  67. // HashSets used to be able to quickly update the sources data when they become visible / not visible
  68. private readonly HashSet<uint> currentSources = new HashSet<uint>();
  69. private readonly HashSet<uint> newSources = new HashSet<uint>();
  70.  
  71. public override SupportedInputInfo GetSupportedInputInfo(uint sourceId)
  72. {
  73. SupportedInputInfo retVal = SupportedInputInfo.None;
  74.  
  75. SourceData sourceData;
  76. if (sourceIdToData.TryGetValue(sourceId, out sourceData))
  77. {
  78. if (sourceData.HasPosition)
  79. {
  80. retVal |= SupportedInputInfo.Position;
  81. }
  82. }
  83.  
  84. return retVal;
  85. }
  86.  
  87. public override bool TryGetMenu(uint sourceId, out bool isPressed)
  88. {
  89. throw new NotImplementedException();
  90. }
  91.  
  92. public override bool TryGetPointerPosition(uint sourceId, out Vector3 position)
  93. {
  94. SourceData sourceData;
  95. if (sourceIdToData.TryGetValue(sourceId, out sourceData))
  96. {
  97. if (sourceData.HasPosition)
  98. {
  99. position = sourceData.SourcePosition;
  100. return true;
  101. }
  102. }
  103.  
  104. // Else, the source doesn't have positional information
  105. position = Vector3.zero;
  106. return false;
  107. }
  108.  
  109. public override bool TryGetPointerRotation(uint sourceId, out Quaternion orientation)
  110. {
  111. // Orientation is not supported by any Windows interaction sources
  112. orientation = Quaternion.identity;
  113. return false;
  114. }
  115.  
  116. public override bool TryGetSourceKind(uint sourceId, out InteractionSourceInfo sourceKind)
  117. {
  118. throw new NotImplementedException();
  119. }
  120.  
  121. public override bool TryGetGripPosition(uint sourceId, out Vector3 position)
  122. {
  123. throw new NotImplementedException();
  124. }
  125.  
  126. public override bool TryGetGripRotation(uint sourceId, out Quaternion rotation)
  127. {
  128. throw new NotImplementedException();
  129. }
  130.  
  131. public override bool TryGetThumbstick(uint sourceId, out bool isPressed, out Vector2 position)
  132. {
  133. throw new NotImplementedException();
  134. }
  135.  
  136. public override bool TryGetTouchpad(uint sourceId, out bool isPressed, out bool isTouched, out Vector2 position)
  137. {
  138. throw new NotImplementedException();
  139. }
  140.  
  141. public override bool TryGetSelect(uint sourceId, out bool isPressed, out double pressedValue)
  142. {
  143. throw new NotImplementedException();
  144. }
  145.  
  146. public override bool TryGetGrasp(uint sourceId, out bool isPressed)
  147. {
  148. throw new NotImplementedException();
  149. }
  150.  
  151. public override bool TryGetPointingRay(uint sourceId, out Ray pointingRay)
  152. {
  153. throw new NotImplementedException();
  154. }
  155.  
  156. private void Update()
  157. {
  158. newSources.Clear();
  159. currentSources.Clear();
  160.  
  161. UpdateSourceData();
  162. SendSourceVisibilityEvents();
  163. }
  164.  
  165. /// <summary>
  166. /// Update the source data for the currently detected sources.
  167. /// </summary>
  168. private void UpdateSourceData()
  169. {
  170. #if UNITY_WSA && !UNITY_2017_2_OR_NEWER
  171. // Poll for updated reading from hands
  172. InteractionSourceState[] sourceStates = InteractionManager.GetCurrentReading();
  173. if (sourceStates != null)
  174. {
  175. for (var i = 0; i < sourceStates.Length; ++i)
  176. {
  177. InteractionSourceState handSource = sourceStates[i];
  178. SourceData sourceData = GetOrAddSourceData(handSource.source);
  179. currentSources.Add(handSource.source.id);
  180.  
  181. UpdateSourceState(handSource, sourceData);
  182. }
  183. }
  184. #endif
  185. }
  186.  
  187. #if UNITY_WSA && !UNITY_2017_2_OR_NEWER
  188. /// <summary>
  189. /// Gets the source data for the specified interaction source if it already exists, otherwise creates it.
  190. /// </summary>
  191. /// <param name="interactionSource">Interaction source for which data should be retrieved.</param>
  192. /// <returns>The source data requested.</returns>
  193. private SourceData GetOrAddSourceData(InteractionSource interactionSource)
  194. {
  195. SourceData sourceData;
  196. if (!sourceIdToData.TryGetValue(interactionSource.id, out sourceData))
  197. {
  198. sourceData = new SourceData(interactionSource.id);
  199. sourceIdToData.Add(sourceData.SourceId, sourceData);
  200. newSources.Add(sourceData.SourceId);
  201. }
  202.  
  203. return sourceData;
  204. }
  205.  
  206. /// <summary>
  207. /// Updates the source positional information.
  208. /// </summary>
  209. /// <param name="interactionSource">Interaction source to use to update the position.</param>
  210. /// <param name="sourceData">SourceData structure to update.</param>
  211. private void UpdateSourceState(InteractionSourceState interactionSource, SourceData sourceData)
  212. {
  213. // Update source position
  214. Vector3 sourcePosition;
  215. if (interactionSource.properties.location.TryGetPosition(out sourcePosition))
  216. {
  217. sourceData.HasPosition = true;
  218. sourceData.SourcePosition = sourcePosition;
  219. }
  220.  
  221. // Check for source presses
  222. if (interactionSource.pressed != sourceData.IsSourceDownPending)
  223. {
  224. sourceData.IsSourceDownPending = interactionSource.pressed;
  225. sourceData.SourceStateUpdateTimer = SourcePressDelay;
  226. }
  227.  
  228. // Source presses are delayed to mitigate issue with hand position shifting during air tap
  229. sourceData.SourceStateChanged = false;
  230. if (sourceData.SourceStateUpdateTimer >= 0)
  231. {
  232. float deltaTime = UseUnscaledTime
  233. ? Time.unscaledDeltaTime
  234. : Time.deltaTime;
  235.  
  236. sourceData.SourceStateUpdateTimer -= deltaTime;
  237. if (sourceData.SourceStateUpdateTimer < 0)
  238. {
  239. sourceData.IsSourceDown = sourceData.IsSourceDownPending;
  240. sourceData.SourceStateChanged = true;
  241. }
  242. }
  243.  
  244. SendSourceStateEvents(sourceData);
  245. }
  246. #endif
  247.  
  248. /// <summary>
  249. /// Sends the events for source state changes.
  250. /// </summary>
  251. /// <param name="sourceData">Source data for which events should be sent.</param>
  252. private void SendSourceStateEvents(SourceData sourceData)
  253. {
  254. // Source pressed/released events
  255. if (sourceData.SourceStateChanged)
  256. {
  257. if (sourceData.IsSourceDown)
  258. {
  259. InputManager.Instance.RaiseSourceDown(this, sourceData.SourceId, InteractionSourcePressInfo.Select);
  260. }
  261. else
  262. {
  263. InputManager.Instance.RaiseSourceUp(this, sourceData.SourceId, InteractionSourcePressInfo.Select);
  264. }
  265. }
  266. }
  267.  
  268. /// <summary>
  269. /// Sends the events for source visibility changes.
  270. /// </summary>
  271. private void SendSourceVisibilityEvents()
  272. {
  273. // Send event for new sources that were added
  274. foreach (uint newSource in newSources)
  275. {
  276. InputManager.Instance.RaiseSourceDetected(this, newSource);
  277. }
  278.  
  279. // Send event for sources that are no longer visible and remove them from our dictionary
  280. foreach (uint existingSource in sourceIdToData.Keys)
  281. {
  282. if (!currentSources.Contains(existingSource))
  283. {
  284. pendingSourceIdDeletes.Add(existingSource);
  285. InputManager.Instance.RaiseSourceLost(this, existingSource);
  286. }
  287. }
  288.  
  289. // Remove pending source IDs
  290. for (int i = 0; i < pendingSourceIdDeletes.Count; ++i)
  291. {
  292. sourceIdToData.Remove(pendingSourceIdDeletes[i]);
  293. }
  294. pendingSourceIdDeletes.Clear();
  295. }
  296. }
  297. }