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