暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ButtonWithTwoModifiers.cs 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using System.ComponentModel;
  2. using UnityEngine.InputSystem.Layouts;
  3. using UnityEngine.InputSystem.Utilities;
  4. using UnityEngine.Scripting;
  5. ////TODO: remove this once we can break the API
  6. namespace UnityEngine.InputSystem.Composites
  7. {
  8. /// <summary>
  9. /// A button with two additional modifiers. The button only triggers when
  10. /// both modifiers are pressed.
  11. /// </summary>
  12. /// <remarks>
  13. /// This composite can be used to require two other buttons to be held while
  14. /// using the control that triggers the action. This is most commonly used
  15. /// on keyboards to require two of the modifier keys (shift, ctrl, or alt)
  16. /// to be held in combination with another key, e.g. "CTRL+SHIFT+1".
  17. ///
  18. /// <example>
  19. /// <code>
  20. /// // Create a button action that triggers when CTRL+SHIFT+1
  21. /// // is pressed on the keyboard.
  22. /// var action = new InputAction(type: InputActionType.Button);
  23. /// action.AddCompositeBinding("TwoModifiers")
  24. /// .With("Modifier1", "&lt;Keyboard&gt;/leftCtrl")
  25. /// .With("Modifier1", "&lt;Keyboard&gt;/rightCtrl")
  26. /// .With("Modifier2", "&lt;Keyboard&gt;/leftShift")
  27. /// .With("Modifier2", "&lt;Keyboard&gt;/rightShift")
  28. /// .With("Button", "&lt;Keyboard&gt;/1")
  29. /// </code>
  30. /// </example>
  31. ///
  32. /// Note that this is not restricted to the keyboard and will preserve
  33. /// the full value of the button.
  34. ///
  35. /// <example>
  36. /// <code>
  37. /// // Create a button action that requires the A and X button on the
  38. /// // gamepad to be held and will then trigger from the gamepad's
  39. /// // left trigger button.
  40. /// var action = new InputAction(type: InputActionType.Button);
  41. /// action.AddCompositeBinding("ButtonWithTwoModifiers")
  42. /// .With("Modifier1", "&lt;Gamepad&gt;/buttonSouth")
  43. /// .With("Modifier2", "&lt;Gamepad&gt;/buttonWest")
  44. /// .With("Button", "&lt;Gamepad&gt;/leftTrigger");
  45. /// </code>
  46. /// </example>
  47. /// </remarks>
  48. /// <seealso cref="ButtonWithOneModifier"/>
  49. [DesignTimeVisible(false)] // Obsoleted by TwoModifiersComposite
  50. [DisplayStringFormat("{modifier1}+{modifier2}+{button}")]
  51. public class ButtonWithTwoModifiers : InputBindingComposite<float>
  52. {
  53. /// <summary>
  54. /// Binding for the first button that acts as a modifier, e.g. <c>&lt;Keyboard/leftCtrl</c>.
  55. /// </summary>
  56. /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
  57. /// <remarks>
  58. /// This property is automatically assigned by the input system.
  59. /// </remarks>
  60. // ReSharper disable once MemberCanBePrivate.Global
  61. // ReSharper disable once FieldCanBeMadeReadOnly.Global
  62. // ReSharper disable once UnassignedField.Global
  63. [InputControl(layout = "Button")] public int modifier1;
  64. /// <summary>
  65. /// Binding for the second button that acts as a modifier, e.g. <c>&lt;Keyboard/leftCtrl</c>.
  66. /// </summary>
  67. /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
  68. /// <remarks>
  69. /// This property is automatically assigned by the input system.
  70. /// </remarks>
  71. // ReSharper disable once MemberCanBePrivate.Global
  72. // ReSharper disable once FieldCanBeMadeReadOnly.Global
  73. // ReSharper disable once UnassignedField.Global
  74. [InputControl(layout = "Button")] public int modifier2;
  75. /// <summary>
  76. /// Binding for the button that is gated by <see cref="modifier1"/> and <see cref="modifier2"/>.
  77. /// The composite will assume the value of this button while both of the modifiers are pressed.
  78. /// </summary>
  79. /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
  80. /// <remarks>
  81. /// This property is automatically assigned by the input system.
  82. /// </remarks>
  83. // ReSharper disable once MemberCanBePrivate.Global
  84. // ReSharper disable once FieldCanBeMadeReadOnly.Global
  85. // ReSharper disable once UnassignedField.Global
  86. [InputControl(layout = "Button")] public int button;
  87. /// <summary>
  88. /// If set to <c>true</c>, <see cref="modifier1"/> and/or <see cref="modifier2"/> can be pressed after <see cref="button"/>
  89. /// and the composite will still trigger. Default is false.
  90. /// </summary>
  91. /// <remarks>
  92. /// By default, <see cref="modifier1"/> and <see cref="modifier2"/> are required to be in pressed state before or at the same
  93. /// time that <see cref="button"/> goes into pressed state for the composite as a whole to trigger. This means that binding to,
  94. /// for example, <c>Ctrl+Shift+B</c>, the <c>ctrl</c> <c>shift</c> keys have to be pressed before pressing the <c>B</c> key.
  95. /// This is the behavior usually expected with keyboard shortcuts.
  96. ///
  97. /// This parameter can be used to bypass this behavior and allow any timing between <see cref="modifier1"/>, <see cref="modifier2"/>,
  98. /// and <see cref="button"/>. The only requirement is for all of them to concurrently be in pressed state.
  99. /// </remarks>
  100. public bool overrideModifiersNeedToBePressedFirst;
  101. /// <summary>
  102. /// Return the value of the <see cref="button"/> part while both <see cref="modifier1"/> and <see cref="modifier2"/>
  103. /// are pressed. Otherwise return 0.
  104. /// </summary>
  105. /// <param name="context">Evaluation context passed in from the input system.</param>
  106. /// <returns>The current value of the composite.</returns>
  107. public override float ReadValue(ref InputBindingCompositeContext context)
  108. {
  109. if (ModifiersArePressed(ref context))
  110. return context.ReadValue<float>(button);
  111. return default;
  112. }
  113. private bool ModifiersArePressed(ref InputBindingCompositeContext context)
  114. {
  115. var modifiersDown = context.ReadValueAsButton(modifier1) && context.ReadValueAsButton(modifier2);
  116. if (modifiersDown && !overrideModifiersNeedToBePressedFirst)
  117. {
  118. var timestamp = context.GetPressTime(button);
  119. var timestamp1 = context.GetPressTime(modifier1);
  120. var timestamp2 = context.GetPressTime(modifier2);
  121. return timestamp1 <= timestamp && timestamp2 <= timestamp;
  122. }
  123. return modifiersDown;
  124. }
  125. /// <summary>
  126. /// Same as <see cref="ReadValue"/> in this case.
  127. /// </summary>
  128. /// <param name="context">Evaluation context passed in from the input system.</param>
  129. /// <returns>A >0 value if the composite is currently actuated.</returns>
  130. public override float EvaluateMagnitude(ref InputBindingCompositeContext context)
  131. {
  132. return ReadValue(ref context);
  133. }
  134. protected override void FinishSetup(ref InputBindingCompositeContext context)
  135. {
  136. if (!overrideModifiersNeedToBePressedFirst)
  137. overrideModifiersNeedToBePressedFirst = !InputSystem.settings.shortcutKeysConsumeInput;
  138. }
  139. }
  140. }