123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- using System.ComponentModel;
- using UnityEngine.InputSystem.Layouts;
- using UnityEngine.InputSystem.Utilities;
- using UnityEngine.Scripting;
-
- ////TODO: remove this once we can break the API
-
- namespace UnityEngine.InputSystem.Composites
- {
- /// <summary>
- /// A button with two additional modifiers. The button only triggers when
- /// both modifiers are pressed.
- /// </summary>
- /// <remarks>
- /// This composite can be used to require two other buttons to be held while
- /// using the control that triggers the action. This is most commonly used
- /// on keyboards to require two of the modifier keys (shift, ctrl, or alt)
- /// to be held in combination with another key, e.g. "CTRL+SHIFT+1".
- ///
- /// <example>
- /// <code>
- /// // Create a button action that triggers when CTRL+SHIFT+1
- /// // is pressed on the keyboard.
- /// var action = new InputAction(type: InputActionType.Button);
- /// action.AddCompositeBinding("TwoModifiers")
- /// .With("Modifier1", "<Keyboard>/leftCtrl")
- /// .With("Modifier1", "<Keyboard>/rightCtrl")
- /// .With("Modifier2", "<Keyboard>/leftShift")
- /// .With("Modifier2", "<Keyboard>/rightShift")
- /// .With("Button", "<Keyboard>/1")
- /// </code>
- /// </example>
- ///
- /// Note that this is not restricted to the keyboard and will preserve
- /// the full value of the button.
- ///
- /// <example>
- /// <code>
- /// // Create a button action that requires the A and X button on the
- /// // gamepad to be held and will then trigger from the gamepad's
- /// // left trigger button.
- /// var action = new InputAction(type: InputActionType.Button);
- /// action.AddCompositeBinding("ButtonWithTwoModifiers")
- /// .With("Modifier1", "<Gamepad>/buttonSouth")
- /// .With("Modifier2", "<Gamepad>/buttonWest")
- /// .With("Button", "<Gamepad>/leftTrigger");
- /// </code>
- /// </example>
- /// </remarks>
- /// <seealso cref="ButtonWithOneModifier"/>
- [DesignTimeVisible(false)] // Obsoleted by TwoModifiersComposite
- [DisplayStringFormat("{modifier1}+{modifier2}+{button}")]
- public class ButtonWithTwoModifiers : InputBindingComposite<float>
- {
- /// <summary>
- /// Binding for the first button that acts as a modifier, e.g. <c><Keyboard/leftCtrl</c>.
- /// </summary>
- /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
- /// <remarks>
- /// This property is automatically assigned by the input system.
- /// </remarks>
- // ReSharper disable once MemberCanBePrivate.Global
- // ReSharper disable once FieldCanBeMadeReadOnly.Global
- // ReSharper disable once UnassignedField.Global
- [InputControl(layout = "Button")] public int modifier1;
-
- /// <summary>
- /// Binding for the second button that acts as a modifier, e.g. <c><Keyboard/leftCtrl</c>.
- /// </summary>
- /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
- /// <remarks>
- /// This property is automatically assigned by the input system.
- /// </remarks>
- // ReSharper disable once MemberCanBePrivate.Global
- // ReSharper disable once FieldCanBeMadeReadOnly.Global
- // ReSharper disable once UnassignedField.Global
- [InputControl(layout = "Button")] public int modifier2;
-
- /// <summary>
- /// Binding for the button that is gated by <see cref="modifier1"/> and <see cref="modifier2"/>.
- /// The composite will assume the value of this button while both of the modifiers are pressed.
- /// </summary>
- /// <value>Part index to use with <see cref="InputBindingCompositeContext.ReadValue{T}(int)"/>.</value>
- /// <remarks>
- /// This property is automatically assigned by the input system.
- /// </remarks>
- // ReSharper disable once MemberCanBePrivate.Global
- // ReSharper disable once FieldCanBeMadeReadOnly.Global
- // ReSharper disable once UnassignedField.Global
- [InputControl(layout = "Button")] public int button;
-
- /// <summary>
- /// If set to <c>true</c>, <see cref="modifier1"/> and/or <see cref="modifier2"/> can be pressed after <see cref="button"/>
- /// and the composite will still trigger. Default is false.
- /// </summary>
- /// <remarks>
- /// By default, <see cref="modifier1"/> and <see cref="modifier2"/> are required to be in pressed state before or at the same
- /// time that <see cref="button"/> goes into pressed state for the composite as a whole to trigger. This means that binding to,
- /// 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.
- /// This is the behavior usually expected with keyboard shortcuts.
- ///
- /// This parameter can be used to bypass this behavior and allow any timing between <see cref="modifier1"/>, <see cref="modifier2"/>,
- /// and <see cref="button"/>. The only requirement is for all of them to concurrently be in pressed state.
- /// </remarks>
- public bool overrideModifiersNeedToBePressedFirst;
-
- /// <summary>
- /// Return the value of the <see cref="button"/> part while both <see cref="modifier1"/> and <see cref="modifier2"/>
- /// are pressed. Otherwise return 0.
- /// </summary>
- /// <param name="context">Evaluation context passed in from the input system.</param>
- /// <returns>The current value of the composite.</returns>
- public override float ReadValue(ref InputBindingCompositeContext context)
- {
- if (ModifiersArePressed(ref context))
- return context.ReadValue<float>(button);
-
- return default;
- }
-
- private bool ModifiersArePressed(ref InputBindingCompositeContext context)
- {
- var modifiersDown = context.ReadValueAsButton(modifier1) && context.ReadValueAsButton(modifier2);
-
- if (modifiersDown && !overrideModifiersNeedToBePressedFirst)
- {
- var timestamp = context.GetPressTime(button);
- var timestamp1 = context.GetPressTime(modifier1);
- var timestamp2 = context.GetPressTime(modifier2);
-
- return timestamp1 <= timestamp && timestamp2 <= timestamp;
- }
-
- return modifiersDown;
- }
-
- /// <summary>
- /// Same as <see cref="ReadValue"/> in this case.
- /// </summary>
- /// <param name="context">Evaluation context passed in from the input system.</param>
- /// <returns>A >0 value if the composite is currently actuated.</returns>
- public override float EvaluateMagnitude(ref InputBindingCompositeContext context)
- {
- return ReadValue(ref context);
- }
-
- protected override void FinishSetup(ref InputBindingCompositeContext context)
- {
- if (!overrideModifiersNeedToBePressedFirst)
- overrideModifiersNeedToBePressedFirst = !InputSystem.settings.shortcutKeysConsumeInput;
- }
- }
- }
|