Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152
  1. using System;
  2. using Unity.Collections.LowLevel.Unsafe;
  3. using UnityEngine.InputSystem.Controls;
  4. using UnityEngine.InputSystem.LowLevel;
  5. using UnityEngine.InputSystem.Utilities;
  6. using UnityEngine.Serialization;
  7. ////TODO: add way to retrieve the binding correspond to a control
  8. ////TODO: add way to retrieve the currently ongoing interaction and also add way to know how long it's been going on
  9. ////FIXME: control goes back to invalid when the action ends, so there's no guarantee you can get to the control through the polling API
  10. ////FIXME: Whether a control from a binding that's part of a composite appears on an action is currently not consistently enforced.
  11. //// If it mentions the action, it appears on the action. Otherwise it doesn't. The controls should consistently appear on the
  12. //// action based on what action the *composite* references.
  13. ////REVIEW: Should we bring the checkboxes for actions back? We tried to "simplify" things by collapsing everything into a InputActionTypes
  14. //// and making the various behavior toggles implicit in that. However, my impression is that this has largely backfired by making
  15. //// it opaque what the choices actually entail and by giving no way out if the choices for one reason or another don't work out
  16. //// perfectly.
  17. ////
  18. //// My impression is that at least two the following two checkboxes would make sense:
  19. //// 1) Initial State Check? Whether the action should immediately sync to the current state of controls when enabled.
  20. //// 2) Resolve Conflicting Inputs? Whether the action should try to resolve conflicts between multiple concurrent inputs.
  21. ////
  22. //// I'm fine hiding this under an "Advanced" foldout or something. But IMO, control over this should be available to the user.
  23. ////
  24. //// In the same vein, we probably also should expose control over how an action behaves on focus loss (https://forum.unity.com/threads/actions-canceled-when-game-loses-focus.855217/).
  25. ////REVIEW: I think the action system as it is today offers too many ways to shoot yourself in the foot. It has
  26. //// flexibility but at the same time has abundant opportunity for ending up with dysfunction. Common setups
  27. //// have to come preconfigured and work robustly for the user without requiring much understanding of how
  28. //// the system fits together.
  29. ////REVIEW: add "lastControl" property? (and maybe a lastDevice at the InputActionMap/Asset level?)
  30. ////REVIEW: have single delegate instead of separate performed/started/canceled callbacks?
  31. ////REVIEW: Do we need to have separate display names for actions?
  32. ////REVIEW: what about having the concept of "consumed" on the callback context?
  33. ////REVIEW: have "Always Enabled" toggle on actions?
  34. ////TODO: allow temporarily disabling individual bindings (flag on binding) such that no re-resolve is needed
  35. //// (SilenceBinding? DisableBinding)
  36. namespace UnityEngine.InputSystem
  37. {
  38. /// <summary>
  39. /// A named input signal that can flexibly decide which input data to tap.
  40. /// </summary>
  41. /// <remarks>
  42. /// An input action is an abstraction over the source of input(s) it receives. They are
  43. /// most useful for representing input as "logical" concepts (e.g. "jump") rather than
  44. /// as "physical" inputs (e.g. "space bar on keyboard pressed").
  45. ///
  46. /// In its most basic form, an action is simply an object along with a collection of
  47. /// bindings that trigger the action.
  48. ///
  49. /// <example>
  50. /// <code>
  51. /// // A simple action can be created directly using `new`. If desired, a binding
  52. /// // can be specified directly as part of construction.
  53. /// var action = new InputAction(binding: "&lt;Gamepad&gt;/buttonSouth");
  54. ///
  55. /// // Additional bindings can be added using `AddBinding`.
  56. /// action.AddBinding("&lt;Mouse&gt;/leftButton");
  57. /// </code>
  58. /// </example>
  59. ///
  60. /// Bindings use control path expressions to reference controls. See <see cref="InputBinding"/>
  61. /// for more details. There may be arbitrary many bindings targeting a single action. The
  62. /// list of bindings targeting an action can be obtained through <see cref="bindings"/>.
  63. ///
  64. /// By itself an action does not do anything until it is enabled:
  65. ///
  66. /// <example>
  67. /// <code>
  68. /// action.Enable();
  69. /// </code>
  70. /// </example>
  71. ///
  72. /// Once enabled, the action will actively monitor all controls on devices present
  73. /// in the system (see <see cref="InputSystem.devices"/>) that match any of the binding paths
  74. /// associated with the action. If you want to restrict the set of bindings used at runtime
  75. /// or restrict the set of devices which controls are chosen from, you can do so using
  76. /// <see cref="bindingMask"/> or, if the action is part of an <see cref="InputActionMap"/>,
  77. /// by setting the <see cref="InputActionMap.devices"/> property of the action map. The
  78. /// controls that an action uses can be queried using the <see cref="controls"/> property.
  79. ///
  80. /// When input is received on controls bound to an action, the action will trigger callbacks
  81. /// in response. These callbacks are <see cref="started"/>, <see cref="performed"/>, and
  82. /// <see cref="canceled"/>. The callbacks are triggered as part of input system updates
  83. /// (see <see cref="InputSystem.Update"/>), i.e. they happen before the respective
  84. /// <c>MonoBehaviour.Update</c> or <c>MonoBehaviour.FixedUpdate</c> methods
  85. /// get executed (depending on which <see cref="InputSettings.updateMode"/> the system is
  86. /// set to).
  87. ///
  88. /// In what order and how those callbacks get triggered depends on both the <see cref="type"/>
  89. /// of the action as well as on the interactions (see <see cref="IInputInteraction"/>) present
  90. /// on the bindings of the action. The default behavior is that when a control is actuated
  91. /// (that is, moving away from its resting position), <see cref="started"/> is called and then
  92. /// <see cref="performed"/>. Subsequently, whenever the a control further changes value to
  93. /// anything other than its default value, <see cref="performed"/> will be called again.
  94. /// Finally, when the control moves back to its default value (i.e. resting position),
  95. /// <see cref="canceled"/> is called.
  96. ///
  97. /// To hook into the callbacks, there are several options available to you. The most obvious
  98. /// one is to hook directly into <see cref="started"/>, <see cref="performed"/>, and/or
  99. /// <see cref="canceled"/>. In these callbacks, you will receive a <see cref="CallbackContext"/>
  100. /// with information about how the action got triggered. For example, you can use <see
  101. /// cref="CallbackContext.ReadValue{TValue}"/> to read the value from the binding that triggered
  102. /// or use <see cref="CallbackContext.interaction"/> to find the interaction that is in progress.
  103. ///
  104. /// <example>
  105. /// <code>
  106. /// action.started += context => Debug.Log($"{context.action} started");
  107. /// action.performed += context => Debug.Log($"{context.action} performed");
  108. /// action.canceled += context => Debug.Log($"{context.action} canceled");
  109. /// </code>
  110. /// </example>
  111. ///
  112. /// Alternatively, you can use the <see cref="InputActionMap.actionTriggered"/> callback for
  113. /// actions that are part of an action map or the global <see cref="InputSystem.onActionChange"/>
  114. /// callback to globally listen for action activity. To simply record action activity instead
  115. /// of responding to it directly, you can use <see cref="InputActionTrace"/>.
  116. ///
  117. /// If you prefer to poll an action directly as part of your <c>MonoBehaviour.Update</c>
  118. /// or <c>MonoBehaviour.FixedUpdate</c> logic, you can do so using the <see cref="triggered"/>
  119. /// and <see cref="ReadValue{TValue}"/> methods.
  120. ///
  121. /// <example>
  122. /// <code>
  123. /// protected void Update()
  124. /// {
  125. /// // For a button type action.
  126. /// if (action.triggered)
  127. /// /* ... */;
  128. ///
  129. /// // For a value type action.
  130. /// // (Vector2 is just an example; pick the value type that is the right
  131. /// // one according to the bindings you have)
  132. /// var v = action.ReadValue&lt;Vector2&gt;();
  133. /// }
  134. /// </code>
  135. /// </example>
  136. ///
  137. /// Note that actions are not generally frame-based. What this means is that an action
  138. /// will observe any value change on its connected controls, even if the control changes
  139. /// value multiple times in the same frame. In practice, this means that, for example,
  140. /// no button press will get missed.
  141. ///
  142. /// Actions can be grouped into maps (see <see cref="InputActionMap"/>) which can in turn
  143. /// be grouped into assets (see <see cref="InputActionAsset"/>).
  144. ///
  145. /// Please note that actions are a player-only feature. They are not supported in
  146. /// edit mode.
  147. ///
  148. /// For more in-depth reading on actions, see the <a href="../manual/Actions.html">manual</a>.
  149. /// </remarks>
  150. /// <seealso cref="InputActionMap"/>
  151. /// <seealso cref="InputActionAsset"/>
  152. /// <seealso cref="InputBinding"/>
  153. [Serializable]
  154. public sealed class InputAction : ICloneable, IDisposable
  155. {
  156. /// <summary>
  157. /// Name of the action.
  158. /// </summary>
  159. /// <value>Plain-text name of the action.</value>
  160. /// <remarks>
  161. /// Can be null for anonymous actions created in code.
  162. ///
  163. /// If the action is part of an <see cref="InputActionMap"/>, it will have a name and the name
  164. /// will be unique in the map. The name is just the name of the action alone, not a "mapName/actionName"
  165. /// combination.
  166. ///
  167. /// The name should not contain slashes or dots but can contain spaces and other punctuation.
  168. ///
  169. /// An action can be renamed after creation using <see cref="InputActionSetupExtensions.Rename"/>..
  170. /// </remarks>
  171. /// <seealso cref="InputActionMap.FindAction(string,bool)"/>
  172. public string name => m_Name;
  173. /// <summary>
  174. /// Behavior type of the action.
  175. /// </summary>
  176. /// <value>General behavior type of the action.</value>
  177. /// <remarks>
  178. /// Determines how the action gets triggered in response to control value changes.
  179. ///
  180. /// For details about how the action type affects an action, see <see cref="InputActionType"/>.
  181. /// </remarks>
  182. public InputActionType type => m_Type;
  183. /// <summary>
  184. /// A stable, unique identifier for the action.
  185. /// </summary>
  186. /// <value>Unique ID of the action.</value>
  187. /// <remarks>
  188. /// This can be used instead of the name to refer to the action. Doing so allows referring to the
  189. /// action such that renaming the action does not break references.
  190. /// </remarks>
  191. public Guid id
  192. {
  193. get
  194. {
  195. MakeSureIdIsInPlace();
  196. return new Guid(m_Id);
  197. }
  198. }
  199. internal Guid idDontGenerate
  200. {
  201. get
  202. {
  203. if (string.IsNullOrEmpty(m_Id))
  204. return default;
  205. return new Guid(m_Id);
  206. }
  207. }
  208. /// <summary>
  209. /// Name of control layout expected for controls bound to this action.
  210. /// </summary>
  211. /// <remarks>
  212. /// This is optional and is null by default.
  213. ///
  214. /// Constraining an action to a particular control layout allows determine the value
  215. /// type and expected input behavior of an action without being reliant on any particular
  216. /// binding.
  217. /// </remarks>
  218. public string expectedControlType
  219. {
  220. get => m_ExpectedControlType;
  221. set => m_ExpectedControlType = value;
  222. }
  223. /// <summary>
  224. /// Processors applied to every binding on the action.
  225. /// </summary>
  226. /// <value>Processors added to all bindings on the action.</value>
  227. /// <remarks>
  228. /// This property is equivalent to appending the same string to the
  229. /// <see cref="InputBinding.processors"/> field of every binding that targets
  230. /// the action. It is thus simply a means of avoiding the need configure the
  231. /// same processor the same way on every binding in case it uniformly applies
  232. /// to all of them.
  233. ///
  234. /// <example>
  235. /// <code>
  236. /// var action = new InputAction(processors: "scaleVector2(x=2, y=2)");
  237. ///
  238. /// // Both of the following bindings will implicitly have a
  239. /// // ScaleVector2Processor applied to them.
  240. /// action.AddBinding("&lt;Gamepad&gt;/leftStick");
  241. /// action.AddBinding("&lt;Joystick&gt;/stick");
  242. /// </code>
  243. /// </example>
  244. /// </remarks>
  245. /// <seealso cref="InputBinding.processors"/>
  246. /// <seealso cref="InputProcessor"/>
  247. /// <seealso cref="InputSystem.RegisterProcessor{T}"/>
  248. public string processors => m_Processors;
  249. /// <summary>
  250. /// Interactions applied to every binding on the action.
  251. /// </summary>
  252. /// <value>Interactions added to all bindings on the action.</value>
  253. /// <remarks>
  254. /// This property is equivalent to appending the same string to the
  255. /// <see cref="InputBinding.interactions"/> field of every binding that targets
  256. /// the action. It is thus simply a means of avoiding the need configure the
  257. /// same interaction the same way on every binding in case it uniformly applies
  258. /// to all of them.
  259. ///
  260. /// <example>
  261. /// <code>
  262. /// var action = new InputAction(interactions: "press");
  263. ///
  264. /// // Both of the following bindings will implicitly have a
  265. /// // Press interaction applied to them.
  266. /// action.AddBinding("&lt;Gamepad&gt;/buttonSouth");
  267. /// action.AddBinding("&lt;Joystick&gt;/trigger");
  268. /// </code>
  269. /// </example>
  270. /// </remarks>
  271. /// <seealso cref="InputBinding.interactions"/>
  272. /// <seealso cref="IInputInteraction"/>
  273. /// <seealso cref="InputSystem.RegisterInteraction{T}"/>
  274. public string interactions => m_Interactions;
  275. /// <summary>
  276. /// The map the action belongs to.
  277. /// </summary>
  278. /// <value><see cref="InputActionMap"/> that the action belongs to or null.</value>
  279. /// <remarks>
  280. /// If the action is a loose action created in code, this will be <c>null</c>.
  281. ///
  282. /// <example>
  283. /// <code>
  284. /// var action1 = new InputAction(); // action1.actionMap will be null
  285. ///
  286. /// var actionMap = new InputActionMap();
  287. /// var action2 = actionMap.AddAction("action"); // action2.actionMap will point to actionMap
  288. /// </code>
  289. /// </example>
  290. /// </remarks>
  291. /// <seealso cref="InputActionSetupExtensions.AddAction"/>
  292. public InputActionMap actionMap => isSingletonAction ? null : m_ActionMap;
  293. /// <summary>
  294. /// An optional mask that determines which bindings of the action to enable and
  295. /// which to ignore.
  296. /// </summary>
  297. /// <value>Optional mask that determines which bindings on the action to enable.</value>
  298. /// <remarks>
  299. /// Binding masks can be applied at three different levels: for an entire asset through
  300. /// <see cref="InputActionAsset.bindingMask"/>, for a specific map through <see
  301. /// cref="InputActionMap.bindingMask"/>, and for single actions through this property.
  302. /// By default, none of the masks will be set (i.e. they will be <c>null</c>).
  303. ///
  304. /// When an action is enabled, all the binding masks that apply to it are taken into
  305. /// account. Specifically, this means that any given binding on the action will be
  306. /// enabled only if it matches the mask applied to the asset, the mask applied
  307. /// to the map that contains the action, and the mask applied to the action itself.
  308. /// All the masks are individually optional.
  309. ///
  310. /// Masks are matched against bindings using <see cref="InputBinding.Matches"/>.
  311. ///
  312. /// Note that if you modify the masks applicable to an action while it is
  313. /// enabled, the action's <see cref="controls"/> will get updated immediately to
  314. /// respect the mask. To avoid repeated binding resolution, it is most efficient
  315. /// to apply binding masks before enabling actions.
  316. ///
  317. /// Binding masks are non-destructive. All the bindings on the action are left
  318. /// in place. Setting a mask will not affect the value of the <see cref="bindings"/>
  319. /// property.
  320. ///
  321. /// <example>
  322. /// <code>
  323. /// // Create a free-standing action with two bindings, one in the
  324. /// // "Keyboard" group and one in the "Gamepad" group.
  325. /// var action = new InputAction();
  326. /// action.AddBinding("&lt;Gamepad&gt;/buttonSouth", groups: "Gamepad");
  327. /// action.AddBinding("&lt;Keyboard&gt;/space", groups: "Keyboard");
  328. ///
  329. /// // By default, all bindings will be enabled. This means if both
  330. /// // a keyboard and gamepad (or several of them) is present, the action
  331. /// // will respond to input from all of them.
  332. /// action.Enable();
  333. ///
  334. /// // With a binding mask we can restrict the action to just specific
  335. /// // bindings. For example, to only enable the gamepad binding:
  336. /// action.bindingMask = InputBinding.MaskByGroup("Gamepad");
  337. ///
  338. /// // Note that we can mask by more than just by group. Masking by path
  339. /// // or by action as well as a combination of these is also possible.
  340. /// // We could, for example, mask for just a specific binding path:
  341. /// action.bindingMask = new InputBinding()
  342. /// {
  343. /// // Select the keyboard binding based on its specific path.
  344. /// path = "&lt;Keyboard&gt;/space"
  345. /// };
  346. /// </code>
  347. /// </example>
  348. /// </remarks>
  349. /// <seealso cref="InputBinding.MaskByGroup"/>
  350. /// <seealso cref="InputActionMap.bindingMask"/>
  351. /// <seealso cref="InputActionAsset.bindingMask"/>
  352. public InputBinding? bindingMask
  353. {
  354. get => m_BindingMask;
  355. set
  356. {
  357. if (value == m_BindingMask)
  358. return;
  359. if (value != null)
  360. {
  361. var v = value.Value;
  362. v.action = name;
  363. value = v;
  364. }
  365. m_BindingMask = value;
  366. var map = GetOrCreateActionMap();
  367. if (map.m_State != null)
  368. map.LazyResolveBindings(fullResolve: true);
  369. }
  370. }
  371. /// <summary>
  372. /// The list of bindings associated with the action.
  373. /// </summary>
  374. /// <value>List of bindings for the action.</value>
  375. /// <remarks>
  376. /// This list contains all bindings from <see cref="InputActionMap.bindings"/> of the action's
  377. /// <see cref="actionMap"/> that reference the action through their <see cref="InputBinding.action"/>
  378. /// property.
  379. ///
  380. /// Note that on the first call, the list may have to be extracted from the action map first which
  381. /// may require allocating GC memory. However, once initialized, no further GC allocation hits should occur.
  382. /// If the binding setup on the map is changed, re-initialization may be required.
  383. /// </remarks>
  384. /// <seealso cref="InputActionMap.bindings"/>
  385. public ReadOnlyArray<InputBinding> bindings => GetOrCreateActionMap().GetBindingsForSingleAction(this);
  386. /// <summary>
  387. /// The set of controls to which the action's <see cref="bindings"/> resolve.
  388. /// </summary>
  389. /// <value>Controls resolved from the action's <see cref="bindings"/>.</value>
  390. /// <remarks>
  391. /// This property can be queried whether the action is enabled or not and will return the
  392. /// set of controls that match the action's bindings according to the current setup of
  393. /// binding masks (<see cref="bindingMask"/>) and device restrictions (<see
  394. /// cref="InputActionMap.devices"/>).
  395. ///
  396. /// Note that internally, controls are not stored on a per-action basis. This means
  397. /// that on the first read of this property, the list of controls for just the action
  398. /// may have to be extracted which in turn may allocate GC memory. After the first read,
  399. /// no further GC allocations should occur except if the set of controls is changed (e.g.
  400. /// by changing the binding mask or by adding/removing devices to/from the system).
  401. ///
  402. /// If the property is queried when the action has not been enabled yet, the system
  403. /// will first resolve controls on the action (and for all actions in the map and/or
  404. /// the asset). See <a href="../manual/ActionBindings.html#binding-resolution">Binding Resolution</a>
  405. /// in the manual for details.
  406. ///
  407. /// To map a control in this array to an index into <see cref="bindings"/>, use
  408. /// <see cref="InputActionRebindingExtensions.GetBindingIndexForControl"/>.
  409. ///
  410. /// <example>
  411. /// <code>
  412. /// // Map control list to binding indices.
  413. /// var bindingIndices = myAction.controls.Select(c => myAction.GetBindingIndexForControl(c));
  414. /// </code>
  415. /// </example>
  416. ///
  417. /// Note that this array will not contain the same control multiple times even if more than
  418. /// one binding on an action references the same control.
  419. ///
  420. /// <example>
  421. /// <code>
  422. /// var action1 = new InputAction();
  423. /// action1.AddBinding("&lt;Gamepad&gt;/buttonSouth");
  424. /// action1.AddBinding("&lt;Gamepad&gt;/buttonSouth"); // This binding will be ignored.
  425. ///
  426. /// // Contains only one instance of buttonSouth which is associated
  427. /// // with the first binding (at index #0).
  428. /// var action1Controls = action1.controls;
  429. ///
  430. /// var action2 = new InputAction();
  431. /// action2.AddBinding("&lt;Gamepad&gt;/buttonSouth");
  432. /// // Add a binding that implicitly matches the first binding, too. When binding resolution
  433. /// // happens, this binding will only receive buttonNorth, buttonWest, and buttonEast, but not
  434. /// // buttonSouth as the first binding already received that control.
  435. /// action2.AddBinding("&lt;Gamepad&gt;/button*");
  436. ///
  437. /// // Contains only all four face buttons (buttonSouth, buttonNorth, buttonEast, buttonWest)
  438. /// // but buttonSouth is associated with the first button and only buttonNorth, buttonEast,
  439. /// // and buttonWest are associated with the second binding.
  440. /// var action2Controls = action2.controls;
  441. /// </code>
  442. /// </example>
  443. /// </remarks>
  444. /// <seealso cref="InputActionRebindingExtensions.GetBindingIndexForControl"/>
  445. /// <seealso cref="bindings"/>
  446. public ReadOnlyArray<InputControl> controls
  447. {
  448. get
  449. {
  450. var map = GetOrCreateActionMap();
  451. map.ResolveBindingsIfNecessary();
  452. return map.GetControlsForSingleAction(this);
  453. }
  454. }
  455. /// <summary>
  456. /// The current phase of the action.
  457. /// </summary>
  458. /// <remarks>
  459. /// When listening for control input and when responding to control value changes,
  460. /// actions will go through several possible phases.
  461. ///
  462. /// In general, when an action starts receiving input, it will go to <see cref="InputActionPhase.Started"/>
  463. /// and when it stops receiving input, it will go to <see cref="InputActionPhase.Canceled"/>.
  464. /// When <see cref="InputActionPhase.Performed"/> is used depends primarily on the type
  465. /// of action. <see cref="InputActionType.Value"/> will trigger <see cref="InputActionPhase.Performed"/>
  466. /// whenever the value of the control changes (including the first time; i.e. it will first
  467. /// trigger <see cref="InputActionPhase.Started"/> and then <see cref="InputActionPhase.Performed"/>
  468. /// right after) whereas <see cref="InputActionType.Button"/> will trigger <see cref="InputActionPhase.Performed"/>
  469. /// as soon as the button press threshold (<see cref="InputSettings.defaultButtonPressPoint"/>)
  470. /// has been crossed.
  471. ///
  472. /// Note that both interactions and the action <see cref="type"/> can affect the phases
  473. /// that an action goes through. <see cref="InputActionType.PassThrough"/> actions will
  474. /// only ever use <see cref="InputActionPhase.Performed"/> and not go to <see
  475. /// cref="InputActionPhase.Started"/> or <see cref="InputActionPhase.Canceled"/> (as
  476. /// pass-through actions do not follow the start-performed-canceled model in general).
  477. ///
  478. /// While an action is disabled, its phase is <see cref="InputActionPhase.Disabled"/>.
  479. /// </remarks>
  480. public InputActionPhase phase => currentState.phase;
  481. /// <summary>
  482. /// True if the action is currently in <see cref="InputActionPhase.Started"/> or <see cref="InputActionPhase.Performed"/>
  483. /// phase. False in all other cases.
  484. /// </summary>
  485. /// <see cref="phase"/>
  486. public bool inProgress => phase.IsInProgress();
  487. /// <summary>
  488. /// Whether the action is currently enabled, i.e. responds to input, or not.
  489. /// </summary>
  490. /// <value>True if the action is currently enabled.</value>
  491. /// <remarks>
  492. /// An action is enabled by either calling <see cref="Enable"/> on it directly or by calling
  493. /// <see cref="InputActionMap.Enable"/> on the <see cref="InputActionMap"/> containing the action.
  494. /// When enabled, an action will listen for changes on the controls it is bound to and trigger
  495. /// callbacks such as <see cref="started"/>, <see cref="performed"/>, and <see cref="canceled"/>
  496. /// in response.
  497. /// </remarks>
  498. /// <seealso cref="Enable"/>
  499. /// <seealso cref="Disable"/>
  500. /// <seealso cref="InputActionMap.Enable"/>
  501. /// <seealso cref="InputActionMap.Disable"/>
  502. /// <seealso cref="InputSystem.ListEnabledActions()"/>
  503. public bool enabled => phase != InputActionPhase.Disabled;
  504. /// <summary>
  505. /// Event that is triggered when the action has been started.
  506. /// </summary>
  507. /// <remarks>
  508. /// See <see cref="phase"/> for details of how an action progresses through phases
  509. /// and triggers this callback.
  510. /// </remarks>
  511. /// <see cref="InputActionPhase.Started"/>
  512. public event Action<CallbackContext> started
  513. {
  514. add => m_OnStarted.AddCallback(value);
  515. remove => m_OnStarted.RemoveCallback(value);
  516. }
  517. /// <summary>
  518. /// Event that is triggered when the action has been <see cref="started"/>
  519. /// but then canceled before being fully <see cref="performed"/>.
  520. /// </summary>
  521. /// <remarks>
  522. /// See <see cref="phase"/> for details of how an action progresses through phases
  523. /// and triggers this callback.
  524. /// </remarks>
  525. /// <see cref="InputActionPhase.Canceled"/>
  526. public event Action<CallbackContext> canceled
  527. {
  528. add => m_OnCanceled.AddCallback(value);
  529. remove => m_OnCanceled.RemoveCallback(value);
  530. }
  531. /// <summary>
  532. /// Event that is triggered when the action has been fully performed.
  533. /// </summary>
  534. /// <remarks>
  535. /// See <see cref="phase"/> for details of how an action progresses through phases
  536. /// and triggers this callback.
  537. /// </remarks>
  538. /// <see cref="InputActionPhase.Performed"/>
  539. public event Action<CallbackContext> performed
  540. {
  541. add => m_OnPerformed.AddCallback(value);
  542. remove => m_OnPerformed.RemoveCallback(value);
  543. }
  544. ////TODO: Obsolete and drop this when we can break API
  545. /// <summary>
  546. /// Equivalent to <see cref="WasPerformedThisFrame"/>.
  547. /// </summary>
  548. /// <seealso cref="WasPerformedThisFrame"/>
  549. public bool triggered => WasPerformedThisFrame();
  550. /// <summary>
  551. /// The currently active control that is driving the action. <see langword="null"/> while the action
  552. /// is in waiting (<see cref="InputActionPhase.Waiting"/>) or canceled (<see cref="InputActionPhase.Canceled"/>)
  553. /// state. Otherwise the control that last had activity on it which wasn't ignored.
  554. /// </summary>
  555. /// <remarks>
  556. /// Note that the control's value does not necessarily correspond to the value of the
  557. /// action (<see cref="ReadValue{TValue}"/>) as the control may be part of a composite.
  558. /// </remarks>
  559. /// <seealso cref="CallbackContext.control"/>
  560. public unsafe InputControl activeControl
  561. {
  562. get
  563. {
  564. var state = GetOrCreateActionMap().m_State;
  565. if (state != null)
  566. {
  567. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  568. var controlIndex = actionStatePtr->controlIndex;
  569. if (controlIndex != InputActionState.kInvalidIndex)
  570. return state.controls[controlIndex];
  571. }
  572. return null;
  573. }
  574. }
  575. /// <summary>
  576. /// Type of value returned by <see cref="ReadValueAsObject"/> and currently expected
  577. /// by <see cref="ReadValue{TValue}"/>. <see langword="null"/> while the action
  578. /// is in waiting (<see cref="InputActionPhase.Waiting"/>) or canceled (<see cref="InputActionPhase.Canceled"/>)
  579. /// state as this is based on the currently active control that is driving the action.
  580. /// </summary>
  581. /// <value>Type of object returned when reading a value.</value>
  582. /// <remarks>
  583. /// The type of value returned by an action is usually determined by the
  584. /// <see cref="InputControl"/> that triggered the action, i.e. by the
  585. /// control referenced from <see cref="activeControl"/>.
  586. ///
  587. /// However, if the binding that triggered is a composite, then the composite
  588. /// will determine values and not the individual control that triggered (that
  589. /// one just feeds values into the composite).
  590. ///
  591. /// The active value type may change depending on which controls are actuated if there are multiple
  592. /// bindings with different control types. This property can be used to ensure you are calling the
  593. /// <see cref="ReadValue{TValue}"/> method with the expected type parameter if your action is
  594. /// configured to allow multiple control types as otherwise that method will throw an <see cref="InvalidOperationException"/>
  595. /// if the type of the control that triggered the action does not match the type parameter.
  596. /// </remarks>
  597. /// <seealso cref="InputControl.valueType"/>
  598. /// <seealso cref="InputBindingComposite.valueType"/>
  599. /// <seealso cref="activeControl"/>
  600. public unsafe Type activeValueType
  601. {
  602. get
  603. {
  604. var state = GetOrCreateActionMap().m_State;
  605. if (state != null)
  606. {
  607. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  608. var controlIndex = actionStatePtr->controlIndex;
  609. if (controlIndex != InputActionState.kInvalidIndex)
  610. return state.GetValueType(actionStatePtr->bindingIndex, controlIndex);
  611. }
  612. return null;
  613. }
  614. }
  615. /// <summary>
  616. /// Whether the action wants a state check on its bound controls as soon as it is enabled. This is always
  617. /// true for <see cref="InputActionType.Value"/> actions but can optionally be enabled for <see cref="InputActionType.Button"/>
  618. /// or <see cref="InputActionType.PassThrough"/> actions.
  619. /// </summary>
  620. /// <remarks>
  621. /// Usually, when an action is <see cref="enabled"/> (e.g. via <see cref="Enable"/>), it will start listening for input
  622. /// and then trigger once the first input arrives. However, <see cref="controls"/> bound to an action may already be
  623. /// actuated when an action is enabled. For example, if a "jump" action is bound to <see cref="Keyboard.spaceKey"/>,
  624. /// the space bar may already be pressed when the jump action is enabled.
  625. ///
  626. /// <see cref="InputActionType.Value"/> actions handle this differently by immediately performing an "initial state check"
  627. /// in the next input update (see <see cref="InputSystem.Update"/>) after being enabled. If any of the bound controls
  628. /// is already actuated, the action will trigger right away -- even with no change in state on the controls.
  629. ///
  630. /// This same behavior can be enabled explicitly for <see cref="InputActionType.Button"/> and <see cref="InputActionType.PassThrough"/>
  631. /// actions using this property.
  632. /// </remarks>
  633. /// <seealso cref="Enable"/>
  634. /// <seealso cref="InputActionType.Value"/>
  635. public bool wantsInitialStateCheck
  636. {
  637. get => type == InputActionType.Value || (m_Flags & ActionFlags.WantsInitialStateCheck) != 0;
  638. set
  639. {
  640. if (value)
  641. m_Flags |= ActionFlags.WantsInitialStateCheck;
  642. else
  643. m_Flags &= ~ActionFlags.WantsInitialStateCheck;
  644. }
  645. }
  646. /// <summary>
  647. /// Construct an unnamed, free-standing action that is not part of any map or asset
  648. /// and has no bindings. Bindings can be added with <see
  649. /// cref="InputActionSetupExtensions.AddBinding(InputAction,string,string,string,string)"/>.
  650. /// The action type defaults to <see cref="InputActionType.Value"/>.
  651. /// </summary>
  652. /// <remarks>
  653. /// The action will not have an associated <see cref="InputActionMap"/> and <see cref="actionMap"/>
  654. /// will thus be <c>null</c>. Use <see cref="InputActionSetupExtensions.AddAction"/> instead if
  655. /// you want to add a new action to an action map.
  656. ///
  657. /// The action will remain disabled after construction and thus not listen/react to input yet.
  658. /// Use <see cref="Enable"/> to enable the action.
  659. ///
  660. /// <example>
  661. /// <code>
  662. /// // Create an action with two bindings.
  663. /// var action = new InputAction();
  664. /// action.AddBinding("&lt;Gamepad&gt;/leftStick");
  665. /// action.AddBinding("&lt;Mouse&gt;/delta");
  666. ///
  667. /// action.performed += ctx => Debug.Log("Value: " + ctx.ReadValue&lt;Vector2&gt;());
  668. ///
  669. /// action.Enable();
  670. /// </code>
  671. /// </example>
  672. /// </remarks>
  673. public InputAction()
  674. {
  675. m_Id = Guid.NewGuid().ToString();
  676. }
  677. /// <summary>
  678. /// Construct a free-standing action that is not part of an <see cref="InputActionMap"/>.
  679. /// </summary>
  680. /// <param name="name">Name of the action. If null or empty, the action will be unnamed.</param>
  681. /// <param name="type">Type of action to create. Defaults to <see cref="InputActionType.Value"/>, i.e.
  682. /// an action that provides continuous values.</param>
  683. /// <param name="binding">If not null or empty, a binding with the given path will be added to the action
  684. /// right away. The format of the string is the as for <see cref="InputBinding.path"/>.</param>
  685. /// <param name="interactions">If <paramref name="binding"/> is not null or empty, this parameter represents
  686. /// the interaction to apply to the newly created binding (i.e. <see cref="InputBinding.interactions"/>). If
  687. /// <paramref name="binding"/> is not supplied, this parameter represents the interactions to apply to the action
  688. /// (i.e. the value of <see cref="interactions"/>).</param>
  689. /// <param name="processors">If <paramref name="binding"/> is not null or empty, this parameter represents
  690. /// the processors to apply to the newly created binding (i.e. <see cref="InputBinding.processors"/>). If
  691. /// <paramref name="binding"/> is not supplied, this parameter represents the processors to apply to the
  692. /// action (i.e. the value of <see cref="processors"/>).</param>
  693. /// <param name="expectedControlType">The optional expected control type for the action (i.e. <see
  694. /// cref="expectedControlType"/>).</param>
  695. /// <remarks>
  696. /// The action will not have an associated <see cref="InputActionMap"/> and <see cref="actionMap"/>
  697. /// will thus be <c>null</c>. Use <see cref="InputActionSetupExtensions.AddAction"/> instead if
  698. /// you want to add a new action to an action map.
  699. ///
  700. /// The action will remain disabled after construction and thus not listen/react to input yet.
  701. /// Use <see cref="Enable"/> to enable the action.
  702. ///
  703. /// Additional bindings can be added with <see
  704. /// cref="InputActionSetupExtensions.AddBinding(InputAction,string,string,string,string)"/>.
  705. ///
  706. /// <example>
  707. /// <code>
  708. /// // Create a button action responding to the gamepad A button.
  709. /// var action = new InputAction(type: InputActionType.Button, binding: "&lt;Gamepad&gt;/buttonSouth");
  710. /// action.performed += ctx => Debug.Log("Pressed");
  711. /// action.Enable();
  712. /// </code>
  713. /// </example>
  714. /// </remarks>
  715. public InputAction(string name = null, InputActionType type = default, string binding = null,
  716. string interactions = null, string processors = null, string expectedControlType = null)
  717. {
  718. m_Name = name;
  719. m_Type = type;
  720. if (!string.IsNullOrEmpty(binding))
  721. {
  722. m_SingletonActionBindings = new[]
  723. {
  724. new InputBinding
  725. {
  726. path = binding,
  727. interactions = interactions,
  728. processors = processors,
  729. action = m_Name,
  730. id = Guid.NewGuid(),
  731. },
  732. };
  733. m_BindingsStartIndex = 0;
  734. m_BindingsCount = 1;
  735. }
  736. else
  737. {
  738. m_Interactions = interactions;
  739. m_Processors = processors;
  740. }
  741. m_ExpectedControlType = expectedControlType;
  742. m_Id = Guid.NewGuid().ToString();
  743. }
  744. /// <summary>
  745. /// Release internal state held on to by the action.
  746. /// </summary>
  747. /// <remarks>
  748. /// Once enabled, actions will allocate a block of state internally that they will hold on to
  749. /// until disposed of. For free-standing actions, that state is private to just the action.
  750. /// For actions that are part of <see cref="InputActionMap"/>s, the state is shared by all
  751. /// actions in the map and, if the map itself is part of an <see cref="InputActionAsset"/>,
  752. /// also by all the maps that are part of the asset.
  753. ///
  754. /// Note that the internal state holds on to GC heap memory as well as memory from the
  755. /// unmanaged, C++ heap.
  756. /// </remarks>
  757. public void Dispose()
  758. {
  759. m_ActionMap?.m_State?.Dispose();
  760. }
  761. /// <summary>
  762. /// Return a string version of the action. Mainly useful for debugging.
  763. /// </summary>
  764. /// <returns>A string version of the action.</returns>
  765. public override string ToString()
  766. {
  767. string str;
  768. if (m_Name == null)
  769. str = "<Unnamed>";
  770. else if (m_ActionMap != null && !isSingletonAction && !string.IsNullOrEmpty(m_ActionMap.name))
  771. str = $"{m_ActionMap.name}/{m_Name}";
  772. else
  773. str = m_Name;
  774. var controls = this.controls;
  775. if (controls.Count > 0)
  776. {
  777. str += "[";
  778. var isFirst = true;
  779. foreach (var control in controls)
  780. {
  781. if (!isFirst)
  782. str += ",";
  783. str += control.path;
  784. isFirst = false;
  785. }
  786. str += "]";
  787. }
  788. return str;
  789. }
  790. /// <summary>
  791. /// Enable the action such that it actively listens for input and runs callbacks
  792. /// in response.
  793. /// </summary>
  794. /// <remarks>
  795. /// If the action is already enabled, this method does nothing.
  796. ///
  797. /// By default, actions start out disabled, i.e. with <see cref="enabled"/> being false.
  798. /// When enabled, two things happen.
  799. ///
  800. /// First, if it hasn't already happened, an action will resolve all of its bindings
  801. /// to <see cref="InputControl"/>s. This also happens if, since the action was last enabled,
  802. /// the setup of devices in the system has changed such that it may impact the action.
  803. ///
  804. /// Second, for all the <see cref="controls"/> bound to an action, change monitors (see
  805. /// <see cref="IInputStateChangeMonitor"/>) will be added to the system. If any of the
  806. /// controls changes state in the future, the action will get notified and respond.
  807. ///
  808. /// <see cref="InputActionType.Value"/> type actions will also perform an initial state
  809. /// check in the input system update following the call to Enable. This means that if
  810. /// any of the bound controls are already actuated and produce a non-<c>default</c> value,
  811. /// the action will immediately trigger in response.
  812. ///
  813. /// Note that this method only enables a single action. This is also allowed for action
  814. /// that are part of an <see cref="InputActionMap"/>. To enable all actions in a map,
  815. /// call <see cref="InputActionMap.Enable"/>.
  816. ///
  817. /// The <see cref="InputActionMap"/> associated with an action (if any), will immediately
  818. /// toggle to being enabled (see <see cref="InputActionMap.enabled"/>) as soon as the first
  819. /// action in the map is enabled and for as long as any action in the map is still enabled.
  820. ///
  821. /// The first time an action is enabled, it will allocate a block of state internally that it
  822. /// will hold on to until disposed of. For free-standing actions, that state is private to
  823. /// just the action. For actions that are part of <see cref="InputActionMap"/>s, the state
  824. /// is shared by all actions in the map and, if the map itself is part of an <see
  825. /// cref="InputActionAsset"/>, also by all the maps that are part of the asset.
  826. ///
  827. /// To dispose of the state, call <see cref="Dispose"/>.
  828. ///
  829. /// <example>
  830. /// <code>
  831. /// var gamepad = InputSystem.AddDevice&lt;Gamepad&gt;();
  832. ///
  833. /// var action = new InputAction(type: InputActionType.Value, binding: "&lt;Gamepad&gt;/leftTrigger");
  834. /// action.performed = ctx => Debug.Log("Action triggered!");
  835. ///
  836. /// // Perform some fake input on the gamepad. Note that the action
  837. /// // will *NOT* get triggered as it is not enabled.
  838. /// // NOTE: We use Update() here only for demonstration purposes. In most cases,
  839. /// // it's not a good method to call directly as it basically injects artificial
  840. /// // input frames into the player loop. Usually a recipe for breakage.
  841. /// InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.5f });
  842. /// InputSystem.Update();
  843. ///
  844. /// action.Enable();
  845. ///
  846. /// // Now, with the left trigger already being down and the action enabled, it will
  847. /// // trigger in the next frame.
  848. /// InputSystem.Update();
  849. /// </code>
  850. /// </example>
  851. /// </remarks>
  852. /// <seealso cref="Disable"/>
  853. /// <seealso cref="enabled"/>
  854. public void Enable()
  855. {
  856. if (enabled)
  857. return;
  858. // For singleton actions, we create an internal-only InputActionMap
  859. // private to the action.
  860. var map = GetOrCreateActionMap();
  861. // First time we're enabled, find all controls.
  862. map.ResolveBindingsIfNecessary();
  863. // Go live.
  864. map.m_State.EnableSingleAction(this);
  865. }
  866. /// <summary>
  867. /// Disable the action such that is stop listening/responding to input.
  868. /// </summary>
  869. /// <remarks>
  870. /// If the action is already disabled, this method does nothing.
  871. ///
  872. /// If the action is currently in progress, i.e. if <see cref="phase"/> is
  873. /// <see cref="InputActionPhase.Started"/>, the action will be canceled as
  874. /// part of being disabled. This means that you will see a call on <see cref="canceled"/>
  875. /// from within the call to <c>Disable()</c>.
  876. /// </remarks>
  877. /// <seealso cref="enabled"/>
  878. /// <seealso cref="Enable"/>
  879. public void Disable()
  880. {
  881. if (!enabled)
  882. return;
  883. m_ActionMap.m_State.DisableSingleAction(this);
  884. }
  885. ////REVIEW: is *not* cloning IDs here really the right thing to do?
  886. /// <summary>
  887. /// Return an identical instance of the action.
  888. /// </summary>
  889. /// <returns>An identical clone of the action</returns>
  890. /// <remarks>
  891. /// Note that if you clone an action that is part of an <see cref="InputActionMap"/>,
  892. /// you will not get a new action that is part of the same map. Instead, you will
  893. /// get a free-standing action not associated with any action map.
  894. ///
  895. /// Also, note that the <see cref="id"/> of the action is not cloned. Instead, the
  896. /// clone will receive a new unique ID. Also, callbacks install on events such
  897. /// as <see cref="started"/> will not be copied over to the clone.
  898. /// </remarks>
  899. public InputAction Clone()
  900. {
  901. var clone = new InputAction(name: m_Name, type: m_Type)
  902. {
  903. m_SingletonActionBindings = bindings.ToArray(),
  904. m_BindingsCount = m_BindingsCount,
  905. m_ExpectedControlType = m_ExpectedControlType,
  906. m_Interactions = m_Interactions,
  907. m_Processors = m_Processors,
  908. m_Flags = m_Flags,
  909. };
  910. return clone;
  911. }
  912. /// <summary>
  913. /// Return an boxed instance of the action.
  914. /// </summary>
  915. /// <returns>An boxed clone of the action</returns>
  916. /// <seealso cref="Clone"/>
  917. object ICloneable.Clone()
  918. {
  919. return Clone();
  920. }
  921. ////TODO: ReadValue(void*, int)
  922. /// <summary>
  923. /// Read the current value of the control that is driving this action. If no bound control is actuated, returns
  924. /// default(TValue), but note that binding processors are always applied.
  925. /// </summary>
  926. /// <typeparam name="TValue">Value type to read. Must match the value type of the binding/control that triggered.</typeparam>
  927. /// <returns>The current value of the control/binding that is driving this action with all binding processors applied.</returns>
  928. /// <remarks>
  929. /// This method can be used as an alternative to hooking into <see cref="started"/>, <see cref="performed"/>,
  930. /// and/or <see cref="canceled"/> and reading out the value using <see cref="CallbackContext.ReadValue{TValue}"/>
  931. /// there. Instead, this API acts more like a polling API that can be called, for example, as part of
  932. /// <c>MonoBehaviour.Update</c>.
  933. ///
  934. /// <example>
  935. /// <code>
  936. /// // Let's say you have a MyControls.inputactions file with "Generate C# Class" enabled
  937. /// // and it has an action map called "gameplay" with a "move" action of type Vector2.
  938. /// public class MyBehavior : MonoBehaviour
  939. /// {
  940. /// public MyControls controls;
  941. /// public float moveSpeed = 4;
  942. ///
  943. /// protected void Awake()
  944. /// {
  945. /// controls = new MyControls();
  946. /// }
  947. ///
  948. /// protected void OnEnable()
  949. /// {
  950. /// controls.gameplay.Enable();
  951. /// }
  952. ///
  953. /// protected void OnDisable()
  954. /// {
  955. /// controls.gameplay.Disable();
  956. /// }
  957. ///
  958. /// protected void Update()
  959. /// {
  960. /// var moveVector = controls.gameplay.move.ReadValue&lt;Vector2&gt;() * (moveSpeed * Time.deltaTime);
  961. /// //...
  962. /// }
  963. /// }
  964. /// </code>
  965. /// </example>
  966. ///
  967. /// If the action has button-like behavior, then <see cref="triggered"/> is usually a better alternative to
  968. /// reading out a float and checking if it is above the button press point.
  969. /// </remarks>
  970. /// <exception cref="InvalidOperationException">The given <typeparamref name="TValue"/> type does not match
  971. /// the value type of the control or composite currently driving the action.</exception>
  972. /// <seealso cref="triggered"/>
  973. /// <seealso cref="ReadValueAsObject"/>
  974. /// <seealso cref="CallbackContext.ReadValue{TValue}"/>
  975. public unsafe TValue ReadValue<TValue>()
  976. where TValue : struct
  977. {
  978. var state = GetOrCreateActionMap().m_State;
  979. if (state == null)
  980. return default(TValue);
  981. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  982. return actionStatePtr->phase.IsInProgress()
  983. ? state.ReadValue<TValue>(actionStatePtr->bindingIndex, actionStatePtr->controlIndex)
  984. : state.ApplyProcessors(actionStatePtr->bindingIndex, default(TValue));
  985. }
  986. /// <summary>
  987. /// Same as <see cref="ReadValue{TValue}"/> but read the value without having to know the value type
  988. /// of the action.
  989. /// </summary>
  990. /// <returns>The current value of the action or <c>null</c> if the action is not currently in <see cref="InputActionPhase.Started"/>
  991. /// or <see cref="InputActionPhase.Performed"/> phase.</returns>
  992. /// <remarks>
  993. /// This method allocates GC memory and is thus not a good choice for getting called as part of gameplay
  994. /// logic.
  995. /// </remarks>
  996. /// <seealso cref="ReadValue{TValue}"/>
  997. /// <seealso cref="InputAction.CallbackContext.ReadValueAsObject"/>
  998. public unsafe object ReadValueAsObject()
  999. {
  1000. var state = GetOrCreateActionMap().m_State;
  1001. if (state == null)
  1002. return null;
  1003. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1004. if (actionStatePtr->phase.IsInProgress())
  1005. {
  1006. var controlIndex = actionStatePtr->controlIndex;
  1007. if (controlIndex != InputActionState.kInvalidIndex)
  1008. return state.ReadValueAsObject(actionStatePtr->bindingIndex, controlIndex);
  1009. }
  1010. return null;
  1011. }
  1012. /// <summary>
  1013. /// Read the current amount of actuation of the control that is driving this action.
  1014. /// </summary>
  1015. /// <returns>Returns the current level of control actuation (usually [0..1]) or -1 if
  1016. /// the control is actuated but does not support computing magnitudes.</returns>
  1017. /// <remarks>
  1018. /// Magnitudes do not make sense for all types of controls. Controls that have no meaningful magnitude
  1019. /// will return -1 when calling this method. Any negative magnitude value should be considered an invalid value.
  1020. /// <br />
  1021. /// The magnitude returned by an action is usually determined by the
  1022. /// <see cref="InputControl"/> that triggered the action, i.e. by the
  1023. /// control referenced from <see cref="activeControl"/>.
  1024. /// <br />
  1025. /// However, if the binding that triggered is a composite, then the composite
  1026. /// will determine the magnitude and not the individual control that triggered.
  1027. /// Instead, the value of the control that triggered the action will be fed into the composite magnitude calculation.
  1028. /// </remarks>
  1029. /// <seealso cref="InputControl.EvaluateMagnitude()"/>
  1030. /// <seealso cref="InputBindingComposite.EvaluateMagnitude"/>
  1031. public unsafe float GetControlMagnitude()
  1032. {
  1033. var state = GetOrCreateActionMap().m_State;
  1034. if (state != null)
  1035. {
  1036. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1037. if (actionStatePtr->haveMagnitude)
  1038. return actionStatePtr->magnitude;
  1039. }
  1040. return 0f;
  1041. }
  1042. /// <summary>
  1043. /// Reset the action state to default.
  1044. /// </summary>
  1045. /// <remarks>
  1046. /// This method can be used to forcibly cancel an action even while it is in progress. Note that unlike
  1047. /// disabling an action, for example, this also effects APIs such as <see cref="WasPressedThisFrame"/>.
  1048. ///
  1049. /// Note that invoking this method will not modify enabled state.
  1050. /// </remarks>
  1051. /// <seealso cref="inProgress"/>
  1052. /// <seealso cref="phase"/>
  1053. /// <seealso cref="Enable"/>
  1054. /// <seealso cref="Disable"/>
  1055. public void Reset()
  1056. {
  1057. var state = GetOrCreateActionMap().m_State;
  1058. state?.ResetActionState(m_ActionIndexInState, toPhase: enabled ? InputActionPhase.Waiting : InputActionPhase.Disabled, hardReset: true);
  1059. }
  1060. /// <summary>
  1061. /// Check whether the current actuation of the action has crossed the button press threshold (see
  1062. /// <see cref="InputSettings.defaultButtonPressPoint"/>) and has not yet fallen back below the
  1063. /// release threshold (see <see cref="InputSettings.buttonReleaseThreshold"/>).
  1064. /// </summary>
  1065. /// <returns>True if the action is considered to be in "pressed" state, false otherwise.</returns>
  1066. /// <remarks>
  1067. /// This method is different from simply reading the action's current <c>float</c> value and comparing
  1068. /// it to the press threshold and is also different from comparing the current actuation of
  1069. /// <see cref="activeControl"/> to it. This is because the current level of actuation might have already
  1070. /// fallen below the press threshold but might not yet have reached the release threshold.
  1071. ///
  1072. /// This method works with any <see cref="type"/> of action, not just buttons.
  1073. ///
  1074. /// Also note that because this operates on the results of <see cref="InputControl.EvaluateMagnitude()"/>,
  1075. /// it works with many kind of controls, not just buttons. For example, if an action is bound
  1076. /// to a <see cref="StickControl"/>, the control will be considered "pressed" once the magnitude
  1077. /// of the Vector2 of the control has crossed the press threshold.
  1078. ///
  1079. /// Finally, note that custom button press points of controls (see <see cref="ButtonControl.pressPoint"/>)
  1080. /// are respected and will take precedence over <see cref="InputSettings.defaultButtonPressPoint"/>.
  1081. ///
  1082. /// <example>
  1083. /// <code>
  1084. /// var up = playerInput.actions["up"];
  1085. /// if (up.IsPressed())
  1086. /// transform.Translate(0, 10 * Time.deltaTime, 0);
  1087. /// </code>
  1088. /// </example>
  1089. ///
  1090. /// Disabled actions will always return false from this method, even if a control bound to the action
  1091. /// is currently pressed. Also, re-enabling an action will not restore the state to when the action
  1092. /// was disabled even if the control is still actuated.
  1093. /// </remarks>
  1094. /// <seealso cref="InputSettings.defaultButtonPressPoint"/>
  1095. /// <seealso cref="ButtonControl.pressPoint"/>
  1096. /// <seealso cref="CallbackContext.ReadValueAsButton"/>
  1097. /// <seealso cref="WasPressedThisFrame"/>
  1098. /// <seealso cref="WasReleasedThisFrame"/>
  1099. public unsafe bool IsPressed()
  1100. {
  1101. var state = GetOrCreateActionMap().m_State;
  1102. if (state != null)
  1103. {
  1104. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1105. return actionStatePtr->isPressed;
  1106. }
  1107. return false;
  1108. }
  1109. /// <summary>
  1110. /// Whether the action has been <see cref="InputActionPhase.Started"/> or <see cref="InputActionPhase.Performed"/>.
  1111. /// </summary>
  1112. /// <returns>True if the action is currently triggering.</returns>
  1113. /// <seealso cref="phase"/>
  1114. public unsafe bool IsInProgress()
  1115. {
  1116. var state = GetOrCreateActionMap().m_State;
  1117. if (state != null)
  1118. {
  1119. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1120. return actionStatePtr->phase.IsInProgress();
  1121. }
  1122. return false;
  1123. }
  1124. /// <summary>
  1125. /// Returns true if the action's value crossed the press threshold (see <see cref="InputSettings.defaultButtonPressPoint"/>)
  1126. /// at any point in the frame.
  1127. /// </summary>
  1128. /// <returns>True if the action was pressed this frame.</returns>
  1129. /// <remarks>
  1130. /// This method is different from <see cref="WasPerformedThisFrame"/> in that it is not bound
  1131. /// to <see cref="phase"/>. Instead, if the action's level of actuation (that is, the level of
  1132. /// magnitude -- see <see cref="InputControl.EvaluateMagnitude()"/> -- of the control(s) bound
  1133. /// to the action) crossed the press threshold (see <see cref="InputSettings.defaultButtonPressPoint"/>)
  1134. /// at any point in the frame, this method will return true. It will do so even if there is an
  1135. /// interaction on the action that has not yet performed the action in response to the press.
  1136. ///
  1137. /// This method works with any <see cref="type"/> of action, not just buttons.
  1138. ///
  1139. /// Also note that because this operates on the results of <see cref="InputControl.EvaluateMagnitude()"/>,
  1140. /// it works with many kind of controls, not just buttons. For example, if an action is bound
  1141. /// to a <see cref="StickControl"/>, the control will be considered "pressed" once the magnitude
  1142. /// of the Vector2 of the control has crossed the press threshold.
  1143. ///
  1144. /// Finally, note that custom button press points of controls (see <see cref="ButtonControl.pressPoint"/>)
  1145. /// are respected and will take precedence over <see cref="InputSettings.defaultButtonPressPoint"/>.
  1146. ///
  1147. /// <example>
  1148. /// <code>
  1149. /// var fire = playerInput.actions["fire"];
  1150. /// if (fire.WasPressedThisFrame() &amp;&amp; fire.IsPressed())
  1151. /// StartFiring();
  1152. /// else if (fire.WasReleasedThisFrame())
  1153. /// StopFiring();
  1154. /// </code>
  1155. /// </example>
  1156. ///
  1157. /// This method will disregard whether the action is currently enabled or disabled. It will keep returning
  1158. /// true for the duration of the frame even if the action was subsequently disabled in the frame.
  1159. ///
  1160. /// The meaning of "frame" is either the current "dynamic" update (<c>MonoBehaviour.Update</c>) or the current
  1161. /// fixed update (<c>MonoBehaviour.FixedUpdate</c>) depending on the value of the <see cref="InputSettings.updateMode"/> setting.
  1162. /// </remarks>
  1163. /// <seealso cref="IsPressed"/>
  1164. /// <seealso cref="WasReleasedThisFrame"/>
  1165. /// <seealso cref="CallbackContext.ReadValueAsButton"/>
  1166. /// <seealso cref="WasPerformedThisFrame"/>
  1167. public unsafe bool WasPressedThisFrame()
  1168. {
  1169. var state = GetOrCreateActionMap().m_State;
  1170. if (state != null)
  1171. {
  1172. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1173. var currentUpdateStep = InputUpdate.s_UpdateStepCount;
  1174. return actionStatePtr->pressedInUpdate == currentUpdateStep && currentUpdateStep != default;
  1175. }
  1176. return false;
  1177. }
  1178. /// <summary>
  1179. /// Returns true if the action's value crossed the release threshold (see <see cref="InputSettings.buttonReleaseThreshold"/>)
  1180. /// at any point in the frame after being in pressed state.
  1181. /// </summary>
  1182. /// <returns>True if the action was released this frame.</returns>
  1183. /// <remarks>
  1184. /// This method works with any <see cref="type"/> of action, not just buttons.
  1185. ///
  1186. /// Also note that because this operates on the results of <see cref="InputControl.EvaluateMagnitude()"/>,
  1187. /// it works with many kind of controls, not just buttons. For example, if an action is bound
  1188. /// to a <see cref="StickControl"/>, the control will be considered "pressed" once the magnitude
  1189. /// of the Vector2 of the control has crossed the press threshold.
  1190. ///
  1191. /// Finally, note that custom button press points of controls (see <see cref="ButtonControl.pressPoint"/>)
  1192. /// are respected and will take precedence over <see cref="InputSettings.defaultButtonPressPoint"/>.
  1193. ///
  1194. /// <example>
  1195. /// <code>
  1196. /// var fire = playerInput.actions["fire"];
  1197. /// if (fire.WasPressedThisFrame() &amp;&amp; fire.IsPressed())
  1198. /// StartFiring();
  1199. /// else if (fire.WasReleasedThisFrame())
  1200. /// StopFiring();
  1201. /// </code>
  1202. /// </example>
  1203. ///
  1204. /// This method will disregard whether the action is currently enabled or disabled. It will keep returning
  1205. /// true for the duration of the frame even if the action was subsequently disabled in the frame.
  1206. ///
  1207. /// The meaning of "frame" is either the current "dynamic" update (<c>MonoBehaviour.Update</c>) or the current
  1208. /// fixed update (<c>MonoBehaviour.FixedUpdate</c>) depending on the value of the <see cref="InputSettings.updateMode"/> setting.
  1209. /// </remarks>
  1210. /// <seealso cref="IsPressed"/>
  1211. /// <seealso cref="WasPressedThisFrame"/>
  1212. /// <seealso cref="CallbackContext.ReadValueAsButton"/>
  1213. /// <seealso cref="WasCompletedThisFrame"/>
  1214. public unsafe bool WasReleasedThisFrame()
  1215. {
  1216. var state = GetOrCreateActionMap().m_State;
  1217. if (state != null)
  1218. {
  1219. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1220. var currentUpdateStep = InputUpdate.s_UpdateStepCount;
  1221. return actionStatePtr->releasedInUpdate == currentUpdateStep && currentUpdateStep != default;
  1222. }
  1223. return false;
  1224. }
  1225. ////REVIEW: Should we also have WasStartedThisFrame()? (and WasCanceledThisFrame()?)
  1226. /// <summary>
  1227. /// Check whether <see cref="phase"/> was <see cref="InputActionPhase.Performed"/> at any point
  1228. /// in the current frame.
  1229. /// </summary>
  1230. /// <returns>True if the action performed this frame.</returns>
  1231. /// <remarks>
  1232. /// This method is different from <see cref="WasPressedThisFrame"/> in that it depends directly on the
  1233. /// interaction(s) driving the action (including the default interaction if no specific interaction
  1234. /// has been added to the action or binding).
  1235. ///
  1236. /// For example, let's say the action is bound to the space bar and that the binding has a
  1237. /// <see cref="Interactions.HoldInteraction"/> assigned to it. In the frame where the space bar
  1238. /// is pressed, <see cref="WasPressedThisFrame"/> will be true (because the button/key is now pressed)
  1239. /// but <c>WasPerformedThisFrame</c> will still be false (because the hold has not been performed yet).
  1240. /// Only after the hold time has expired will <c>WasPerformedThisFrame</c> be true and only in the frame
  1241. /// where the hold performed.
  1242. ///
  1243. /// This is different from checking <see cref="phase"/> directly as the action might have already progressed
  1244. /// to a different phase after performing. In other words, even if an action performed in a frame, <see cref="phase"/>
  1245. /// might no longer be <see cref="InputActionPhase.Performed"/>, whereas <c>WasPerformedThisFrame</c> will remain
  1246. /// true for the entirety of the frame regardless of what else the action does.
  1247. ///
  1248. /// Unlike <see cref="ReadValue{TValue}"/>, which will reset when the action goes back to waiting
  1249. /// state, this property will stay true for the duration of the current frame (that is, until the next
  1250. /// <see cref="InputSystem.Update"/> runs) as long as the action was triggered at least once.
  1251. ///
  1252. /// <example>
  1253. /// <code>
  1254. /// var warp = playerInput.actions["Warp"];
  1255. /// if (warp.WasPerformedThisFrame())
  1256. /// InitiateWarp();
  1257. /// </code>
  1258. /// </example>
  1259. ///
  1260. /// This method will disregard whether the action is currently enabled or disabled. It will keep returning
  1261. /// true for the duration of the frame even if the action was subsequently disabled in the frame.
  1262. ///
  1263. /// The meaning of "frame" is either the current "dynamic" update (<c>MonoBehaviour.Update</c>) or the current
  1264. /// fixed update (<c>MonoBehaviour.FixedUpdate</c>) depending on the value of the <see cref="InputSettings.updateMode"/> setting.
  1265. /// </remarks>
  1266. /// <seealso cref="WasCompletedThisFrame"/>
  1267. /// <seealso cref="WasPressedThisFrame"/>
  1268. /// <seealso cref="phase"/>
  1269. public unsafe bool WasPerformedThisFrame()
  1270. {
  1271. var state = GetOrCreateActionMap().m_State;
  1272. if (state != null)
  1273. {
  1274. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1275. var currentUpdateStep = InputUpdate.s_UpdateStepCount;
  1276. return actionStatePtr->lastPerformedInUpdate == currentUpdateStep && currentUpdateStep != default;
  1277. }
  1278. return false;
  1279. }
  1280. /// <summary>
  1281. /// Check whether <see cref="phase"/> transitioned from <see cref="InputActionPhase.Performed"/> to any other phase
  1282. /// value at least once in the current frame.
  1283. /// </summary>
  1284. /// <returns>True if the action completed this frame.</returns>
  1285. /// <remarks>
  1286. /// Although <see cref="InputActionPhase.Disabled"/> is technically a phase, this method does not consider disabling
  1287. /// the action while the action is in <see cref="InputActionPhase.Performed"/> to be "completed".
  1288. ///
  1289. /// This method is different from <see cref="WasReleasedThisFrame"/> in that it depends directly on the
  1290. /// interaction(s) driving the action (including the default interaction if no specific interaction
  1291. /// has been added to the action or binding).
  1292. ///
  1293. /// For example, let's say the action is bound to the space bar and that the binding has a
  1294. /// <see cref="Interactions.HoldInteraction"/> assigned to it. In the frame where the space bar
  1295. /// is pressed, <see cref="WasPressedThisFrame"/> will be true (because the button/key is now pressed)
  1296. /// but <see cref="WasPerformedThisFrame"/> will still be false (because the hold has not been performed yet).
  1297. /// If at that time the space bar is released, <see cref="WasReleasedThisFrame"/> will be true (because the
  1298. /// button/key is now released) but <c>WasCompletedThisFrame</c> will still be false (because the hold
  1299. /// had not been performed yet). If instead the space bar is held down for long enough for the hold interaction,
  1300. /// the phase will change to and stay <see cref="InputActionPhase.Performed"/> and <see cref="WasPerformedThisFrame"/>
  1301. /// will be true for one frame as it meets the duration threshold. Once released, <c>WasCompletedThisFrame</c> will be true
  1302. /// (because the action is no longer performed) and only in the frame where the hold transitioned away from Performed.
  1303. ///
  1304. /// For another example where the action could be considered pressed but also completed, let's say the action
  1305. /// is bound to the thumbstick and that the binding has a Sector interaction from the XR Interaction Toolkit assigned
  1306. /// to it such that it only performs in the forward sector area past a button press threshold. In the frame where the
  1307. /// thumbstick is pushed forward, both <see cref="WasPressedThisFrame"/> will be true (because the thumbstick actuation is
  1308. /// now considered pressed) and <see cref="WasPerformedThisFrame"/> will be true (because the thumbstick is in
  1309. /// the forward sector). If the thumbstick is then moved to the left in a sweeping motion, <see cref="IsPressed"/>
  1310. /// will still be true. However, <c>WasCompletedThisFrame</c> will also be true (because the thumbstick is
  1311. /// no longer in the forward sector while still crossed the button press threshold) and only in the frame where
  1312. /// the thumbstick was no longer within the forward sector. For more details about the Sector interaction, see
  1313. /// <a href="https://docs.unity3d.com/Packages/com.unity.xr.interaction.toolkit@2.5/api/UnityEngine.XR.Interaction.Toolkit.Inputs.Interactions.SectorInteraction.html"><c>SectorInteraction</c></a>
  1314. /// in the XR Interaction Toolkit Scripting API documentation.
  1315. /// <br />
  1316. /// Unlike <see cref="ReadValue{TValue}"/>, which will reset when the action goes back to waiting
  1317. /// state, this property will stay true for the duration of the current frame (that is, until the next
  1318. /// <see cref="InputSystem.Update"/> runs) as long as the action was completed at least once.
  1319. ///
  1320. /// <example>
  1321. /// <code>
  1322. /// var teleport = playerInput.actions["Teleport"];
  1323. /// if (teleport.WasPerformedThisFrame())
  1324. /// InitiateTeleport();
  1325. /// else if (teleport.WasCompletedThisFrame())
  1326. /// StopTeleport();
  1327. /// </code>
  1328. /// </example>
  1329. ///
  1330. /// This method will disregard whether the action is currently enabled or disabled. It will keep returning
  1331. /// true for the duration of the frame even if the action was subsequently disabled in the frame.
  1332. ///
  1333. /// The meaning of "frame" is either the current "dynamic" update (<c>MonoBehaviour.Update</c>) or the current
  1334. /// fixed update (<c>MonoBehaviour.FixedUpdate</c>) depending on the value of the <see cref="InputSettings.updateMode"/> setting.
  1335. /// </remarks>
  1336. /// <seealso cref="WasPerformedThisFrame"/>
  1337. /// <seealso cref="WasReleasedThisFrame"/>
  1338. /// <seealso cref="phase"/>
  1339. public unsafe bool WasCompletedThisFrame()
  1340. {
  1341. var state = GetOrCreateActionMap().m_State;
  1342. if (state != null)
  1343. {
  1344. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  1345. var currentUpdateStep = InputUpdate.s_UpdateStepCount;
  1346. return actionStatePtr->lastCompletedInUpdate == currentUpdateStep && currentUpdateStep != default;
  1347. }
  1348. return false;
  1349. }
  1350. /// <summary>
  1351. /// Return the completion percentage of the timeout (if any) running on the current interaction.
  1352. /// </summary>
  1353. /// <returns>A value &gt;= 0 (no progress) and &lt;= 1 (finished) indicating the level of completion
  1354. /// of the currently running timeout.</returns>
  1355. /// <remarks>
  1356. /// This method is useful, for example, when providing UI feedback for an ongoing action. If, say,
  1357. /// you have a <see cref="Interactions.HoldInteraction"/> on a binding, you might want to show a
  1358. /// progress indicator in the UI and need to know how far into the hold the action
  1359. /// current is. Once the hold has been started, this method will return how far into the hold
  1360. /// the action currently is.
  1361. ///
  1362. /// Note that if an interaction performs and stays performed (see <see cref="InputInteractionContext.PerformedAndStayPerformed"/>),
  1363. /// the completion percentage will remain at 1 until the interaction is canceled.
  1364. ///
  1365. /// Also note that completion is based on the progression of time and not dependent on input
  1366. /// updates. This means that if, for example, the timeout for a <see cref="Interactions.HoldInteraction"/>
  1367. /// has expired according the current time but the expiration has not yet been processed by
  1368. /// an input update (thus causing the hold to perform), the returned completion percentage
  1369. /// will still be 1. In other words, there isn't always a correlation between the current
  1370. /// completion percentage and <see cref="phase"/>.
  1371. ///
  1372. /// The meaning of the timeout is dependent on the interaction in play. For a <see cref="Interactions.HoldInteraction"/>,
  1373. /// "completion" represents the duration timeout (that is, the time until a "hold" is considered to be performed), whereas
  1374. /// for a <see cref="Interactions.TapInteraction"/> "completion" represents "time to failure" (that is, the remaining time window
  1375. /// that the interaction can be completed within).
  1376. ///
  1377. /// Note that an interaction might run multiple timeouts in succession. One such example is <see cref="Interactions.MultiTapInteraction"/>.
  1378. /// In this case, progression towards a single timeout does not necessarily mean progression towards completion
  1379. /// of the whole interaction. An interaction can call <see cref="InputInteractionContext.SetTotalTimeoutCompletionTime"/>
  1380. /// to inform the Input System of the total length of timeouts to run. If this is done, the result of the
  1381. /// <c>GetTimeoutCompletionPercentage</c> method will return a value reflecting the progression with respect
  1382. /// to total time.
  1383. ///
  1384. /// <example>
  1385. /// <code>
  1386. /// // Scale a UI element in response to the completion of a hold on the gamepad's A button.
  1387. ///
  1388. /// Transform uiObjectToScale;
  1389. ///
  1390. /// InputAction holdAction;
  1391. ///
  1392. /// void OnEnable()
  1393. /// {
  1394. /// if (holdAction == null)
  1395. /// {
  1396. /// // Create hold action with a 2 second timeout.
  1397. /// // NOTE: Here we create the action in code. You can, of course, grab the action from an .inputactions
  1398. /// // asset created in the editor instead.
  1399. /// holdAction = new InputAction(type: InputActionType.Button, interactions: "hold(duration=2)");
  1400. ///
  1401. /// // Show the UI object when the hold starts and hide it when it ends.
  1402. /// holdAction.started += _ =&gt; uiObjectToScale.SetActive(true);
  1403. /// holdAction.canceled += _ =&gt; uiObjectToScale.SetActive(false);
  1404. ///
  1405. /// // If you want to play a visual effect when the action performs, you can initiate from
  1406. /// // the performed callback.
  1407. /// holdAction.performed += _ =&gt; /* InitiateVisualEffectWhenHoldIsComplete() */;
  1408. /// }
  1409. ///
  1410. /// holdAction.Enable();
  1411. ///
  1412. /// // Hide the UI object until the action is started.
  1413. /// uiObjectToScale.gameObject.SetActive(false);
  1414. /// }
  1415. ///
  1416. /// void OnDisable()
  1417. /// {
  1418. /// holdAction.Disable();
  1419. /// }
  1420. ///
  1421. /// void Update()
  1422. /// {
  1423. /// var completion = holdAction.GetTimeoutCompletionPercentage();
  1424. /// uiObjectToScale.localScale = new Vector3(1, completion, 1);
  1425. /// }
  1426. /// </code>
  1427. /// </example>
  1428. /// </remarks>
  1429. /// <seealso cref="IInputInteraction"/>
  1430. /// <seealso cref="InputInteractionContext.SetTimeout"/>
  1431. /// <seealso cref="InputInteractionContext.SetTotalTimeoutCompletionTime"/>
  1432. public unsafe float GetTimeoutCompletionPercentage()
  1433. {
  1434. var actionMap = GetOrCreateActionMap();
  1435. var state = actionMap.m_State;
  1436. // If there's no state, there can't be activity on the action so our completion
  1437. // percentage must be zero.
  1438. if (state == null)
  1439. return 0;
  1440. ref var actionState = ref state.actionStates[m_ActionIndexInState];
  1441. var interactionIndex = actionState.interactionIndex;
  1442. if (interactionIndex == -1)
  1443. {
  1444. ////REVIEW: should this use WasPerformedThisFrame()?
  1445. // There's no interactions on the action or on the currently active binding, so go
  1446. // entirely by the current phase. Performed is 100%, everything else is 0%.
  1447. return actionState.phase == InputActionPhase.Performed ? 1 : 0;
  1448. }
  1449. ref var interactionState = ref state.interactionStates[interactionIndex];
  1450. switch (interactionState.phase)
  1451. {
  1452. case InputActionPhase.Started:
  1453. // If the interaction was started and there is a timer running, the completion level
  1454. // is determined by far we are between the interaction start time and timer expiration.
  1455. var timerCompletion = 0f;
  1456. if (interactionState.isTimerRunning)
  1457. {
  1458. var duration = interactionState.timerDuration;
  1459. var startTime = interactionState.timerStartTime;
  1460. var endTime = startTime + duration;
  1461. var remainingTime = endTime - InputState.currentTime;
  1462. if (remainingTime <= 0)
  1463. timerCompletion = 1;
  1464. else
  1465. timerCompletion = (float)((duration - remainingTime) / duration);
  1466. }
  1467. if (interactionState.totalTimeoutCompletionTimeRemaining > 0)
  1468. {
  1469. return (interactionState.totalTimeoutCompletionDone + timerCompletion * interactionState.timerDuration) /
  1470. (interactionState.totalTimeoutCompletionDone + interactionState.totalTimeoutCompletionTimeRemaining);
  1471. }
  1472. else
  1473. {
  1474. return timerCompletion;
  1475. }
  1476. case InputActionPhase.Performed:
  1477. return 1;
  1478. }
  1479. return 0;
  1480. }
  1481. ////REVIEW: it would be best if these were InternedStrings; however, for serialization, it has to be strings
  1482. [Tooltip("Human readable name of the action. Must be unique within its action map (case is ignored). Can be changed "
  1483. + "without breaking references to the action.")]
  1484. [SerializeField] internal string m_Name;
  1485. [Tooltip("Determines how the action triggers.\n"
  1486. + "\n"
  1487. + "A Value action will start and perform when a control moves from its default value and then "
  1488. + "perform on every value change. It will cancel when controls go back to default value. Also, when enabled, a Value "
  1489. + "action will respond right away to a control's current value.\n"
  1490. + "\n"
  1491. + "A Button action will start when a button is pressed and perform when the press threshold (see 'Default Button Press Point' in settings) "
  1492. + "is reached. It will cancel when the button is going below the release threshold (see 'Button Release Threshold' in settings). Also, "
  1493. + "if a button is already pressed when the action is enabled, the button has to be released first.\n"
  1494. + "\n"
  1495. + "A Pass-Through action will not explicitly start and will never cancel. Instead, for every value change on any bound control, "
  1496. + "the action will perform.")]
  1497. [SerializeField] internal InputActionType m_Type;
  1498. [FormerlySerializedAs("m_ExpectedControlLayout")]
  1499. [Tooltip("The type of control expected by the action (e.g. \"Button\" or \"Stick\"). This will limit the controls shown "
  1500. + "when setting up bindings in the UI and will also limit which controls can be bound interactively to the action.")]
  1501. [SerializeField] internal string m_ExpectedControlType;
  1502. [Tooltip("Unique ID of the action (GUID). Used to reference the action from bindings such that actions can be renamed "
  1503. + "without breaking references.")]
  1504. [SerializeField] internal string m_Id; // Can't serialize System.Guid and Unity's GUID is editor only.
  1505. [SerializeField] internal string m_Processors;
  1506. [SerializeField] internal string m_Interactions;
  1507. // For singleton actions, we serialize the bindings directly as part of the action.
  1508. // For any other type of action, this is null.
  1509. [SerializeField] internal InputBinding[] m_SingletonActionBindings;
  1510. [SerializeField] internal ActionFlags m_Flags;
  1511. [NonSerialized] internal InputBinding? m_BindingMask;
  1512. [NonSerialized] internal int m_BindingsStartIndex;
  1513. [NonSerialized] internal int m_BindingsCount;
  1514. [NonSerialized] internal int m_ControlStartIndex;
  1515. [NonSerialized] internal int m_ControlCount;
  1516. /// <summary>
  1517. /// Index of the action in the <see cref="InputActionState"/> associated with the
  1518. /// action's <see cref="InputActionMap"/>.
  1519. /// </summary>
  1520. /// <remarks>
  1521. /// This is not necessarily the same as the index of the action in its map.
  1522. /// </remarks>
  1523. /// <seealso cref="actionMap"/>
  1524. [NonSerialized] internal int m_ActionIndexInState = InputActionState.kInvalidIndex;
  1525. /// <summary>
  1526. /// The action map that owns the action.
  1527. /// </summary>
  1528. /// <remarks>
  1529. /// This is not serialized. The action map will restore this back references after deserialization.
  1530. /// </remarks>
  1531. [NonSerialized] internal InputActionMap m_ActionMap;
  1532. // Listeners. No array allocations if only a single listener.
  1533. [NonSerialized] internal CallbackArray<Action<CallbackContext>> m_OnStarted;
  1534. [NonSerialized] internal CallbackArray<Action<CallbackContext>> m_OnCanceled;
  1535. [NonSerialized] internal CallbackArray<Action<CallbackContext>> m_OnPerformed;
  1536. /// <summary>
  1537. /// Whether the action is a loose action created in code (e.g. as a property on a component).
  1538. /// </summary>
  1539. /// <remarks>
  1540. /// Singleton actions are not contained in maps visible to the user. Internally, we do create
  1541. /// a map for them that contains just the singleton action. To the action system, there are no
  1542. /// actions without action maps.
  1543. /// </remarks>
  1544. internal bool isSingletonAction => m_ActionMap == null || ReferenceEquals(m_ActionMap.m_SingletonAction, this);
  1545. [Flags]
  1546. internal enum ActionFlags
  1547. {
  1548. WantsInitialStateCheck = 1 << 0,
  1549. }
  1550. private InputActionState.TriggerState currentState
  1551. {
  1552. get
  1553. {
  1554. if (m_ActionIndexInState == InputActionState.kInvalidIndex)
  1555. return new InputActionState.TriggerState();
  1556. Debug.Assert(m_ActionMap != null, "Action must have associated action map");
  1557. Debug.Assert(m_ActionMap.m_State != null, "Action map must have state at this point");
  1558. return m_ActionMap.m_State.FetchActionState(this);
  1559. }
  1560. }
  1561. internal string MakeSureIdIsInPlace()
  1562. {
  1563. if (string.IsNullOrEmpty(m_Id))
  1564. GenerateId();
  1565. return m_Id;
  1566. }
  1567. internal void GenerateId()
  1568. {
  1569. m_Id = Guid.NewGuid().ToString();
  1570. }
  1571. internal InputActionMap GetOrCreateActionMap()
  1572. {
  1573. if (m_ActionMap == null)
  1574. CreateInternalActionMapForSingletonAction();
  1575. return m_ActionMap;
  1576. }
  1577. private void CreateInternalActionMapForSingletonAction()
  1578. {
  1579. m_ActionMap = new InputActionMap
  1580. {
  1581. m_Actions = new[] { this },
  1582. m_SingletonAction = this,
  1583. m_Bindings = m_SingletonActionBindings
  1584. };
  1585. }
  1586. internal void RequestInitialStateCheckOnEnabledAction()
  1587. {
  1588. Debug.Assert(enabled, "This should only be called on actions that are enabled");
  1589. var map = GetOrCreateActionMap();
  1590. var state = map.m_State;
  1591. state.SetInitialStateCheckPending(m_ActionIndexInState);
  1592. }
  1593. // NOTE: This does *NOT* check whether the control is valid according to the binding it
  1594. // resolved from and/or the current binding mask. If, for example, the binding is
  1595. // "<Keyboard>/#(ä)" and the keyboard switches from a DE layout to a US layout, the
  1596. // key would still be considered valid even if the path in the binding would actually
  1597. // no longer resolve to it.
  1598. internal bool ActiveControlIsValid(InputControl control)
  1599. {
  1600. if (control == null)
  1601. return false;
  1602. // Device must still be added.
  1603. var device = control.device;
  1604. if (!device.added)
  1605. return false;
  1606. // If we have a device list in the map or asset, device
  1607. // must be in list.
  1608. var map = GetOrCreateActionMap();
  1609. var deviceList = map.devices;
  1610. if (deviceList != null && !deviceList.Value.ContainsReference(device))
  1611. return false;
  1612. return true;
  1613. }
  1614. internal InputBinding? FindEffectiveBindingMask()
  1615. {
  1616. if (m_BindingMask.HasValue)
  1617. return m_BindingMask;
  1618. if (m_ActionMap?.m_BindingMask != null)
  1619. return m_ActionMap.m_BindingMask;
  1620. return m_ActionMap?.m_Asset?.m_BindingMask;
  1621. }
  1622. internal int BindingIndexOnActionToBindingIndexOnMap(int indexOfBindingOnAction)
  1623. {
  1624. // We don't want to hit InputAction.bindings here as this requires setting up per-action
  1625. // binding info which we then nuke as part of the override process. Calling ApplyBindingOverride
  1626. // repeatedly with an index would thus cause the same data to be computed and thrown away
  1627. // over and over.
  1628. // Instead we manually search through the map's bindings to find the right binding index
  1629. // in the map.
  1630. var actionMap = GetOrCreateActionMap();
  1631. var bindingsInMap = actionMap.m_Bindings;
  1632. var bindingCountInMap = bindingsInMap.LengthSafe();
  1633. var actionName = name;
  1634. var currentBindingIndexOnAction = -1;
  1635. for (var i = 0; i < bindingCountInMap; ++i)
  1636. {
  1637. ref var binding = ref bindingsInMap[i];
  1638. if (!binding.TriggersAction(this))
  1639. continue;
  1640. ++currentBindingIndexOnAction;
  1641. if (currentBindingIndexOnAction == indexOfBindingOnAction)
  1642. return i;
  1643. }
  1644. throw new ArgumentOutOfRangeException(nameof(indexOfBindingOnAction),
  1645. $"Binding index {indexOfBindingOnAction} is out of range for action '{this}' with {currentBindingIndexOnAction + 1} bindings");
  1646. }
  1647. internal int BindingIndexOnMapToBindingIndexOnAction(int indexOfBindingOnMap)
  1648. {
  1649. var actionMap = GetOrCreateActionMap();
  1650. var bindingsInMap = actionMap.m_Bindings;
  1651. var actionName = name;
  1652. var bindingIndexOnAction = 0;
  1653. for (var i = indexOfBindingOnMap - 1; i >= 0; --i)
  1654. {
  1655. ref var binding = ref bindingsInMap[i];
  1656. if (string.Compare(binding.action, actionName, StringComparison.InvariantCultureIgnoreCase) == 0 ||
  1657. binding.action == m_Id)
  1658. ++bindingIndexOnAction;
  1659. }
  1660. return bindingIndexOnAction;
  1661. }
  1662. ////TODO: make current event available in some form
  1663. ////TODO: make source binding info available (binding index? binding instance?)
  1664. /// <summary>
  1665. /// Information provided to action callbacks about what triggered an action.
  1666. /// </summary>
  1667. /// <remarks>
  1668. /// This struct should not be held on to past the duration of the callback.
  1669. /// </remarks>
  1670. /// <seealso cref="performed"/>
  1671. /// <seealso cref="started"/>
  1672. /// <seealso cref="canceled"/>
  1673. /// <seealso cref="InputActionMap.actionTriggered"/>
  1674. public struct CallbackContext // Ideally would be a ref struct but couldn't use it in lambdas then.
  1675. {
  1676. internal InputActionState m_State;
  1677. internal int m_ActionIndex;
  1678. ////REVIEW: there should probably be a mechanism for the user to be able to correlate
  1679. //// the callback to a specific binding on the action
  1680. private int actionIndex => m_ActionIndex;
  1681. private unsafe int bindingIndex => m_State.actionStates[actionIndex].bindingIndex;
  1682. private unsafe int controlIndex => m_State.actionStates[actionIndex].controlIndex;
  1683. private unsafe int interactionIndex => m_State.actionStates[actionIndex].interactionIndex;
  1684. /// <summary>
  1685. /// Current phase of the action. Equivalent to accessing <see cref="InputAction.phase"/>
  1686. /// on <see cref="action"/>.
  1687. /// </summary>
  1688. /// <value>Current phase of the action.</value>
  1689. /// <seealso cref="started"/>
  1690. /// <seealso cref="performed"/>
  1691. /// <seealso cref="canceled"/>
  1692. /// <seealso cref="InputAction.phase"/>
  1693. public unsafe InputActionPhase phase
  1694. {
  1695. get
  1696. {
  1697. if (m_State == null)
  1698. return InputActionPhase.Disabled;
  1699. return m_State.actionStates[actionIndex].phase;
  1700. }
  1701. }
  1702. /// <summary>
  1703. /// Whether the <see cref="action"/> has just been started.
  1704. /// </summary>
  1705. /// <value>If true, the action was just started.</value>
  1706. /// <seealso cref="InputAction.started"/>
  1707. public bool started => phase == InputActionPhase.Started;
  1708. /// <summary>
  1709. /// Whether the <see cref="action"/> has just been performed.
  1710. /// </summary>
  1711. /// <value>If true, the action was just performed.</value>
  1712. /// <seealso cref="InputAction.performed"/>
  1713. public bool performed => phase == InputActionPhase.Performed;
  1714. /// <summary>
  1715. /// Whether the <see cref="action"/> has just been canceled.
  1716. /// </summary>
  1717. /// <value>If true, the action was just canceled.</value>
  1718. /// <seealso cref="InputAction.canceled"/>
  1719. public bool canceled => phase == InputActionPhase.Canceled;
  1720. /// <summary>
  1721. /// The action that got triggered.
  1722. /// </summary>
  1723. /// <value>Action that got triggered.</value>
  1724. public InputAction action => m_State?.GetActionOrNull(bindingIndex);
  1725. /// <summary>
  1726. /// The control that triggered the action.
  1727. /// </summary>
  1728. /// <value>Control that triggered the action.</value>
  1729. /// <remarks>
  1730. /// In case of a composite binding, this is the control of the composite that activated the
  1731. /// composite as a whole. For example, in case of a WASD-style binding, it could be the W key.
  1732. ///
  1733. /// Note that an action may also change its <see cref="phase"/> in response to a timeout.
  1734. /// For example, a <see cref="Interactions.TapInteraction"/> will cancel itself if the
  1735. /// button control is not released within a certain time. When this happens, the <c>control</c>
  1736. /// property will be the control that last fed input into the action.
  1737. /// </remarks>
  1738. /// <seealso cref="InputAction.controls"/>
  1739. /// <seealso cref="InputBinding.path"/>
  1740. public InputControl control => m_State?.controls[controlIndex];
  1741. /// <summary>
  1742. /// The interaction that triggered the action or <c>null</c> if the binding that triggered does not
  1743. /// have any particular interaction set on it.
  1744. /// </summary>
  1745. /// <value>Interaction that triggered the callback.</value>
  1746. /// <remarks>
  1747. /// <example>
  1748. /// <code>
  1749. /// void FirePerformed(InputAction.CallbackContext context)
  1750. /// {
  1751. /// // If SlowTap interaction was performed, perform a charged
  1752. /// // firing. Otherwise, fire normally.
  1753. /// if (context.interaction is SlowTapInteraction)
  1754. /// FireChargedProjectile();
  1755. /// else
  1756. /// FireNormalProjectile();
  1757. /// }
  1758. /// </code>
  1759. /// </example>
  1760. /// </remarks>
  1761. /// <seealso cref="InputBinding.interactions"/>
  1762. /// <seealso cref="InputAction.interactions"/>
  1763. public IInputInteraction interaction
  1764. {
  1765. get
  1766. {
  1767. if (m_State == null)
  1768. return null;
  1769. var index = interactionIndex;
  1770. if (index == InputActionState.kInvalidIndex)
  1771. return null;
  1772. return m_State.interactions[index];
  1773. }
  1774. }
  1775. /// <summary>
  1776. /// The time at which the action got triggered.
  1777. /// </summary>
  1778. /// <value>Time relative to <c>Time.realtimeSinceStartup</c> at which
  1779. /// the action got triggered.</value>
  1780. /// <remarks>
  1781. /// This is usually determined by the timestamp of the input event that activated a control
  1782. /// bound to the action. What this means is that this is normally <em>not</em> the
  1783. /// value of <c>Time.realtimeSinceStartup</c> when the input system calls the
  1784. /// callback but rather the time at which the input was generated that triggered
  1785. /// the action.
  1786. /// </remarks>
  1787. /// <seealso cref="InputEvent.time"/>
  1788. public unsafe double time
  1789. {
  1790. get
  1791. {
  1792. if (m_State == null)
  1793. return 0;
  1794. return m_State.actionStates[actionIndex].time;
  1795. }
  1796. }
  1797. /// <summary>
  1798. /// Time at which the action was started.
  1799. /// </summary>
  1800. /// <value>Value relative to <c>Time.realtimeSinceStartup</c> when the action
  1801. /// changed to <see cref="started"/>.</value>
  1802. /// <remarks>
  1803. /// This is only relevant for actions that go through distinct a <see cref="InputActionPhase.Started"/>
  1804. /// cycle as driven by <see cref="IInputInteraction">interactions</see>.
  1805. ///
  1806. /// The value of this property is that of <see cref="time"/> when <see
  1807. /// cref="InputAction.started"/> was called. See the <see cref="time"/>
  1808. /// property for how the timestamp works.
  1809. /// </remarks>
  1810. public unsafe double startTime
  1811. {
  1812. get
  1813. {
  1814. if (m_State == null)
  1815. return 0;
  1816. return m_State.actionStates[actionIndex].startTime;
  1817. }
  1818. }
  1819. /// <summary>
  1820. /// Time difference between <see cref="time"/> and <see cref="startTime"/>.
  1821. /// </summary>
  1822. /// <value>Difference between <see cref="time"/> and <see cref="startTime"/>.</value>
  1823. /// <remarks>
  1824. /// This property can be used, for example, to determine how long a button
  1825. /// was held down.
  1826. ///
  1827. /// <example>
  1828. /// <code>
  1829. /// // Let's create a button action bound to the A button
  1830. /// // on the gamepad.
  1831. /// var action = new InputAction(
  1832. /// type: InputActionType.Button,
  1833. /// binding: "&lt;Gamepad&gt;/buttonSouth");
  1834. ///
  1835. /// // When the action is performed (which will happen when the
  1836. /// // button is pressed and then released) we take the duration
  1837. /// // of the press to determine how many projectiles to spawn.
  1838. /// action.performed +=
  1839. /// context =>
  1840. /// {
  1841. /// const float kSpawnRate = 3; // 3 projectiles per second
  1842. /// var projectileCount = kSpawnRate * context.duration;
  1843. /// for (var i = 0; i &lt; projectileCount; ++i)
  1844. /// {
  1845. /// var projectile = UnityEngine.Object.Instantiate(projectile);
  1846. /// // Apply other changes to the projectile...
  1847. /// }
  1848. /// };
  1849. /// </code>
  1850. /// </example>
  1851. /// </remarks>
  1852. public double duration => time - startTime;
  1853. /// <summary>
  1854. /// Type of value returned by <see cref="ReadValueAsObject"/> and expected
  1855. /// by <see cref="ReadValue{TValue}"/>.
  1856. /// </summary>
  1857. /// <value>Type of object returned when reading a value.</value>
  1858. /// <remarks>
  1859. /// The type of value returned by an action is usually determined by the
  1860. /// <see cref="InputControl"/> that triggered the action, i.e. by the
  1861. /// control referenced from <see cref="control"/>.
  1862. ///
  1863. /// However, if the binding that triggered is a composite, then the composite
  1864. /// will determine values and not the individual control that triggered (that
  1865. /// one just feeds values into the composite).
  1866. /// </remarks>
  1867. /// <seealso cref="InputControl.valueType"/>
  1868. /// <seealso cref="InputBindingComposite.valueType"/>
  1869. /// <seealso cref="activeValueType"/>
  1870. public Type valueType => m_State?.GetValueType(bindingIndex, controlIndex);
  1871. /// <summary>
  1872. /// Size of values returned by <see cref="ReadValue(void*,int)"/>.
  1873. /// </summary>
  1874. /// <value>Size of value returned when reading.</value>
  1875. /// <remarks>
  1876. /// All input values passed around by the system are required to be "blittable",
  1877. /// i.e. they cannot contain references, cannot be heap objects themselves, and
  1878. /// must be trivially mem-copyable. This means that any value can be read out
  1879. /// and retained in a raw byte buffer.
  1880. ///
  1881. /// The value of this property determines how many bytes will be written
  1882. /// by <see cref="ReadValue(void*,int)"/>.
  1883. /// </remarks>
  1884. /// <seealso cref="InputControl.valueSizeInBytes"/>
  1885. /// <seealso cref="InputBindingComposite.valueSizeInBytes"/>
  1886. /// <seealso cref="ReadValue(void*,int)"/>
  1887. public int valueSizeInBytes
  1888. {
  1889. get
  1890. {
  1891. if (m_State == null)
  1892. return 0;
  1893. return m_State.GetValueSizeInBytes(bindingIndex, controlIndex);
  1894. }
  1895. }
  1896. /// <summary>
  1897. /// Read the value of the action as a raw byte buffer. This allows reading
  1898. /// values without having to know value types but also, unlike <see cref="ReadValueAsObject"/>,
  1899. /// without allocating GC heap memory.
  1900. /// </summary>
  1901. /// <param name="buffer">Memory buffer to read the value into.</param>
  1902. /// <param name="bufferSize">Size of buffer allocated at <paramref name="buffer"/>. Must be
  1903. /// at least <see cref="valueSizeInBytes"/>.</param>
  1904. /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is <c>null</c>.</exception>
  1905. /// <exception cref="ArgumentException"><paramref name="bufferSize"/> is too small.</exception>
  1906. /// <remarks>
  1907. /// <example>
  1908. /// <code>
  1909. /// // Read a Vector2 using the raw memory ReadValue API.
  1910. /// // Here we just read into a local variable which we could
  1911. /// // just as well (and more easily) do using ReadValue&lt;Vector2&gt;.
  1912. /// // Still, it serves as a demonstration for how the API
  1913. /// // operates in general.
  1914. /// unsafe
  1915. /// {
  1916. /// var value = default(Vector2);
  1917. /// var valuePtr = UnsafeUtility.AddressOf(ref value);
  1918. /// context.ReadValue(buffer, UnsafeUtility.SizeOf&lt;Vector2&gt;());
  1919. /// }
  1920. /// </code>
  1921. /// </example>
  1922. /// </remarks>
  1923. /// <seealso cref="InputControlExtensions.ReadValueIntoBuffer"/>
  1924. /// <seealso cref="InputAction.ReadValue{TValue}"/>
  1925. /// <seealso cref="ReadValue{TValue}"/>
  1926. public unsafe void ReadValue(void* buffer, int bufferSize)
  1927. {
  1928. if (buffer == null)
  1929. throw new ArgumentNullException(nameof(buffer));
  1930. if (m_State != null && phase.IsInProgress())
  1931. {
  1932. m_State.ReadValue(bindingIndex, controlIndex, buffer, bufferSize);
  1933. }
  1934. else
  1935. {
  1936. var valueSize = valueSizeInBytes;
  1937. if (bufferSize < valueSize)
  1938. throw new ArgumentException(
  1939. $"Expected buffer of at least {valueSize} bytes but got buffer of only {bufferSize} bytes", nameof(bufferSize));
  1940. UnsafeUtility.MemClear(buffer, valueSizeInBytes);
  1941. }
  1942. }
  1943. /// <summary>
  1944. /// Read the value of the action.
  1945. /// </summary>
  1946. /// <typeparam name="TValue">Type of value to read. This must correspond to the
  1947. /// expected by either <see cref="control"/> or, if it is a composite, by the
  1948. /// <see cref="InputBindingComposite"/> in use.</typeparam>
  1949. /// <returns>The value read from the action.</returns>
  1950. /// <exception cref="InvalidOperationException">The given type <typeparamref name="TValue"/>
  1951. /// does not match the value type expected by the control or binding composite.</exception>
  1952. /// <seealso cref="InputAction.ReadValue{TValue}"/>
  1953. /// <seealso cref="ReadValue(void*,int)"/>
  1954. /// <seealso cref="ReadValueAsObject"/>
  1955. public TValue ReadValue<TValue>()
  1956. where TValue : struct
  1957. {
  1958. var value = default(TValue);
  1959. if (m_State != null)
  1960. {
  1961. value = phase.IsInProgress() ?
  1962. m_State.ReadValue<TValue>(bindingIndex, controlIndex) :
  1963. m_State.ApplyProcessors(bindingIndex, value);
  1964. }
  1965. return value;
  1966. }
  1967. /// <summary>
  1968. /// Read the current value of the action as a <c>float</c> and return true if it is equal to
  1969. /// or greater than the button press threshold.
  1970. /// </summary>
  1971. /// <returns>True if the action is considered in "pressed" state, false otherwise.</returns>
  1972. /// <remarks>
  1973. /// If the currently active control is a <see cref="ButtonControl"/>, the <see cref="ButtonControl.pressPoint"/>
  1974. /// of the button will be taken into account (if set). If there is no custom button press point, the
  1975. /// global <see cref="InputSettings.defaultButtonPressPoint"/> will be used.
  1976. /// </remarks>
  1977. /// <seealso cref="InputSettings.defaultButtonPressPoint"/>
  1978. /// <seealso cref="ButtonControl.pressPoint"/>
  1979. public bool ReadValueAsButton()
  1980. {
  1981. var value = false;
  1982. if (m_State != null && phase.IsInProgress())
  1983. value = m_State.ReadValueAsButton(bindingIndex, controlIndex);
  1984. return value;
  1985. }
  1986. /// <summary>
  1987. /// Same as <see cref="ReadValue{TValue}"/> except that it is not necessary to
  1988. /// know the type of value at compile time.
  1989. /// </summary>
  1990. /// <returns>The current value from the binding that triggered the action or <c>null</c> if the action
  1991. /// is not currently in progress.</returns>
  1992. /// <remarks>
  1993. /// This method allocates GC heap memory. Using it during normal gameplay will lead
  1994. /// to frame-rate instabilities.
  1995. /// </remarks>
  1996. /// <seealso cref="ReadValue{TValue}"/>
  1997. /// <seealso cref="InputAction.ReadValueAsObject"/>
  1998. public object ReadValueAsObject()
  1999. {
  2000. if (m_State != null && phase.IsInProgress())
  2001. return m_State.ReadValueAsObject(bindingIndex, controlIndex);
  2002. return null;
  2003. }
  2004. /// <summary>
  2005. /// Return a string representation of the context useful for debugging.
  2006. /// </summary>
  2007. /// <returns>String representation of the context.</returns>
  2008. public override string ToString()
  2009. {
  2010. return $"{{ action={action} phase={phase} time={time} control={control} value={ReadValueAsObject()} interaction={interaction} }}";
  2011. }
  2012. }
  2013. }
  2014. }