using System; 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 { /// /// A button with an additional modifier. The button only triggers when /// the modifier is pressed. /// /// /// This composite can be used to require another button to be held while /// pressing the button that triggers the action. This is most commonly used /// on keyboards to require one of the modifier keys (shift, ctrl, or alt) /// to be held in combination with another key, e.g. "CTRL+1". /// /// /// /// // Create a button action that triggers when CTRL+1 /// // is pressed on the keyboard. /// var action = new InputAction(type: InputActionType.Button); /// action.AddCompositeBinding("ButtonWithOneModifier") /// .With("Modifier", "<Keyboard>/leftCtrl") /// .With("Modifier", "<Keyboard>/rightControl") /// .With("Button", "<Keyboard>/1") /// /// /// /// Note that this is not restricted to the keyboard and will preserve /// the full value of the button. /// /// /// /// // Create a button action that requires the A 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("ButtonWithOneModifier") /// .With("Modifier", "<Gamepad>/buttonSouth") /// .With("Button", "<Gamepad>/leftTrigger"); /// /// /// /// [DesignTimeVisible(false)] // Obsoleted by OneModifierComposite [DisplayStringFormat("{modifier}+{button}")] public class ButtonWithOneModifier : InputBindingComposite { /// /// Binding for the button that acts as a modifier, e.g. <Keyboard/leftCtrl. /// /// Part index to use with . /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global // ReSharper disable once UnassignedField.Global [InputControl(layout = "Button")] public int modifier; /// /// Binding for the button that is gated by the modifier. The composite will assume the value /// of this button while the modifier is pressed. /// /// Part index to use with . /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global // ReSharper disable once UnassignedField.Global [InputControl(layout = "Button")] public int button; /// /// If set to true, can be pressed after and the composite will /// still trigger. Default is false. /// /// /// By default, if the setting is enabled, /// is required to be in pressed state before or at the same time that /// goes into pressed state for the composite as a whole to trigger. This means that binding to, for example, Shift+B, /// the shift key has to be pressed before pressing the B key. This is the behavior usually expected with /// keyboard shortcuts. /// /// This parameter can be used to bypass this behavior and allow any timing between and . /// The only requirement is for them both to concurrently be in pressed state. /// /// To don't depends on the setting please consider using instead. /// [Tooltip("Obsolete please use modifiers Order. If enabled, this will override the Input Consumption setting, allowing the modifier keys to be pressed after the button and the composite will still trigger.")] [Obsolete("Use ModifiersOrder.Unordered with 'modifiersOrder' instead")] public bool overrideModifiersNeedToBePressedFirst; /// /// Determines how a modifiers keys need to be pressed in order or not. /// public enum ModifiersOrder { /// /// By default, if the setting is enabled, /// is required to be in pressed state before or at the same time that /// goes into pressed state for the composite as a whole to trigger. This means that binding to, for example, Shift+B, /// the shift key has to be pressed before pressing the B key. This is the behavior usually expected with /// keyboard shortcuts. /// /// If the setting is disabled, /// modifiers can be pressed after the button and the composite will still trigger. /// Default = 0, /// /// is required to be in pressed state before or at the same /// time that goes into pressed state for the composite as a whole to trigger. This means that binding to, /// for example, Ctrl+B, the ctrl key have to be pressed before pressing the B key. /// This is the behavior usually expected with keyboard shortcuts. /// Ordered = 1, /// /// can be pressed after /// and the composite will still trigger. The only requirement is for all of them to concurrently be in pressed state. /// Unordered = 2 } /// /// If set to Ordered or Unordered, the built-in logic to determine if modifiers need to be pressed first is overridden. /// /// /// By default, if the setting is enabled, /// is required to be in pressed state before or at the same time that /// goes into pressed state for the composite as a whole to trigger. This means that binding to, for example, Shift+B, /// the shift key has to be pressed before pressing the B key. This is the behavior usually expected with /// keyboard shortcuts. /// /// If the setting is disabled, /// modifiers can be pressed after the button and the composite will still trigger. /// /// This parameter can be used to bypass this behavior and enforce the timing order or allow any timing between and . /// The only requirement is for them both to concurrently be in pressed state. /// [Tooltip("By default it follows the Input Consumption setting to determine if the modifers keys need to be pressed first.")] public ModifiersOrder modifiersOrder = ModifiersOrder.Default; /// /// Return the value of the part if is pressed. Otherwise /// return 0. /// /// Evaluation context passed in from the input system. /// The current value of the composite. public override float ReadValue(ref InputBindingCompositeContext context) { if (ModifierIsPressed(ref context)) return context.ReadValue(button); return default; } private bool ModifierIsPressed(ref InputBindingCompositeContext context) { var modifierDown = context.ReadValueAsButton(modifier); if (modifierDown && modifiersOrder == ModifiersOrder.Ordered) { var timestamp = context.GetPressTime(button); var timestamp1 = context.GetPressTime(modifier); return timestamp1 <= timestamp; } return modifierDown; } /// /// Same as in this case. /// /// Evaluation context passed in from the input system. /// A >0 value if the composite is currently actuated. public override float EvaluateMagnitude(ref InputBindingCompositeContext context) { return ReadValue(ref context); } protected override void FinishSetup(ref InputBindingCompositeContext context) { if (modifiersOrder == ModifiersOrder.Default) { // Legacy. We need to reference the obsolete member here so temporarily // turn off the warning. #pragma warning disable CS0618 if (overrideModifiersNeedToBePressedFirst) #pragma warning restore CS0618 modifiersOrder = ModifiersOrder.Unordered; else modifiersOrder = InputSystem.settings.shortcutKeysConsumeInput ? ModifiersOrder.Ordered : ModifiersOrder.Unordered; } } } }