InputAction.cs 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  1. using System;
  2. using UnityEngine.InputSystem.LowLevel;
  3. using UnityEngine.InputSystem.Utilities;
  4. using UnityEngine.Serialization;
  5. ////TODO: add way to retrieve the binding correspond to a control
  6. ////TODO: add way to retrieve the currently ongoing interaction and also add way to know how long it's been going on
  7. ////FIXME: Whether a control from a binding that's part of a composite appears on an action is currently not consistently enforced.
  8. //// If it mentions the action, it appears on the action. Otherwise it doesn't. The controls should consistently appear on the
  9. //// action based on what action the *composite* references.
  10. ////REVIEW: Should we bring the checkboxes for actions back? We tried to "simplify" things by collapsing everything into a InputActionTypes
  11. //// and making the various behavior toggles implicit in that. However, my impression is that this has largely backfired by making
  12. //// 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
  13. //// perfectly.
  14. ////
  15. //// My impression is that at least two the following two checkboxes would make sense:
  16. //// 1) Initial State Check? Whether the action should immediately sync to the current state of controls when enabled.
  17. //// 2) Resolve Conflicting Inputs? Whether the action should try to resolve conflicts between multiple concurrent inputs.
  18. ////
  19. //// I'm fine hiding this under an "Advanced" foldout or something. But IMO, control over this should be available to the user.
  20. ////
  21. //// 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/).
  22. ////REVIEW: I think the action system as it is today offers too many ways to shoot yourself in the foot. It has
  23. //// flexibility but at the same time has abundant opportunity for ending up with dysfunction. Common setups
  24. //// have to come preconfigured and work robustly for the user without requiring much understanding of how
  25. //// the system fits together.
  26. ////REVIEW: have single delegate instead of separate performed/started/canceled callbacks?
  27. ////REVIEW: Do we need to have separate display names for actions?
  28. ////TODO: allow changing bindings without having to disable
  29. ////REVIEW: what about having the concept of "consumed" on the callback context?
  30. ////REVIEW: have "Always Enabled" toggle on actions?
  31. namespace UnityEngine.InputSystem
  32. {
  33. /// <summary>
  34. /// A named input signal that can flexibly decide which input data to tap.
  35. /// </summary>
  36. /// <remarks>
  37. /// An input action is an abstraction over the source of input(s) it receives. They are
  38. /// most useful for representing input as "logical" concepts (e.g. "jump") rather than
  39. /// as "physical" inputs (e.g. "space bar on keyboard pressed").
  40. ///
  41. /// In its most basic form, an action is simply an object along with a collection of
  42. /// bindings that trigger the action.
  43. ///
  44. /// <example>
  45. /// <code>
  46. /// // A simple action can be created directly using `new`. If desired, a binding
  47. /// // can be specified directly as part of construction.
  48. /// var action = new InputAction(binding: "&lt;Gamepad&gt;/buttonSouth");
  49. ///
  50. /// // Additional bindings can be added using `AddBinding`.
  51. /// action.AddBinding("&lt;Mouse&gt;/leftButton");
  52. /// </code>
  53. /// </example>
  54. ///
  55. /// Bindings use control path expressions to reference controls. See <see cref="InputBinding"/>
  56. /// for more details. There may be arbitrary many bindings targeting a single action. The
  57. /// list of bindings targeting an action can be obtained through <see cref="bindings"/>.
  58. ///
  59. /// By itself an action does not do anything until it is enabled:
  60. ///
  61. /// <example>
  62. /// <code>
  63. /// action.Enable();
  64. /// </code>
  65. /// </example>
  66. ///
  67. /// Once enabled, the action will actively monitor all controls on devices present
  68. /// in the system (see <see cref="InputSystem.devices"/>) that match any of the binding paths
  69. /// associated with the action. If you want to restrict the set of bindings used at runtime
  70. /// or restrict the set of devices which controls are chosen from, you can do so using
  71. /// <see cref="bindingMask"/> or, if the action is part of an <see cref="InputActionMap"/>,
  72. /// by setting the <see cref="InputActionMap.devices"/> property of the action map. The
  73. /// controls that an action uses can be queried using the <see cref="controls"/> property.
  74. ///
  75. /// When input is received on controls bound to an action, the action will trigger callbacks
  76. /// in response. These callbacks are <see cref="started"/>, <see cref="performed"/>, and
  77. /// <see cref="canceled"/>. The callbacks are triggered as part of input system updates
  78. /// (see <see cref="InputSystem.Update"/>), i.e. they happen before the respective
  79. /// <c>MonoBehaviour.Update</c> or <c>MonoBehaviour.FixedUpdate</c> methods
  80. /// get executed (depending on which <see cref="InputSettings.updateMode"/> the system is
  81. /// set to).
  82. ///
  83. /// In what order and how those callbacks get triggered depends on both the <see cref="type"/>
  84. /// of the action as well as on the interactions (see <see cref="IInputInteraction"/>) present
  85. /// on the bindings of the action. The default behavior is that when a control is actuated
  86. /// (i.e. moving away from its resting position), <see cref="started"/> is called and then
  87. /// <see cref="performed"/>. Subsequently, whenever the a control further changes value to
  88. /// anything other than its default value, <see cref="performed"/> will be called again.
  89. /// Finally, when the control moves back to its default value (i.e. resting position),
  90. /// <see cref="canceled"/> is called.
  91. ///
  92. /// To hook into the callbacks, there are several options available to you. The most obvious
  93. /// one is to hook directly into <see cref="started"/>, <see cref="performed"/>, and/or
  94. /// <see cref="canceled"/>. In these callbacks, you will receive a <see cref="CallbackContext"/>
  95. /// with information about how the action got triggered. For example, you can use <see
  96. /// cref="CallbackContext.ReadValue{TValue}"/> to read the value from the binding that triggered
  97. /// or use <see cref="CallbackContext.interaction"/> to find the interaction that is in progress.
  98. ///
  99. /// <example>
  100. /// <code>
  101. /// action.started += context => Debug.Log($"{context.action} started");
  102. /// action.performed += context => Debug.Log($"{context.action} performed");
  103. /// action.canceled += context => Debug.Log($"{context.action} canceled");
  104. /// </code>
  105. /// </example>
  106. ///
  107. /// Alternatively, you can use the <see cref="InputActionMap.actionTriggered"/> callback for
  108. /// actions that are part of an action map or the global <see cref="InputSystem.onActionChange"/>
  109. /// callback to globally listen for action activity. To simply record action activity instead
  110. /// of responding to it directly, you can use <see cref="InputActionTrace"/>.
  111. ///
  112. /// If you prefer to poll an action directly as part of your <c>MonoBehaviour.Update</c>
  113. /// or <c>MonoBehaviour.FixedUpdate</c> logic, you can do so using the <see cref="triggered"/>
  114. /// and <see cref="ReadValue{TValue}"/> methods.
  115. ///
  116. /// <example>
  117. /// <code>
  118. /// protected void Update()
  119. /// {
  120. /// // For a button type action.
  121. /// if (action.triggered)
  122. /// /* ... */;
  123. ///
  124. /// // For a value type action.
  125. /// // (Vector2 is just an example; pick the value type that is the right
  126. /// // one according to the bindings you have)
  127. /// var v = action.ReadValue&lt;Vector2&gt;();
  128. /// }
  129. /// </code>
  130. /// </example>
  131. ///
  132. /// Note that actions are not generally frame-based. What this means is that an action
  133. /// will observe any value change on its connected controls, even if the control changes
  134. /// value multiple times in the same frame. In practice, this means that, for example,
  135. /// no button press will get missed.
  136. ///
  137. /// Actions can be grouped into maps (see <see cref="InputActionMap"/>) which can in turn
  138. /// be grouped into assets (see <see cref="InputActionAsset"/>).
  139. ///
  140. /// Please note that actions are a player-only feature. They are not supported in
  141. /// edit mode.
  142. ///
  143. /// For more in-depth reading on actions, see the <a href="../manual/Actions.html">manual</a>.
  144. /// </remarks>
  145. /// <seealso cref="InputActionMap"/>
  146. /// <seealso cref="InputActionAsset"/>
  147. /// <seealso cref="InputBinding"/>
  148. [Serializable]
  149. public sealed class InputAction : ICloneable, IDisposable
  150. {
  151. /// <summary>
  152. /// Name of the action.
  153. /// </summary>
  154. /// <value>Plain-text name of the action.</value>
  155. /// <remarks>
  156. /// Can be null for anonymous actions created in code.
  157. ///
  158. /// If the action is part of an <see cref="InputActionMap"/>, it will have a name and the name
  159. /// will be unique in the map. The name is just the name of the action alone, not a "mapName/actionName"
  160. /// combination.
  161. ///
  162. /// The name should not contain slashes or dots but can contain spaces and other punctuation.
  163. ///
  164. /// An action can be renamed after creation using <see cref="InputActionSetupExtensions.Rename"/>..
  165. /// </remarks>
  166. /// <seealso cref="InputActionMap.FindAction(string,bool)"/>
  167. public string name => m_Name;
  168. /// <summary>
  169. /// Behavior type of the action.
  170. /// </summary>
  171. /// <value>General behavior type of the action.</value>
  172. /// <remarks>
  173. /// Determines how the action gets triggered in response to control value changes.
  174. ///
  175. /// For details about how the action type affects an action, see <see cref="InputActionType"/>.
  176. /// </remarks>
  177. public InputActionType type => m_Type;
  178. /// <summary>
  179. /// A stable, unique identifier for the action.
  180. /// </summary>
  181. /// <value>Unique ID of the action.</value>
  182. /// <remarks>
  183. /// This can be used instead of the name to refer to the action. Doing so allows referring to the
  184. /// action such that renaming the action does not break references.
  185. /// </remarks>
  186. public Guid id
  187. {
  188. get
  189. {
  190. MakeSureIdIsInPlace();
  191. return new Guid(m_Id);
  192. }
  193. }
  194. internal Guid idDontGenerate
  195. {
  196. get
  197. {
  198. if (string.IsNullOrEmpty(m_Id))
  199. return default;
  200. return new Guid(m_Id);
  201. }
  202. }
  203. /// <summary>
  204. /// Name of control layout expected for controls bound to this action.
  205. /// </summary>
  206. /// <remarks>
  207. /// This is optional and is null by default.
  208. ///
  209. /// Constraining an action to a particular control layout allows determine the value
  210. /// type and expected input behavior of an action without being reliant on any particular
  211. /// binding.
  212. /// </remarks>
  213. public string expectedControlType
  214. {
  215. get => m_ExpectedControlType;
  216. set => m_ExpectedControlType = value;
  217. }
  218. /// <summary>
  219. /// Processors applied to every binding on the action.
  220. /// </summary>
  221. /// <value>Processors added to all bindings on the action.</value>
  222. /// <remarks>
  223. /// This property is equivalent to appending the same string to the
  224. /// <see cref="InputBinding.processors"/> field of every binding that targets
  225. /// the action. It is thus simply a means of avoiding the need configure the
  226. /// same processor the same way on every binding in case it uniformly applies
  227. /// to all of them.
  228. ///
  229. /// <example>
  230. /// <code>
  231. /// var action = new InputAction(processors: "scaleVector2(x=2, y=2)");
  232. ///
  233. /// // Both of the following bindings will implicitly have a
  234. /// // ScaleVector2Processor applied to them.
  235. /// action.AddBinding("&lt;Gamepad&gt;/leftStick");
  236. /// action.AddBinding("&lt;Joystick&gt;/stick");
  237. /// </code>
  238. /// </example>
  239. /// </remarks>
  240. /// <seealso cref="InputBinding.processors"/>
  241. /// <seealso cref="InputProcessor"/>
  242. /// <seealso cref="InputSystem.RegisterProcessor{T}"/>
  243. public string processors => m_Processors;
  244. /// <summary>
  245. /// Interactions applied to every binding on the action.
  246. /// </summary>
  247. /// <value>Interactions added to all bindings on the action.</value>
  248. /// <remarks>
  249. /// This property is equivalent to appending the same string to the
  250. /// <see cref="InputBinding.interactions"/> field of every binding that targets
  251. /// the action. It is thus simply a means of avoiding the need configure the
  252. /// same interaction the same way on every binding in case it uniformly applies
  253. /// to all of them.
  254. ///
  255. /// <example>
  256. /// <code>
  257. /// var action = new InputAction(interactions: "press");
  258. ///
  259. /// // Both of the following bindings will implicitly have a
  260. /// // Press interaction applied to them.
  261. /// action.AddBinding("&lt;Gamepad&gt;/buttonSouth");
  262. /// action.AddBinding("&lt;Joystick&gt;/trigger");
  263. /// </code>
  264. /// </example>
  265. /// </remarks>
  266. /// <seealso cref="InputBinding.interactions"/>
  267. /// <seealso cref="IInputInteraction"/>
  268. /// <seealso cref="InputSystem.RegisterInteraction{T}"/>
  269. public string interactions => m_Interactions;
  270. /// <summary>
  271. /// The map the action belongs to.
  272. /// </summary>
  273. /// <value><see cref="InputActionMap"/> that the action belongs to or null.</value>
  274. /// <remarks>
  275. /// If the action is a loose action created in code, this will be <c>null</c>.
  276. ///
  277. /// <example>
  278. /// <code>
  279. /// var action1 = new InputAction(); // action1.actionMap will be null
  280. ///
  281. /// var actionMap = new InputActionMap();
  282. /// var action2 = actionMap.AddAction("action"); // action2.actionMap will point to actionMap
  283. /// </code>
  284. /// </example>
  285. /// </remarks>
  286. /// <seealso cref="InputActionSetupExtensions.AddAction"/>
  287. public InputActionMap actionMap => isSingletonAction ? null : m_ActionMap;
  288. /// <summary>
  289. /// An optional mask that determines which bindings of the action to enable and
  290. /// which to ignore.
  291. /// </summary>
  292. /// <value>Optional mask that determines which bindings on the action to enable.</value>
  293. /// <remarks>
  294. /// Binding masks can be applied at three different levels: for an entire asset through
  295. /// <see cref="InputActionAsset.bindingMask"/>, for a specific map through <see
  296. /// cref="InputActionMap.bindingMask"/>, and for single actions through this property.
  297. /// By default, none of the masks will be set (i.e. they will be <c>null</c>).
  298. ///
  299. /// When an action is enabled, all the binding masks that apply to it are taken into
  300. /// account. Specifically, this means that any given binding on the action will be
  301. /// enabled only if it matches the mask applied to the asset, the mask applied
  302. /// to the map that contains the action, and the mask applied to the action itself.
  303. /// All the masks are individually optional.
  304. ///
  305. /// Masks are matched against bindings using <see cref="InputBinding.Matches"/>.
  306. ///
  307. /// Note that if you modify the masks applicable to an action while it is
  308. /// enabled, the action's <see cref="controls"/> will get updated immediately to
  309. /// respect the mask. To avoid repeated binding resolution, it is most efficient
  310. /// to apply binding masks before enabling actions.
  311. ///
  312. /// Binding masks are non-destructive. All the bindings on the action are left
  313. /// in place. Setting a mask will not affect the value of the <see cref="bindings"/>
  314. /// property.
  315. ///
  316. /// <example>
  317. /// <code>
  318. /// // Create a free-standing action with two bindings, one in the
  319. /// // "Keyboard" group and one in the "Gamepad" group.
  320. /// var action = new InputAction();
  321. /// action.AddBinding("&lt;Gamepad&gt;/buttonSouth", groups: "Gamepad");
  322. /// action.AddBinding("&lt;Keyboard&gt;/space", groups: "Keyboard");
  323. ///
  324. /// // By default, all bindings will be enabled. This means if both
  325. /// // a keyboard and gamepad (or several of them) is present, the action
  326. /// // will respond to input from all of them.
  327. /// action.Enable();
  328. ///
  329. /// // With a binding mask we can restrict the action to just specific
  330. /// // bindings. For example, to only enable the gamepad binding:
  331. /// action.bindingMask = InputBinding.MaskByGroup("Gamepad");
  332. ///
  333. /// // Note that we can mask by more than just by group. Masking by path
  334. /// // or by action as well as a combination of these is also possible.
  335. /// // We could, for example, mask for just a specific binding path:
  336. /// action.bindingMask = new InputBinding()
  337. /// {
  338. /// // Select the keyboard binding based on its specific path.
  339. /// path = "&lt;Keyboard&gt;/space"
  340. /// };
  341. /// </code>
  342. /// </example>
  343. /// </remarks>
  344. /// <seealso cref="InputBinding.MaskByGroup"/>
  345. /// <seealso cref="InputActionMap.bindingMask"/>
  346. /// <seealso cref="InputActionAsset.bindingMask"/>
  347. public InputBinding? bindingMask
  348. {
  349. get => m_BindingMask;
  350. set
  351. {
  352. if (value == m_BindingMask)
  353. return;
  354. if (value != null)
  355. {
  356. var v = value.Value;
  357. v.action = name;
  358. value = v;
  359. }
  360. m_BindingMask = value;
  361. var map = GetOrCreateActionMap();
  362. if (map.m_State != null)
  363. map.LazyResolveBindings();
  364. }
  365. }
  366. /// <summary>
  367. /// The list of bindings associated with the action.
  368. /// </summary>
  369. /// <value>List of bindings for the action.</value>
  370. /// <remarks>
  371. /// This list contains all bindings from <see cref="InputActionMap.bindings"/> of the action's
  372. /// <see cref="actionMap"/> that reference the action through their <see cref="InputBinding.action"/>
  373. /// property.
  374. ///
  375. /// Note that on the first call, the list may have to be extracted from the action map first which
  376. /// may require allocating GC memory. However, once initialized, no further GC allocation hits should occur.
  377. /// If the binding setup on the map is changed, re-initialization may be required.
  378. /// </remarks>
  379. /// <seealso cref="InputActionMap.bindings"/>
  380. public ReadOnlyArray<InputBinding> bindings => GetOrCreateActionMap().GetBindingsForSingleAction(this);
  381. /// <summary>
  382. /// The set of controls to which the action's <see cref="bindings"/> resolve.
  383. /// </summary>
  384. /// <value>Controls resolved from the action's <see cref="bindings"/>.</value>
  385. /// <remarks>
  386. /// This property can be queried whether the action is enabled or not and will return the
  387. /// set of controls that match the action's bindings according to the current setup of
  388. /// binding masks (<see cref="bindingMask"/>) and device restrictions (<see
  389. /// cref="InputActionMap.devices"/>).
  390. ///
  391. /// Note that internally, controls are not stored on a per-action basis. This means
  392. /// that on the first read of this property, the list of controls for just the action
  393. /// may have to be extracted which in turn may allocate GC memory. After the first read,
  394. /// no further GC allocations should occur except if the set of controls is changed (e.g.
  395. /// by changing the binding mask or by adding/removing devices to/from the system).
  396. ///
  397. /// If the property is queried when the action has not been enabled yet, the system
  398. /// will first resolve controls on the action (and for all actions in the map and/or
  399. /// the asset). See <a href="../manual/ActionBindings.html#binding-resolution">Binding Resolution</a>
  400. /// in the manual for details.
  401. /// </remarks>
  402. public ReadOnlyArray<InputControl> controls
  403. {
  404. get
  405. {
  406. var map = GetOrCreateActionMap();
  407. map.ResolveBindingsIfNecessary();
  408. return map.GetControlsForSingleAction(this);
  409. }
  410. }
  411. /// <summary>
  412. /// The current phase of the action.
  413. /// </summary>
  414. /// <remarks>
  415. /// When listening for control input and when responding to control value changes,
  416. /// actions will go through several possible phases.
  417. ///
  418. /// In general, when an action starts receiving input, it will go to <see cref="InputActionPhase.Started"/>
  419. /// and when it stops receiving input, it will go to <see cref="InputActionPhase.Canceled"/>.
  420. /// When <see cref="InputActionPhase.Performed"/> is used depends primarily on the type
  421. /// of action. <see cref="InputActionType.Value"/> will trigger <see cref="InputActionPhase.Performed"/>
  422. /// whenever the value of the control changes (including the first time; i.e. it will first
  423. /// trigger <see cref="InputActionPhase.Started"/> and then <see cref="InputActionPhase.Performed"/>
  424. /// right after) whereas <see cref="InputActionType.Button"/> will trigger <see cref="InputActionPhase.Performed"/>
  425. /// as soon as the button press threshold (<see cref="InputSettings.buttonPressThreshold"/>)
  426. /// has been crossed.
  427. ///
  428. /// Note that both interactions and the action <see cref="type"/> can affect the phases
  429. /// that an action goes through. <see cref="InputActionType.PassThrough"/> actions will
  430. /// only ever use <see cref="InputActionPhase.Performed"/> and not go to <see
  431. /// cref="InputActionPhase.Started"/> or <see cref="InputActionPhase.Canceled"/> (as
  432. /// pass-through actions do not follow the start-performed-canceled model in general).
  433. /// Also, interactions can choose their
  434. ///
  435. /// While an action is disabled, its phase is <see cref="InputActionPhase.Disabled"/>.
  436. /// </remarks>
  437. public InputActionPhase phase => currentState.phase;
  438. /// <summary>
  439. /// Whether the action is currently enabled, i.e. responds to input, or not.
  440. /// </summary>
  441. /// <value>True if the action is currently enabled.</value>
  442. /// <remarks>
  443. /// An action is enabled by either calling <see cref="Enable"/> on it directly or by calling
  444. /// <see cref="InputActionMap.Enable"/> on the <see cref="InputActionMap"/> containing the action.
  445. /// When enabled, an action will listen for changes on the controls it is bound to and trigger
  446. /// callbacks such as <see cref="started"/>, <see cref="performed"/>, and <see cref="canceled"/>
  447. /// in response.
  448. /// </remarks>
  449. /// <seealso cref="Enable"/>
  450. /// <seealso cref="Disable"/>
  451. /// <seealso cref="InputActionMap.Enable"/>
  452. /// <seealso cref="InputActionMap.Disable"/>
  453. /// <seealso cref="InputSystem.ListEnabledActions()"/>
  454. public bool enabled => phase != InputActionPhase.Disabled;
  455. /// <summary>
  456. /// Event that is triggered when the action has been started.
  457. /// </summary>
  458. /// <remarks>
  459. /// See <see cref="phase"/> for details of how an action progresses through phases
  460. /// and triggers this callback.
  461. /// </remarks>
  462. /// <see cref="InputActionPhase.Started"/>
  463. public event Action<CallbackContext> started
  464. {
  465. add => m_OnStarted.Append(value);
  466. remove => m_OnStarted.Remove(value);
  467. }
  468. /// <summary>
  469. /// Event that is triggered when the action has been <see cref="started"/>
  470. /// but then canceled before being fully <see cref="performed"/>.
  471. /// </summary>
  472. /// <remarks>
  473. /// See <see cref="phase"/> for details of how an action progresses through phases
  474. /// and triggers this callback.
  475. /// </remarks>
  476. /// <see cref="InputActionPhase.Canceled"/>
  477. public event Action<CallbackContext> canceled
  478. {
  479. add => m_OnCanceled.Append(value);
  480. remove => m_OnCanceled.Remove(value);
  481. }
  482. /// <summary>
  483. /// Event that is triggered when the action has been fully performed.
  484. /// </summary>
  485. /// <remarks>
  486. /// See <see cref="phase"/> for details of how an action progresses through phases
  487. /// and triggers this callback.
  488. /// </remarks>
  489. /// <see cref="InputActionPhase.Performed"/>
  490. public event Action<CallbackContext> performed
  491. {
  492. add => m_OnPerformed.Append(value);
  493. remove => m_OnPerformed.Remove(value);
  494. }
  495. /// <summary>
  496. /// Whether the action was triggered (i.e. had <see cref="performed"/> called) this frame.
  497. /// </summary>
  498. /// <remarks>
  499. /// Unlike <see cref="ReadValue{TValue}"/>, which will reset when the action goes back to waiting
  500. /// state, this property will stay true for the duration of the current frame (i.e. until the next
  501. /// <see cref="InputSystem.Update"/> runs) as long as the action was triggered at least once.
  502. ///
  503. /// <example>
  504. /// <code>
  505. /// if (myControls.gameplay.fire.triggered)
  506. /// Fire();
  507. /// </code>
  508. /// </example>
  509. /// </remarks>
  510. /// <seealso cref="InputActionType.Button"/>
  511. /// <seealso cref="ReadValue{TValue}"/>
  512. public unsafe bool triggered
  513. {
  514. get
  515. {
  516. var map = GetOrCreateActionMap();
  517. if (map.m_State == null)
  518. return false;
  519. var lastTriggeredInUpdate = map.m_State.actionStates[m_ActionIndexInState].lastTriggeredInUpdate;
  520. return lastTriggeredInUpdate != 0 && lastTriggeredInUpdate == InputUpdate.s_UpdateStepCount;
  521. }
  522. }
  523. /// <summary>
  524. /// The currently active control that is driving the action. Null while the action
  525. /// is in waiting (<see cref="InputActionPhase.Waiting"/>) or canceled (<see cref="InputActionPhase.Canceled"/>)
  526. /// state. Otherwise the control that last had activity on it which wasn't ignored.
  527. /// </summary>
  528. /// <remarks>
  529. /// Note that the control's value does not necessarily correspond to the value of the
  530. /// action (<see cref="ReadValue{TValue}"/>) as the control may be part of a composite.
  531. /// </remarks>
  532. /// <seealso cref="CallbackContext.control"/>
  533. public unsafe InputControl activeControl
  534. {
  535. get
  536. {
  537. var state = GetOrCreateActionMap().m_State;
  538. if (state != null)
  539. {
  540. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  541. var controlIndex = actionStatePtr->controlIndex;
  542. if (controlIndex != InputActionState.kInvalidIndex)
  543. return state.controls[controlIndex];
  544. }
  545. return null;
  546. }
  547. }
  548. /// <summary>
  549. /// Whether the action wants a state check on its bound controls as soon as it is enabled.
  550. /// </summary>
  551. internal bool wantsInitialStateCheck => type == InputActionType.Value;
  552. /// <summary>
  553. /// Construct an unnamed, free-standing action that is not part of any map or asset
  554. /// and has no bindings. Bindings can be added with <see
  555. /// cref="InputActionSetupExtensions.AddBinding(InputAction,string,string,string,string)"/>.
  556. /// The action type defaults to <see cref="InputActionType.Value"/>.
  557. /// </summary>
  558. /// <remarks>
  559. /// The action will not have an associated <see cref="InputActionMap"/> and <see cref="actionMap"/>
  560. /// will thus be <c>null</c>. Use <see cref="InputActionSetupExtensions.AddAction"/> instead if
  561. /// you want to add a new action to an action map.
  562. ///
  563. /// The action will remain disabled after construction and thus not listen/react to input yet.
  564. /// Use <see cref="Enable"/> to enable the action.
  565. ///
  566. /// <example>
  567. /// <code>
  568. /// // Create an action with two bindings.
  569. /// var action = new InputAction();
  570. /// action.AddBinding("&lt;Gamepad&gt;/leftStick");
  571. /// action.AddBinding("&lt;Mouse&gt;/delta");
  572. ///
  573. /// action.performed += ctx => Debug.Log("Value: " + ctx.ReadValue&lt;Vector2&gt;());
  574. ///
  575. /// action.Enable();
  576. /// </code>
  577. /// </example>
  578. /// </remarks>
  579. public InputAction()
  580. {
  581. }
  582. /// <summary>
  583. /// Construct a free-standing action that is not part of an <see cref="InputActionMap"/>.
  584. /// </summary>
  585. /// <param name="name">Name of the action. If null or empty, the action will be unnamed.</param>
  586. /// <param name="type">Type of action to create. Defaults to <see cref="InputActionType.Value"/>, i.e.
  587. /// an action that provides continuous values.</param>
  588. /// <param name="binding">If not null or empty, a binding with the given path will be added to the action
  589. /// right away. The format of the string is the as for <see cref="InputBinding.path"/>.</param>
  590. /// <param name="interactions">If <paramref name="binding"/> is not null or empty, this parameter represents
  591. /// the interaction to apply to the newly created binding (i.e. <see cref="InputBinding.interactions"/>). If
  592. /// <paramref name="binding"/> is not supplied, this parameter represents the interactions to apply to the action
  593. /// (i.e. the value of <see cref="interactions"/>).</param>
  594. /// <param name="processors">If <paramref name="binding"/> is not null or empty, this parameter represents
  595. /// the processors to apply to the newly created binding (i.e. <see cref="InputBinding.processors"/>). If
  596. /// <paramref name="binding"/> is not supplied, this parameter represents the processors to apply to the
  597. /// action (i.e. the value of <see cref="processors"/>).</param>
  598. /// <param name="expectedControlType">The optional expected control type for the action (i.e. <see
  599. /// cref="expectedControlType"/>).</param>
  600. /// <remarks>
  601. /// The action will not have an associated <see cref="InputActionMap"/> and <see cref="actionMap"/>
  602. /// will thus be <c>null</c>. Use <see cref="InputActionSetupExtensions.AddAction"/> instead if
  603. /// you want to add a new action to an action map.
  604. ///
  605. /// The action will remain disabled after construction and thus not listen/react to input yet.
  606. /// Use <see cref="Enable"/> to enable the action.
  607. ///
  608. /// Additional bindings can be added with <see
  609. /// cref="InputActionSetupExtensions.AddBinding(InputAction,string,string,string,string)"/>.
  610. ///
  611. /// <example>
  612. /// <code>
  613. /// // Create a button action responding to the gamepad A button.
  614. /// var action = new InputAction(type: InputActionType.Button, binding: "&lt;Gamepad&gt;/buttonSouth");
  615. /// action.performed += ctx => Debug.Log("Pressed");
  616. /// action.Enable();
  617. /// </code>
  618. /// </example>
  619. /// </remarks>
  620. public InputAction(string name = null, InputActionType type = default, string binding = null,
  621. string interactions = null, string processors = null, string expectedControlType = null)
  622. {
  623. m_Name = name;
  624. m_Type = type;
  625. if (!string.IsNullOrEmpty(binding))
  626. {
  627. m_SingletonActionBindings = new[]
  628. {
  629. new InputBinding
  630. {
  631. path = binding,
  632. interactions = interactions,
  633. processors = processors,
  634. action = m_Name
  635. }
  636. };
  637. m_BindingsStartIndex = 0;
  638. m_BindingsCount = 1;
  639. }
  640. else
  641. {
  642. m_Interactions = interactions;
  643. m_Processors = processors;
  644. }
  645. m_ExpectedControlType = expectedControlType;
  646. }
  647. /// <summary>
  648. /// Release internal state held on to by the action.
  649. /// </summary>
  650. /// <remarks>
  651. /// Once enabled, actions will allocate a block of state internally that they will hold on to
  652. /// until disposed of. For free-standing actions, that state is private to just the action.
  653. /// For actions that are part of <see cref="InputActionMap"/>s, the state is shared by all
  654. /// actions in the map and, if the map itself is part of an <see cref="InputActionAsset"/>,
  655. /// also by all the maps that are part of the asset.
  656. ///
  657. /// Note that the internal state holds on to GC heap memory as well as memory from the
  658. /// unmanaged, C++ heap.
  659. /// </remarks>
  660. public void Dispose()
  661. {
  662. m_ActionMap?.m_State?.Dispose();
  663. }
  664. /// <summary>
  665. /// Return a string version of the action. Mainly useful for debugging.
  666. /// </summary>
  667. /// <returns>A string version of the action.</returns>
  668. public override string ToString()
  669. {
  670. string str;
  671. if (m_Name == null)
  672. str = "<Unnamed>";
  673. else if (m_ActionMap != null && !isSingletonAction && !string.IsNullOrEmpty(m_ActionMap.name))
  674. str = $"{m_ActionMap.name}/{m_Name}";
  675. else
  676. str = m_Name;
  677. var controls = this.controls;
  678. if (controls.Count > 0)
  679. {
  680. str += "[";
  681. var isFirst = true;
  682. foreach (var control in controls)
  683. {
  684. if (!isFirst)
  685. str += ",";
  686. str += control.path;
  687. isFirst = false;
  688. }
  689. str += "]";
  690. }
  691. return str;
  692. }
  693. /// <summary>
  694. /// Enable the action such that it actively listens for input and runs callbacks
  695. /// in response.
  696. /// </summary>
  697. /// <remarks>
  698. /// If the action is already enabled, this method does nothing.
  699. ///
  700. /// By default, actions start out disabled, i.e. with <see cref="enabled"/> being false.
  701. /// When enabled, two things happen.
  702. ///
  703. /// First, if it hasn't already happened, an action will resolve all of its bindings
  704. /// to <see cref="InputControl"/>s. This also happens if, since the action was last enabled,
  705. /// the setup of devices in the system has changed such that it may impact the action.
  706. ///
  707. /// Second, for all the <see cref="controls"/> bound to an action, change monitors (see
  708. /// <see cref="IInputStateChangeMonitor"/>) will be added to the system. If any of the
  709. /// controls changes state in the future, the action will get notified and respond.
  710. ///
  711. /// <see cref="InputActionType.Value"/> type actions will also perform an initial state
  712. /// check in the input system update following the call to Enable. This means that if
  713. /// any of the bound controls are already actuated and produce a non-<c>default</c> value,
  714. /// the action will immediately trigger in response.
  715. ///
  716. /// Note that this method only enables a single action. This is also allowed for action
  717. /// that are part of an <see cref="InputActionMap"/>. To enable all actions in a map,
  718. /// call <see cref="InputActionMap.Enable"/>.
  719. ///
  720. /// The <see cref="InputActionMap"/> associated with an action (if any), will immediately
  721. /// toggle to being enabled (see <see cref="InputActionMap.enabled"/>) as soon as the first
  722. /// action in the map is enabled and for as long as any action in the map is still enabled.
  723. ///
  724. /// The first time an action is enabled, it will allocate a block of state internally that it
  725. /// will hold on to until disposed of. For free-standing actions, that state is private to
  726. /// just the action. For actions that are part of <see cref="InputActionMap"/>s, the state
  727. /// is shared by all actions in the map and, if the map itself is part of an <see
  728. /// cref="InputActionAsset"/>, also by all the maps that are part of the asset.
  729. ///
  730. /// To dispose of the state, call <see cref="Dispose"/>.
  731. ///
  732. /// <example>
  733. /// <code>
  734. /// var gamepad = InputSystem.AddDevice&lt;Gamepad&gt;();
  735. ///
  736. /// var action = new InputAction(type: InputActionType.Value, binding: "&lt;Gamepad&gt;/leftTrigger");
  737. /// action.performed = ctx => Debug.Log("Action triggered!");
  738. ///
  739. /// // Perform some fake input on the gamepad. Note that the action
  740. /// // will *NOT* get triggered as it is not enabled.
  741. /// // NOTE: We use Update() here only for demonstration purposes. In most cases,
  742. /// // it's not a good method to call directly as it basically injects artificial
  743. /// // input frames into the player loop. Usually a recipe for breakage.
  744. /// InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.5f });
  745. /// InputSystem.Update();
  746. ///
  747. /// action.Enable();
  748. ///
  749. /// // Now, with the left trigger already being down and the action enabled, it will
  750. /// // trigger in the next frame.
  751. /// InputSystem.Update();
  752. /// </code>
  753. /// </example>
  754. /// </remarks>
  755. /// <seealso cref="Disable"/>
  756. /// <seealso cref="enabled"/>
  757. public void Enable()
  758. {
  759. if (enabled)
  760. return;
  761. // For singleton actions, we create an internal-only InputActionMap
  762. // private to the action.
  763. var map = GetOrCreateActionMap();
  764. // First time we're enabled, find all controls.
  765. map.ResolveBindingsIfNecessary();
  766. // Go live.
  767. map.m_State.EnableSingleAction(this);
  768. }
  769. /// <summary>
  770. /// Disable the action such that is stop listening/responding to input.
  771. /// </summary>
  772. /// <remarks>
  773. /// If the action is already disabled, this method does nothing.
  774. ///
  775. /// If the action is currently in progress, i.e. if <see cref="phase"/> is
  776. /// <see cref="InputActionPhase.Started"/>, the action will be canceled as
  777. /// part of being disabled. This means that you will see a call on <see cref="canceled"/>
  778. /// from within the call to <c>Disable()</c>.
  779. /// </remarks>
  780. /// <seealso cref="enabled"/>
  781. /// <seealso cref="Enable"/>
  782. public void Disable()
  783. {
  784. if (!enabled)
  785. return;
  786. m_ActionMap.m_State.DisableSingleAction(this);
  787. }
  788. ////REVIEW: is *not* cloning IDs here really the right thing to do?
  789. /// <summary>
  790. /// Return an identical instance of the action.
  791. /// </summary>
  792. /// <returns>An identical clone of the action</returns>
  793. /// <remarks>
  794. /// Note that if you clone an action that is part of an <see cref="InputActionMap"/>,
  795. /// you will not get a new action that is part of the same map. Instead, you will
  796. /// get a free-standing action not associated with any action map.
  797. ///
  798. /// Also, note that the <see cref="id"/> of the action is not cloned. Instead, the
  799. /// clone will receive a new unique ID. Also, callbacks install on events such
  800. /// as <see cref="started"/> will not be copied over to the clone.
  801. /// </remarks>
  802. public InputAction Clone()
  803. {
  804. var clone = new InputAction(name: m_Name, type: m_Type)
  805. {
  806. m_SingletonActionBindings = bindings.ToArray(),
  807. m_BindingsCount = m_BindingsCount,
  808. m_ExpectedControlType = m_ExpectedControlType,
  809. m_Interactions = m_Interactions,
  810. m_Processors = m_Processors,
  811. };
  812. return clone;
  813. }
  814. object ICloneable.Clone()
  815. {
  816. return Clone();
  817. }
  818. ////TODO: ReadValue(void*, int)
  819. /// <summary>
  820. /// Read the current value of the action. This is the last value received on <see cref="started"/>,
  821. /// or <see cref="performed"/>. If the action is in canceled or waiting phase, returns default(TValue).
  822. /// </summary>
  823. /// <typeparam name="TValue">Value type to read. Must match the value type of the binding/control that triggered.</typeparam>
  824. /// <returns>The current value of the action or <c>default(TValue)</c> if the action is not currently in-progress.</returns>
  825. /// <remarks>
  826. /// This method can be used as an alternative to hooking into <see cref="started"/>, <see cref="performed"/>,
  827. /// and/or <see cref="canceled"/> and reading out the value using <see cref="CallbackContext.ReadValue{TValue}"/>
  828. /// there. Instead, this API acts more like a polling API that can be called, for example, as part of
  829. /// <c>MonoBehaviour.Update</c>.
  830. ///
  831. /// <example>
  832. /// <code>
  833. /// // Let's say you have a MyControls.inputactions file with "Generate C# Class" enabled
  834. /// // and it has an action map called "gameplay" with a "move" action of type Vector2.
  835. /// public class MyBehavior : MonoBehaviour
  836. /// {
  837. /// public MyControls controls;
  838. /// public float moveSpeed = 4;
  839. ///
  840. /// protected void Awake()
  841. /// {
  842. /// controls = new MyControls();
  843. /// }
  844. ///
  845. /// protected void OnEnable()
  846. /// {
  847. /// controls.gameplay.Enable();
  848. /// }
  849. ///
  850. /// protected void OnDisable()
  851. /// {
  852. /// controls.gameplay.Disable();
  853. /// }
  854. ///
  855. /// protected void Update()
  856. /// {
  857. /// var moveVector = controls.gameplay.move.ReadValue&lt;Vector2&gt;() * (moveSpeed * Time.deltaTime);
  858. /// //...
  859. /// }
  860. /// }
  861. /// </code>
  862. /// </example>
  863. ///
  864. /// If the action has button-like behavior, then <see cref="triggered"/> is usually a better alternative to
  865. /// reading out a float and checking if it is above the button press point.
  866. /// </remarks>
  867. /// <exception cref="InvalidOperationException">The given <typeparamref name="TValue"/> type does not match
  868. /// the value type of the control or composite currently driving the action.</exception>
  869. /// <seealso cref="triggered"/>
  870. /// <seealso cref="ReadValueAsObject"/>
  871. /// <seealso cref="CallbackContext.ReadValue{TValue}"/>
  872. public unsafe TValue ReadValue<TValue>()
  873. where TValue : struct
  874. {
  875. var result = default(TValue);
  876. var state = GetOrCreateActionMap().m_State;
  877. if (state != null)
  878. {
  879. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  880. var controlIndex = actionStatePtr->controlIndex;
  881. if (controlIndex != InputActionState.kInvalidIndex)
  882. result = state.ReadValue<TValue>(actionStatePtr->bindingIndex, controlIndex);
  883. }
  884. return result;
  885. }
  886. /// <summary>
  887. /// Same as <see cref="ReadValue{TValue}"/> but read the value without having to know the value type
  888. /// of the action.
  889. /// </summary>
  890. /// <returns>The current value of the action or null if the action is not currently in <see cref="InputActionPhase.Started"/>
  891. /// or <see cref="InputActionPhase.Performed"/> phase.</returns>
  892. /// <remarks>
  893. /// This method allocates GC memory and is thus not a good choice for getting called as part of gameplay
  894. /// logic.
  895. /// </remarks>
  896. /// <seealso cref="ReadValue{TValue}"/>
  897. public unsafe object ReadValueAsObject()
  898. {
  899. var state = GetOrCreateActionMap().m_State;
  900. if (state == null)
  901. return null;
  902. var actionStatePtr = &state.actionStates[m_ActionIndexInState];
  903. var controlIndex = actionStatePtr->controlIndex;
  904. if (controlIndex != InputActionState.kInvalidIndex)
  905. return state.ReadValueAsObject(actionStatePtr->bindingIndex, controlIndex);
  906. return null;
  907. }
  908. ////REVIEW: it would be best if these were InternedStrings; however, for serialization, it has to be strings
  909. [Tooltip("Human readable name of the action. Must be unique within its action map (case is ignored). Can be changed "
  910. + "without breaking references to the action.")]
  911. [SerializeField] internal string m_Name;
  912. [SerializeField] internal InputActionType m_Type;
  913. [FormerlySerializedAs("m_ExpectedControlLayout")]
  914. [Tooltip("Type of control expected by the action (e.g. \"Button\" or \"Stick\"). This will limit the controls shown "
  915. + "when setting up bindings in the UI and will also limit which controls can be bound interactively to the action.")]
  916. [SerializeField] internal string m_ExpectedControlType;
  917. [Tooltip("Unique ID of the action (GUID). Used to reference the action from bindings such that actions can be renamed "
  918. + "without breaking references.")]
  919. [SerializeField] internal string m_Id; // Can't serialize System.Guid and Unity's GUID is editor only.
  920. [SerializeField] internal string m_Processors;
  921. [SerializeField] internal string m_Interactions;
  922. // For singleton actions, we serialize the bindings directly as part of the action.
  923. // For any other type of action, this is null.
  924. [SerializeField] internal InputBinding[] m_SingletonActionBindings;
  925. [NonSerialized] internal InputBinding? m_BindingMask;
  926. [NonSerialized] internal int m_BindingsStartIndex;
  927. [NonSerialized] internal int m_BindingsCount;
  928. [NonSerialized] internal int m_ControlStartIndex;
  929. [NonSerialized] internal int m_ControlCount;
  930. /// <summary>
  931. /// Index of the action in the <see cref="InputActionState"/> associated with the
  932. /// action's <see cref="InputActionMap"/>.
  933. /// </summary>
  934. /// <remarks>
  935. /// This is not necessarily the same as the index of the action in its map.
  936. /// </remarks>
  937. /// <seealso cref="actionMap"/>
  938. [NonSerialized] internal int m_ActionIndexInState = InputActionState.kInvalidIndex;
  939. /// <summary>
  940. /// The action map that owns the action.
  941. /// </summary>
  942. /// <remarks>
  943. /// This is not serialized. The action map will restore this back references after deserialization.
  944. /// </remarks>
  945. [NonSerialized] internal InputActionMap m_ActionMap;
  946. // Listeners. No array allocations if only a single listener.
  947. [NonSerialized] internal InlinedArray<Action<CallbackContext>> m_OnStarted;
  948. [NonSerialized] internal InlinedArray<Action<CallbackContext>> m_OnCanceled;
  949. [NonSerialized] internal InlinedArray<Action<CallbackContext>> m_OnPerformed;
  950. /// <summary>
  951. /// Whether the action is a loose action created in code (e.g. as a property on a component).
  952. /// </summary>
  953. /// <remarks>
  954. /// Singleton actions are not contained in maps visible to the user. Internally, we do create
  955. /// a map for them that contains just the singleton action. To the action system, there are no
  956. /// actions without action maps.
  957. /// </remarks>
  958. internal bool isSingletonAction => m_ActionMap == null || ReferenceEquals(m_ActionMap.m_SingletonAction, this);
  959. private InputActionState.TriggerState currentState
  960. {
  961. get
  962. {
  963. if (m_ActionIndexInState == InputActionState.kInvalidIndex)
  964. return new InputActionState.TriggerState();
  965. Debug.Assert(m_ActionMap != null);
  966. Debug.Assert(m_ActionMap.m_State != null);
  967. return m_ActionMap.m_State.FetchActionState(this);
  968. }
  969. }
  970. internal string MakeSureIdIsInPlace()
  971. {
  972. if (string.IsNullOrEmpty(m_Id))
  973. GenerateId();
  974. return m_Id;
  975. }
  976. internal void GenerateId()
  977. {
  978. m_Id = Guid.NewGuid().ToString();
  979. }
  980. internal InputActionMap GetOrCreateActionMap()
  981. {
  982. if (m_ActionMap == null)
  983. CreateInternalActionMapForSingletonAction();
  984. return m_ActionMap;
  985. }
  986. private void CreateInternalActionMapForSingletonAction()
  987. {
  988. m_ActionMap = new InputActionMap
  989. {
  990. m_Actions = new[] { this },
  991. m_SingletonAction = this,
  992. m_Bindings = m_SingletonActionBindings
  993. };
  994. }
  995. internal InputBinding? FindEffectiveBindingMask()
  996. {
  997. if (m_BindingMask.HasValue)
  998. return m_BindingMask;
  999. if (m_ActionMap?.m_BindingMask != null)
  1000. return m_ActionMap.m_BindingMask;
  1001. return m_ActionMap?.m_Asset?.m_BindingMask;
  1002. }
  1003. internal int BindingIndexOnActionToBindingIndexOnMap(int indexOfBindingOnAction)
  1004. {
  1005. // We don't want to hit InputAction.bindings here as this requires setting up per-action
  1006. // binding info which we then nuke as part of the override process. Calling ApplyBindingOverride
  1007. // repeatedly with an index would thus cause the same data to be computed and thrown away
  1008. // over and over.
  1009. // Instead we manually search through the map's bindings to find the right binding index
  1010. // in the map.
  1011. var actionMap = GetOrCreateActionMap();
  1012. var bindingsInMap = actionMap.m_Bindings;
  1013. var bindingCountInMap = bindingsInMap.LengthSafe();
  1014. var actionName = name;
  1015. var currentBindingIndexOnAction = -1;
  1016. for (var i = 0; i < bindingCountInMap; ++i)
  1017. {
  1018. ref var binding = ref bindingsInMap[i];
  1019. // Match both name and ID on binding.
  1020. if (string.Compare(binding.action, actionName, StringComparison.InvariantCultureIgnoreCase) != 0 &&
  1021. binding.action != m_Id)
  1022. continue;
  1023. ++currentBindingIndexOnAction;
  1024. if (currentBindingIndexOnAction == indexOfBindingOnAction)
  1025. return i;
  1026. }
  1027. throw new ArgumentOutOfRangeException(nameof(indexOfBindingOnAction),
  1028. $"Binding index {indexOfBindingOnAction} is out of range for action '{this}' with {currentBindingIndexOnAction + 1} bindings");
  1029. }
  1030. internal int BindingIndexOnMapToBindingIndexOnAction(int indexOfBindingOnMap)
  1031. {
  1032. var actionMap = GetOrCreateActionMap();
  1033. var bindingsInMap = actionMap.m_Bindings;
  1034. var actionName = name;
  1035. var bindingIndexOnAction = 0;
  1036. for (var i = indexOfBindingOnMap - 1; i >= 0; --i)
  1037. {
  1038. ref var binding = ref bindingsInMap[i];
  1039. if (string.Compare(binding.action, actionName, StringComparison.InvariantCultureIgnoreCase) == 0 ||
  1040. binding.action == m_Id)
  1041. ++bindingIndexOnAction;
  1042. }
  1043. return bindingIndexOnAction;
  1044. }
  1045. ////TODO: make current event available in some form
  1046. /// <summary>
  1047. /// Information provided to action callbacks about what triggered an action.
  1048. /// </summary>
  1049. /// <remarks>
  1050. /// This struct should not be held on to past the duration of the callback.
  1051. /// </remarks>
  1052. /// <seealso cref="performed"/>
  1053. /// <seealso cref="started"/>
  1054. /// <seealso cref="canceled"/>
  1055. /// <seealso cref="InputActionMap.actionTriggered"/>
  1056. public struct CallbackContext // Ideally would be a ref struct but couldn't use it in lambdas then.
  1057. {
  1058. internal InputActionState m_State;
  1059. internal int m_ActionIndex;
  1060. ////REVIEW: there should probably be a mechanism for the user to be able to correlate
  1061. //// the callback to a specific binding on the action
  1062. private int actionIndex => m_ActionIndex;
  1063. private unsafe int bindingIndex => m_State.actionStates[actionIndex].bindingIndex;
  1064. private unsafe int controlIndex => m_State.actionStates[actionIndex].controlIndex;
  1065. private unsafe int interactionIndex => m_State.actionStates[actionIndex].interactionIndex;
  1066. /// <summary>
  1067. /// Current phase of the action. Equivalent to accessing <see cref="InputAction.phase"/>
  1068. /// on <see cref="action"/>.
  1069. /// </summary>
  1070. /// <value>Current phase of the action.</value>
  1071. /// <seealso cref="started"/>
  1072. /// <seealso cref="performed"/>
  1073. /// <seealso cref="canceled"/>
  1074. /// <seealso cref="InputAction.phase"/>
  1075. public unsafe InputActionPhase phase
  1076. {
  1077. get
  1078. {
  1079. if (m_State == null)
  1080. return InputActionPhase.Disabled;
  1081. return m_State.actionStates[actionIndex].phase;
  1082. }
  1083. }
  1084. /// <summary>
  1085. /// Whether the <see cref="action"/> has just been started.
  1086. /// </summary>
  1087. /// <value>If true, the action was just started.</value>
  1088. /// <seealso cref="InputAction.started"/>
  1089. public bool started => phase == InputActionPhase.Started;
  1090. /// <summary>
  1091. /// Whether the <see cref="action"/> has just been performed.
  1092. /// </summary>
  1093. /// <value>If true, the action was just performed.</value>
  1094. /// <seealso cref="InputAction.performed"/>
  1095. public bool performed => phase == InputActionPhase.Performed;
  1096. /// <summary>
  1097. /// Whether the <see cref="action"/> has just been canceled.
  1098. /// </summary>
  1099. /// <value>If true, the action was just canceled.</value>
  1100. /// <seealso cref="InputAction.canceled"/>
  1101. public bool canceled => phase == InputActionPhase.Canceled;
  1102. /// <summary>
  1103. /// The action that got triggered.
  1104. /// </summary>
  1105. /// <value>Action that got triggered.</value>
  1106. public InputAction action => m_State?.GetActionOrNull(bindingIndex);
  1107. /// <summary>
  1108. /// The control that triggered the action.
  1109. /// </summary>
  1110. /// <value>Control that triggered the action.</value>
  1111. /// <remarks>
  1112. /// In case of a composite binding, this is the control of the composite that activated the
  1113. /// composite as a whole. For example, in case of a WASD-style binding, it could be the W key.
  1114. ///
  1115. /// Note that an action may also change its <see cref="phase"/> in response to a timeout.
  1116. /// For example, a <see cref="Interactions.TapInteraction"/> will cancel itself if the
  1117. /// button control is not released within a certain time. When this happens, the <c>control</c>
  1118. /// property will be the control that last fed input into the action.
  1119. /// </remarks>
  1120. /// <seealso cref="InputAction.controls"/>
  1121. /// <seealso cref="InputBinding.path"/>
  1122. public InputControl control => m_State?.controls[controlIndex];
  1123. /// <summary>
  1124. /// The interaction that triggered the action or <c>null</c> if the binding that triggered does not
  1125. /// have any particular interaction set on it.
  1126. /// </summary>
  1127. /// <value>Interaction that triggered the callback.</value>
  1128. /// <remarks>
  1129. /// <example>
  1130. /// <code>
  1131. /// void FirePerformed(InputAction.CallbackContext context)
  1132. /// {
  1133. /// // If SlowTap interaction was performed, perform a charged
  1134. /// // firing. Otherwise, fire normally.
  1135. /// if (context.interaction is SlowTapInteraction)
  1136. /// FireChargedProjectile();
  1137. /// else
  1138. /// FireNormalProjectile();
  1139. /// }
  1140. /// </code>
  1141. /// </example>
  1142. /// </remarks>
  1143. /// <seealso cref="InputBinding.interactions"/>
  1144. /// <seealso cref="InputAction.interactions"/>
  1145. public IInputInteraction interaction
  1146. {
  1147. get
  1148. {
  1149. if (m_State == null)
  1150. return null;
  1151. var index = interactionIndex;
  1152. if (index == InputActionState.kInvalidIndex)
  1153. return null;
  1154. return m_State.interactions[index];
  1155. }
  1156. }
  1157. /// <summary>
  1158. /// The time at which the action got triggered.
  1159. /// </summary>
  1160. /// <value>Time relative to <c>Time.realtimeSinceStartup</c> at which
  1161. /// the action got triggered.</value>
  1162. /// <remarks>
  1163. /// This is usually determined by the timestamp of the input event that activated a control
  1164. /// bound to the action. What this means is that this is normally <em>not</em> the
  1165. /// value of <c>Time.realtimeSinceStartup</c> when the input system calls the
  1166. /// callback but rather the time at which the input was generated that triggered
  1167. /// the action.
  1168. /// </remarks>
  1169. /// <seealso cref="InputEvent.time"/>
  1170. public unsafe double time
  1171. {
  1172. get
  1173. {
  1174. if (m_State == null)
  1175. return 0;
  1176. return m_State.actionStates[actionIndex].time;
  1177. }
  1178. }
  1179. /// <summary>
  1180. /// Time at which the action was started.
  1181. /// </summary>
  1182. /// <value>Value relative to <c>Time.realtimeSinceStartup</c> when the action
  1183. /// changed to <see cref="started"/>.</value>
  1184. /// <remarks>
  1185. /// This is only relevant for actions that go through distinct a <see cref="InputActionPhase.Started"/>
  1186. /// cycle as driven by <see cref="IInputInteraction">interactions</see>.
  1187. ///
  1188. /// The value of this property is that of <see cref="time"/> when <see
  1189. /// cref="InputAction.started"/> was called. See the <see cref="time"/>
  1190. /// property for how the timestamp works.
  1191. /// </remarks>
  1192. public unsafe double startTime
  1193. {
  1194. get
  1195. {
  1196. if (m_State == null)
  1197. return 0;
  1198. return m_State.actionStates[actionIndex].startTime;
  1199. }
  1200. }
  1201. /// <summary>
  1202. /// Time difference between <see cref="time"/> and <see cref="startTime"/>.
  1203. /// </summary>
  1204. /// <value>Difference between <see cref="time"/> and <see cref="startTime"/>.</value>
  1205. /// <remarks>
  1206. /// This property can be used, for example, to determine how long a button
  1207. /// was held down.
  1208. ///
  1209. /// <example>
  1210. /// <code>
  1211. /// // Let's create a button action bound to the A button
  1212. /// // on the gamepad.
  1213. /// var action = new InputAction(
  1214. /// type: InputActionType.Button,
  1215. /// binding: "&lt;Gamepad&gt;/buttonSouth");
  1216. ///
  1217. /// // When the action is performed (which will happen when the
  1218. /// // button is pressed and then released) we take the duration
  1219. /// // of the press to determine how many projectiles to spawn.
  1220. /// action.performed +=
  1221. /// context =>
  1222. /// {
  1223. /// const float kSpawnRate = 3; // 3 projectiles per second
  1224. /// var projectileCount = kSpawnRate * context.duration;
  1225. /// for (var i = 0; i &lt; projectileCount; ++i)
  1226. /// {
  1227. /// var projectile = UnityEngine.Object.Instantiate(projectile);
  1228. /// // Apply other changes to the projectile...
  1229. /// }
  1230. /// };
  1231. /// </code>
  1232. /// </example>
  1233. /// </remarks>
  1234. public double duration => time - startTime;
  1235. /// <summary>
  1236. /// Type of value returned by <see cref="ReadValueAsObject"/> and expected
  1237. /// by <see cref="ReadValue{TValue}"/>.
  1238. /// </summary>
  1239. /// <value>Type of object returned when reading a value.</value>
  1240. /// <remarks>
  1241. /// The type of value returned by an action is usually determined by the
  1242. /// <see cref="InputControl"/> that triggered the action, i.e. by the
  1243. /// control referenced from <see cref="control"/>.
  1244. ///
  1245. /// However, if the binding that triggered is a composite, then the composite
  1246. /// will determine values and not the individual control that triggered (that
  1247. /// one just feeds values into the composite).
  1248. /// </remarks>
  1249. /// <seealso cref="InputControl.valueType"/>
  1250. /// <seealso cref="InputBindingComposite.valueType"/>
  1251. public Type valueType => m_State?.GetValueType(bindingIndex, controlIndex);
  1252. /// <summary>
  1253. /// Size of values returned by <see cref="ReadValue(void*,int)"/>.
  1254. /// </summary>
  1255. /// <value>Size of value returned when reading.</value>
  1256. /// <remarks>
  1257. /// All input values passed around by the system are required to be "blittable",
  1258. /// i.e. they cannot contain references, cannot be heap objects themselves, and
  1259. /// must be trivially mem-copyable. This means that any value can be read out
  1260. /// and retained in a raw byte buffer.
  1261. ///
  1262. /// The value of this property determines how many bytes will be written
  1263. /// by <see cref="ReadValue(void*,int)"/>.
  1264. /// </remarks>
  1265. /// <seealso cref="InputControl.valueSizeInBytes"/>
  1266. /// <seealso cref="InputBindingComposite.valueSizeInBytes"/>
  1267. /// <seealso cref="ReadValue(void*,int)"/>
  1268. public int valueSizeInBytes
  1269. {
  1270. get
  1271. {
  1272. if (m_State == null)
  1273. return 0;
  1274. return m_State.GetValueSizeInBytes(bindingIndex, controlIndex);
  1275. }
  1276. }
  1277. ////TODO: need ability to read as button
  1278. /// <summary>
  1279. /// Read the value of the action as a raw byte buffer. This allows reading
  1280. /// values without having to know value types but also, unlike <see cref="ReadValueAsObject"/>,
  1281. /// without allocating GC heap memory.
  1282. /// </summary>
  1283. /// <param name="buffer">Memory buffer to read the value into.</param>
  1284. /// <param name="bufferSize">Size of buffer allocated at <paramref name="buffer"/>. Must be
  1285. /// at least <see cref="valueSizeInBytes"/>.</param>
  1286. /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is <c>null</c>.</exception>
  1287. /// <exception cref="ArgumentException"><paramref name="bufferSize"/> is too small.</exception>
  1288. /// <remarks>
  1289. /// <example>
  1290. /// <code>
  1291. /// // Read a Vector2 using the raw memory ReadValue API.
  1292. /// // Here we just read into a local variable which we could
  1293. /// // just as well (and more easily) do using ReadValue&lt;Vector2&gt;.
  1294. /// // Still, it serves as a demonstration for how the API
  1295. /// // operates in general.
  1296. /// unsafe
  1297. /// {
  1298. /// var value = default(Vector2);
  1299. /// var valuePtr = UnsafeUtility.AddressOf(ref value);
  1300. /// context.ReadValue(buffer, UnsafeUtility.SizeOf&lt;Vector2&gt;());
  1301. /// }
  1302. /// </code>
  1303. /// </example>
  1304. /// </remarks>
  1305. /// <seealso cref="InputControlExtensions.ReadValueIntoBuffer"/>
  1306. /// <seealso cref="InputAction.ReadValue{TValue}"/>
  1307. /// <seealso cref="ReadValue{TValue}"/>
  1308. public unsafe void ReadValue(void* buffer, int bufferSize)
  1309. {
  1310. if (buffer == null)
  1311. throw new ArgumentNullException(nameof(buffer));
  1312. m_State?.ReadValue(bindingIndex, controlIndex, buffer, bufferSize);
  1313. }
  1314. /// <summary>
  1315. /// Read the value of the action.
  1316. /// </summary>
  1317. /// <typeparam name="TValue">Type of value to read. This must correspond to the
  1318. /// expected by either <see cref="control"/> or, if it is a composite, by the
  1319. /// <see cref="InputBindingComposite"/> in use.</typeparam>
  1320. /// <returns>The value read from the action.</returns>
  1321. /// <exception cref="InvalidOperationException">The given type <typeparamref name="TValue"/>
  1322. /// does not match the value type expected by the control or binding composite.</exception>
  1323. /// <seealso cref="InputAction.ReadValue{TValue}"/>
  1324. /// <seealso cref="ReadValue(void*,int)"/>
  1325. /// <seealso cref="ReadValueAsObject"/>
  1326. public TValue ReadValue<TValue>()
  1327. where TValue : struct
  1328. {
  1329. var value = default(TValue);
  1330. if (m_State != null && phase != InputActionPhase.Canceled)
  1331. value = m_State.ReadValue<TValue>(bindingIndex, controlIndex);
  1332. return value;
  1333. }
  1334. /// <summary>
  1335. /// Read the current value of the action as a <c>float</c> and return true if it is equal to
  1336. /// or greater than the button press threshold.
  1337. /// </summary>
  1338. /// <returns>True if the action is considered in "pressed" state, false otherwise.</returns>
  1339. /// <remarks>
  1340. /// If the currently active control is a <see cref="ButtonControl"/>, the <see cref="ButtonControl.pressPoint"/>
  1341. /// of the button will be taken into account (if set). If there is no custom button press point, the
  1342. /// global <see cref="InputSettings.defaultButtonPressPoint"/> will be used.
  1343. /// </remarks>
  1344. /// <seealso cref="InputSettings.defaultButtonPressPoint"/>
  1345. /// <seealso cref="ButtonControl.pressPoint"/>
  1346. public bool ReadValueAsButton()
  1347. {
  1348. var value = false;
  1349. if (m_State != null && phase != InputActionPhase.Canceled)
  1350. value = m_State.ReadValueAsButton(bindingIndex, controlIndex);
  1351. return value;
  1352. }
  1353. /// <summary>
  1354. /// Same as <see cref="ReadValue{TValue}"/> except that it is not necessary to
  1355. /// know the type of value at compile time.
  1356. /// </summary>
  1357. /// <returns>The current value from the binding that triggered the action.</returns>
  1358. /// <remarks>
  1359. /// This method allocates GC heap memory. Using it during normal gameplay will lead
  1360. /// to frame-rate instabilities.
  1361. /// </remarks>
  1362. /// <seealso cref="ReadValue{TValue}"/>
  1363. public object ReadValueAsObject()
  1364. {
  1365. return m_State?.ReadValueAsObject(bindingIndex, controlIndex);
  1366. }
  1367. /// <summary>
  1368. /// Return a string representation of the context useful for debugging.
  1369. /// </summary>
  1370. /// <returns>String representation of the context.</returns>
  1371. public override string ToString()
  1372. {
  1373. return $"{{ action={action} phase={phase} time={time} control={control} value={ReadValueAsObject()} interaction={interaction} }}";
  1374. }
  1375. }
  1376. }
  1377. }