Aucune description
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

InputBindingCompositeContext.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. using System;
  2. using System.Collections.Generic;
  3. namespace UnityEngine.InputSystem
  4. {
  5. /// <summary>
  6. /// Contextual data made available when processing values of composite bindings.
  7. /// </summary>
  8. /// <remarks>
  9. /// An instance of this struct is passed to <see
  10. /// cref="InputBindingComposite{TValue}.ReadValue(ref InputBindingCompositeContext)"/>.
  11. /// Use it to access contextual data such as the value for individual part bindings.
  12. ///
  13. /// Note that an instance of this struct should never be held on to past the duration
  14. /// of the call to <c>ReadValue</c>. The data it retrieves is only valid during
  15. /// the callback.
  16. /// </remarks>
  17. /// <seealso cref="InputBindingComposite"/>
  18. /// <seealso cref="InputBindingComposite{TValue}"/>
  19. /// <seealso cref="InputBindingComposite{TValue}.ReadValue(ref InputBindingCompositeContext)"/>
  20. public struct InputBindingCompositeContext
  21. {
  22. /// <summary>
  23. /// Information about a control bound to a part of a composite.
  24. /// </summary>
  25. public struct PartBinding
  26. {
  27. /// <summary>
  28. /// Identifier of the part. This is the numeric identifier stored in the public
  29. /// fields of the composite by the input system.
  30. /// </summary>
  31. public int part { get; set; }
  32. /// <summary>
  33. /// The control bound to the part.
  34. /// </summary>
  35. public InputControl control { get; set; }
  36. }
  37. /// <summary>
  38. /// Enumerate all the controls that are part of the composite.
  39. /// </summary>
  40. /// <seealso cref="InputBindingComposite.FinishSetup"/>
  41. public IEnumerable<PartBinding> controls
  42. {
  43. get
  44. {
  45. if (m_State == null)
  46. yield break;
  47. var totalBindingCount = m_State.totalBindingCount;
  48. for (var bindingIndex = m_BindingIndex + 1; bindingIndex < totalBindingCount; ++bindingIndex)
  49. {
  50. var bindingState = m_State.GetBindingState(bindingIndex);
  51. if (!bindingState.isPartOfComposite)
  52. break;
  53. var controlStartIndex = bindingState.controlStartIndex;
  54. for (var i = 0; i < bindingState.controlCount; ++i)
  55. {
  56. var control = m_State.controls[controlStartIndex + i];
  57. yield return new PartBinding
  58. {
  59. part = bindingState.partIndex,
  60. control = control
  61. };
  62. }
  63. }
  64. }
  65. }
  66. public float EvaluateMagnitude(int partNumber)
  67. {
  68. return m_State.EvaluateCompositePartMagnitude(m_BindingIndex, partNumber);
  69. }
  70. /// <summary>
  71. /// Read the value of the giving part binding.
  72. /// </summary>
  73. /// <param name="partNumber">Number of the part to read. This is assigned
  74. /// automatically by the input system and should be treated as an opaque
  75. /// identifier. See the example below.</param>
  76. /// <typeparam name="TValue">Type of value to read. This must match the
  77. /// value type expected from controls bound to the part.</typeparam>
  78. /// <returns>The value read from the part bindings.</returns>
  79. /// <exception cref="InvalidOperationException">The given <typeparamref name="TValue"/>
  80. /// value type does not match the actual value type of the control(s) bound
  81. /// to the part.</exception>
  82. /// <remarks>
  83. /// If no control is bound to the given part, the return value will always
  84. /// be <c>default(TValue)</c>. If a single control is bound to the part, the
  85. /// value will be that of the control. If multiple controls are bound to a
  86. /// part, the return value will be that greatest one according to <c>IComparable</c>
  87. /// implemented by <typeparamref name="TValue"/>.
  88. ///
  89. /// Note that this method only works with values that are <c>IComparable</c>.
  90. /// To read a value type that is not <c>IComparable</c> or to supply a custom
  91. /// comparer, use <see cref="ReadValue{TValue,TComparer}(int,TComparer)"/>.
  92. ///
  93. /// If an invalid <paramref name="partNumber"/> is supplied, the return value
  94. /// will simply be <c>default(TValue)</c>. No exception is thrown.
  95. ///
  96. /// <example>
  97. /// <code>
  98. /// public class MyComposite : InputBindingComposite&lt;float&gt;
  99. /// {
  100. /// // Defines a "part" binding for the composite. Each part can be
  101. /// // bound to arbitrary many times (including not at all). The "layout"
  102. /// // property of the attribute we supply determines what kind of
  103. /// // control is expected to be bound to the part.
  104. /// //
  105. /// // When initializing a composite instance, the input system will
  106. /// // automatically assign part numbers and store them in the fields
  107. /// // we define here.
  108. /// [InputControl(layout = "Button")]
  109. /// public int firstPart;
  110. ///
  111. /// // Defines a second part.
  112. /// [InputControl(layout = "Vector2")]
  113. /// public int secondPart;
  114. ///
  115. /// public override float ReadValue(ref InputBindingCompositeContext context)
  116. /// {
  117. /// // Read the button.
  118. /// var firstValue = context.ReadValue&lt;float&gt;();
  119. ///
  120. /// // Read the vector.
  121. /// var secondValue = context.ReadValue&lt;Vector2&gt;();
  122. ///
  123. /// // Perform some computation based on the inputs. Here, we just
  124. /// // scale the vector by the value we got from the button.
  125. /// return secondValue * firstValue;
  126. /// }
  127. /// }
  128. /// </code>
  129. /// </example>
  130. /// </remarks>
  131. /// <seealso cref="ReadValue{TValue,TComparer}(int,TComparer)"/>
  132. /// <seealso cref="InputControl{TValue}.ReadValue"/>
  133. public unsafe TValue ReadValue<TValue>(int partNumber)
  134. where TValue : struct, IComparable<TValue>
  135. {
  136. if (m_State == null)
  137. return default;
  138. return m_State.ReadCompositePartValue<TValue, DefaultComparer<TValue>>
  139. (m_BindingIndex, partNumber, null, out _);
  140. }
  141. /// <summary>
  142. /// Same as <see cref="ReadValue{TValue}(int)"/> but also return the control
  143. /// from which the value was read.
  144. /// </summary>
  145. /// <param name="partNumber">Number of the part to read. This is assigned
  146. /// automatically by the input system and should be treated as an opaque
  147. /// identifier.</param>
  148. /// <param name="sourceControl">Receives the <see cref="InputControl"/> from
  149. /// which the value was read. If multiple controls are bound to the given part,
  150. /// this is the control whose value was ultimately selected. Will be set to
  151. /// <c>null</c> if <paramref name="partNumber"/> is not a valid part or if no
  152. /// controls are bound to the part.</param>
  153. /// <typeparam name="TValue">Type of value to read. This must match the
  154. /// value type expected from controls bound to the part.</typeparam>
  155. /// <returns>The value read from the part bindings.</returns>
  156. /// <remarks>
  157. /// Like <see cref="ReadValue{TValue}(int)"/>, this method relies on using <c>IComparable</c>
  158. /// implemented by <typeparamref name="TValue"/> to determine the greatest value
  159. /// if multiple controls are bound to the specified part.
  160. /// </remarks>
  161. /// <seealso cref="ReadValue{TValue}(int)"/>
  162. public unsafe TValue ReadValue<TValue>(int partNumber, out InputControl sourceControl)
  163. where TValue : struct, IComparable<TValue>
  164. {
  165. if (m_State == null)
  166. {
  167. sourceControl = null;
  168. return default;
  169. }
  170. var value = m_State.ReadCompositePartValue<TValue, DefaultComparer<TValue>>(m_BindingIndex, partNumber,
  171. null, out var controlIndex);
  172. if (controlIndex != InputActionState.kInvalidIndex)
  173. sourceControl = m_State.controls[controlIndex];
  174. else
  175. sourceControl = null;
  176. return value;
  177. }
  178. ////TODO: once we can break the API, remove the versions that rely on comparers and do everything through magnitude
  179. /// <summary>
  180. /// Read the value of the given part bindings and use the given <paramref name="comparer"/>
  181. /// to determine which value to return if multiple controls are bound to the part.
  182. /// </summary>
  183. /// <param name="partNumber">Number of the part to read. This is assigned
  184. /// automatically by the input system and should be treated as an opaque
  185. /// identifier.</param>
  186. /// <param name="comparer">Instance of <typeparamref name="TComparer"/> for comparing
  187. /// multiple values.</param>
  188. /// <typeparam name="TValue">Type of value to read. This must match the
  189. /// value type expected from controls bound to the part.</typeparam>
  190. /// <returns>The value read from the part bindings.</returns>
  191. /// <typeparam name="TComparer">Comparer to use if multiple controls are bound to
  192. /// the given part. All values will be compared using <c>TComparer.Compare</c> and
  193. /// the greatest value will be returned.</typeparam>
  194. /// <returns>The value read from the part bindings.</returns>
  195. /// <remarks>
  196. /// This method is a useful alternative to <see cref="ReadValue{TValue}(int)"/> for
  197. /// value types that do not implement <c>IComparable</c> or when the default comparison
  198. /// behavior is undesirable.
  199. ///
  200. /// <example>
  201. /// <code>
  202. /// public class CompositeWithVector2Part : InputBindingComposite&lt;Vector2&gt;
  203. /// {
  204. /// [InputControl(layout = "Vector2")]
  205. /// public int part;
  206. ///
  207. /// public override Vector2 ReadValue(ref InputBindingCompositeContext context)
  208. /// {
  209. /// // Return the Vector3 with the greatest magnitude.
  210. /// return context.ReadValue&lt;Vector2, Vector2MagnitudeComparer&gt;(part);
  211. /// }
  212. /// }
  213. /// </code>
  214. /// </example>
  215. /// </remarks>
  216. /// <seealso cref="Utilities.Vector2MagnitudeComparer"/>
  217. /// <seealso cref="Utilities.Vector3MagnitudeComparer"/>
  218. public unsafe TValue ReadValue<TValue, TComparer>(int partNumber, TComparer comparer = default)
  219. where TValue : struct
  220. where TComparer : IComparer<TValue>
  221. {
  222. if (m_State == null)
  223. return default;
  224. return m_State.ReadCompositePartValue<TValue, TComparer>(
  225. m_BindingIndex, partNumber, null, out _, comparer);
  226. }
  227. /// <summary>
  228. /// Like <see cref="ReadValue{TValue,TComparer}(int,TComparer)"/> but also return
  229. /// the control from which the value has ultimately been read.
  230. /// </summary>
  231. /// <param name="partNumber">Number of the part to read. This is assigned
  232. /// automatically by the input system and should be treated as an opaque
  233. /// identifier.</param>
  234. /// <param name="sourceControl">Receives the <see cref="InputControl"/> from
  235. /// which the value was read. If multiple controls are bound to the given part,
  236. /// this is the control whose value was ultimately selected. Will be set to
  237. /// <c>null</c> if <paramref name="partNumber"/> is not a valid part or if no
  238. /// controls are bound to the part.</param>
  239. /// <param name="comparer">Instance of <typeparamref name="TComparer"/> for comparing
  240. /// multiple values.</param>
  241. /// <typeparam name="TValue">Type of value to read. This must match the
  242. /// value type expected from controls bound to the part.</typeparam>
  243. /// <returns>The value read from the part bindings.</returns>
  244. /// <typeparam name="TComparer">Comparer to use if multiple controls are bound to
  245. /// the given part. All values will be compared using <c>TComparer.Compare</c> and
  246. /// the greatest value will be returned.</typeparam>
  247. /// <returns>The value read from the part bindings.</returns>
  248. public unsafe TValue ReadValue<TValue, TComparer>(int partNumber, out InputControl sourceControl, TComparer comparer = default)
  249. where TValue : struct
  250. where TComparer : IComparer<TValue>
  251. {
  252. if (m_State == null)
  253. {
  254. sourceControl = null;
  255. return default;
  256. }
  257. var value = m_State.ReadCompositePartValue<TValue, TComparer>(m_BindingIndex, partNumber, null,
  258. out var controlIndex, comparer);
  259. if (controlIndex != InputActionState.kInvalidIndex)
  260. sourceControl = m_State.controls[controlIndex];
  261. else
  262. sourceControl = null;
  263. return value;
  264. }
  265. /// <summary>
  266. /// Like <see cref="ReadValue{TValue}(int)"/> but treat bound controls as buttons. This means
  267. /// that custom <see cref="Controls.ButtonControl.pressPoint"/> are respected and that floating-point
  268. /// values from non-ButtonControls will be compared to <see cref="InputSettings.defaultButtonPressPoint"/>.
  269. /// </summary>
  270. /// <param name="partNumber">Number of the part to read. This is assigned
  271. /// automatically by the input system and should be treated as an opaque
  272. /// identifier.</param>
  273. /// <returns>True if any button bound to the part is pressed.</returns>
  274. /// <remarks>
  275. /// This method expects all controls bound to the part to be of type <c>InputControl&lt;float&gt;</c>.
  276. ///
  277. /// This method is different from just calling <see cref="ReadValue{TValue}(int)"/> with a <c>float</c>
  278. /// parameter and comparing the result to <see cref="InputSettings.defaultButtonPressPoint"/> in that
  279. /// custom press points set on individual ButtonControls will be respected.
  280. /// </remarks>
  281. /// <seealso cref="Controls.ButtonControl"/>
  282. /// <seealso cref="InputSettings.defaultButtonPressPoint"/>
  283. public unsafe bool ReadValueAsButton(int partNumber)
  284. {
  285. if (m_State == null)
  286. return default;
  287. ////REVIEW: wouldn't this have to take release points into account now?
  288. var buttonValue = false;
  289. m_State.ReadCompositePartValue<float, DefaultComparer<float>>(m_BindingIndex, partNumber, &buttonValue,
  290. out _);
  291. return buttonValue;
  292. }
  293. public unsafe void ReadValue(int partNumber, void* buffer, int bufferSize)
  294. {
  295. m_State?.ReadCompositePartValue(m_BindingIndex, partNumber, buffer, bufferSize);
  296. }
  297. public object ReadValueAsObject(int partNumber)
  298. {
  299. return m_State.ReadCompositePartValueAsObject(m_BindingIndex, partNumber);
  300. }
  301. /// <summary>
  302. /// Return the timestamp (see <see cref="LowLevel.InputEvent.time"/>) for when the given
  303. /// binding part crossed the button press threshold (see <see cref="Controls.ButtonControl.pressPoint"/>).
  304. /// </summary>
  305. /// <param name="partNumber">Number of the part to read. This is assigned
  306. /// automatically by the input system and should be treated as an opaque
  307. /// identifier.</param>
  308. /// <returns>Returns the time at which the given part binding moved into "press" state or 0 if there's
  309. /// current no press.</returns>
  310. /// <remarks>
  311. /// If the given part has more than a single binding and/or more than a single bound control, the <em>earliest</em>
  312. /// press time is returned.
  313. /// </remarks>
  314. public double GetPressTime(int partNumber)
  315. {
  316. return m_State.GetCompositePartPressTime(m_BindingIndex, partNumber);
  317. }
  318. internal InputActionState m_State;
  319. internal int m_BindingIndex;
  320. private struct DefaultComparer<TValue> : IComparer<TValue>
  321. where TValue : IComparable<TValue>
  322. {
  323. public int Compare(TValue x, TValue y)
  324. {
  325. return x.CompareTo(y);
  326. }
  327. }
  328. }
  329. }