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 two additional modifiers. The button only triggers when /// both modifiers are pressed. /// /// /// 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". /// /// /// /// // 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") /// /// /// /// 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 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"); /// /// /// /// [DesignTimeVisible(false)] // Obsoleted by TwoModifiersComposite [DisplayStringFormat("{modifier1}+{modifier2}+{button}")] public class ButtonWithTwoModifiers : InputBindingComposite { /// /// Binding for the first 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 modifier1; /// /// Binding for the second 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 modifier2; /// /// Binding for the button that is gated by and . /// The composite will assume the value of this button while both of the modifiers are 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, and/or can be pressed after /// and the composite will still trigger. Default is false. /// /// /// By default, and are 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+Shift+B, the ctrl shift keys have 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 all of them to concurrently be in pressed state. /// public bool overrideModifiersNeedToBePressedFirst; /// /// Return the value of the part while both and /// are 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 (ModifiersArePressed(ref context)) return context.ReadValue(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; } /// /// 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 (!overrideModifiersNeedToBePressedFirst) overrideModifiersNeedToBePressedFirst = InputSystem.settings.IsFeatureEnabled(InputFeatureNames.kDisableShortcutSupport); } } }