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 an additional modifier. The button only triggers when
12 /// the modifier is pressed.
13 /// </summary>
14 /// <remarks>
15 /// This composite can be used to require another button to be held while
16 /// pressing the button that triggers the action. This is most commonly used
17 /// on keyboards to require one of the modifier keys (shift, ctrl, or alt)
18 /// to be held in combination with another key, e.g. "CTRL+1".
19 ///
20 /// <example>
21 /// <code>
22 /// // Create a button action that triggers when CTRL+1
23 /// // is pressed on the keyboard.
24 /// var action = new InputAction(type: InputActionType.Button);
25 /// action.AddCompositeBinding("ButtonWithOneModifier")
26 /// .With("Modifier", "<Keyboard>/leftCtrl")
27 /// .With("Modifier", "<Keyboard>/rightControl")
28 /// .With("Button", "<Keyboard>/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 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("ButtonWithOneModifier")
42 /// .With("Modifier", "<Gamepad>/buttonSouth")
43 /// .With("Button", "<Gamepad>/leftTrigger");
44 /// </code>
45 /// </example>
46 /// </remarks>
47 /// <seealso cref="ButtonWithTwoModifiers"/>
48 [DesignTimeVisible(false)] // Obsoleted by OneModifierComposite
49 [DisplayStringFormat("{modifier}+{button}")]
50 public class ButtonWithOneModifier : InputBindingComposite<float>
51 {
52 /// <summary>
53 /// Binding for the button that acts as a modifier, e.g. <c><Keyboard/leftCtrl</c>.
54 /// </summary>
55 /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
56 /// <remarks>
57 /// This property is automatically assigned by the input system.
58 /// </remarks>
59 // ReSharper disable once MemberCanBePrivate.Global
60 // ReSharper disable once FieldCanBeMadeReadOnly.Global
61 // ReSharper disable once UnassignedField.Global
62 [InputControl(layout = "Button")] public int modifier;
63
64 /// <summary>
65 /// Binding for the button that is gated by the modifier. The composite will assume the value
66 /// of this button while the modifier is pressed.
67 /// </summary>
68 /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
69 /// <remarks>
70 /// This property is automatically assigned by the input system.
71 /// </remarks>
72 // ReSharper disable once MemberCanBePrivate.Global
73 // ReSharper disable once FieldCanBeMadeReadOnly.Global
74 // ReSharper disable once UnassignedField.Global
75 [InputControl(layout = "Button")] public int button;
76
77 /// <summary>
78 /// If set to <c>true</c>, <see cref="modifier"/> can be pressed after <see cref="button"/> and the composite will
79 /// still trigger. Default is false.
80 /// </summary>
81 /// <remarks>
82 /// By default, <see cref="modifier"/> is required to be in pressed state before or at the same time that <see cref="button"/>
83 /// goes into pressed state for the composite as a whole to trigger. This means that binding to, for example, <c>Shift+B</c>,
84 /// the <c>shift</c> key has to be pressed before pressing the <c>B</c> key. This is the behavior usually expected with
85 /// keyboard shortcuts.
86 ///
87 /// This parameter can be used to bypass this behavior and allow any timing between <see cref="modifier"/> and <see cref="button"/>.
88 /// The only requirement is for them both to concurrently be in pressed state.
89 /// </remarks>
90 public bool overrideModifiersNeedToBePressedFirst;
91
92 /// <summary>
93 /// Return the value of the <see cref="button"/> part if <see cref="modifier"/> is pressed. Otherwise
94 /// return 0.
95 /// </summary>
96 /// <param name="context">Evaluation context passed in from the input system.</param>
97 /// <returns>The current value of the composite.</returns>
98 public override float ReadValue(ref InputBindingCompositeContext context)
99 {
100 if (ModifierIsPressed(ref context))
101 return context.ReadValue<float>(button);
102
103 return default;
104 }
105
106 private bool ModifierIsPressed(ref InputBindingCompositeContext context)
107 {
108 var modifierDown = context.ReadValueAsButton(modifier);
109
110 if (modifierDown && !overrideModifiersNeedToBePressedFirst)
111 {
112 var timestamp = context.GetPressTime(button);
113 var timestamp1 = context.GetPressTime(modifier);
114
115 return timestamp1 <= timestamp;
116 }
117
118 return modifierDown;
119 }
120
121 /// <summary>
122 /// Same as <see cref="ReadValue"/> in this case.
123 /// </summary>
124 /// <param name="context">Evaluation context passed in from the input system.</param>
125 /// <returns>A >0 value if the composite is currently actuated.</returns>
126 public override float EvaluateMagnitude(ref InputBindingCompositeContext context)
127 {
128 return ReadValue(ref context);
129 }
130
131 protected override void FinishSetup(ref InputBindingCompositeContext context)
132 {
133 if (!overrideModifiersNeedToBePressedFirst)
134 overrideModifiersNeedToBePressedFirst = !InputSystem.settings.shortcutKeysConsumeInput;
135 }
136 }
137}