diff --git a/Assets/Tests/InputSystem/ActuationPressPointTests.cs b/Assets/Tests/InputSystem/ActuationPressPointTests.cs new file mode 100644 index 0000000000..4a0fa7c351 --- /dev/null +++ b/Assets/Tests/InputSystem/ActuationPressPointTests.cs @@ -0,0 +1,358 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.LowLevel; + +// Covers IActuationPressPoint, defaultButtonPressPoint, InputAction.IsPressed, and InputControl.IsPressed(). +[TestFixture] +[Category("ActuationPressPoint")] +internal class ActuationPressPointTests : CoreTestsFixture +{ + #region InputAction.IsPressed (Vector2 + Press interaction / control pressPoint) + + [Test] + [Category("Actions")] + public void Actions_Vector2IsPressed_UsesPressInteractionPressPoint() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + InputSystem.settings.buttonReleaseThreshold = 0.8f; + + var gamepad = InputSystem.AddDevice(); + + Set(gamepad.leftStick, Vector2.zero); + InputSystem.Update(); + + var action = new InputAction( + type: InputActionType.Value, + expectedControlType: "Vector2", + binding: "/leftStick", + interactions: "press(pressPoint=0.6)"); + action.Enable(); + + Set(gamepad.leftStick, new Vector2(0.55f, 0f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.False); + + Set(gamepad.leftStick, new Vector2(0f, 0.65f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.True); + } + + [Test] + [Category("Actions")] + public void Actions_Vector2IsPressed_UsesVector2ControlPressPoint() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + InputSystem.settings.buttonReleaseThreshold = 0.8f; + + var gamepad = InputSystem.AddDevice(); + + Set(gamepad.leftStick, Vector2.zero); + InputSystem.Update(); + + var action = new InputAction( + type: InputActionType.Value, + expectedControlType: "Vector2", + binding: "/leftStick"); + gamepad.leftStick.pressPoint = 0.7f; + action.Enable(); + + Set(gamepad.leftStick, new Vector2(0.65f, 0f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.False); + + Set(gamepad.leftStick, new Vector2(0.75f, 0f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.True); + + gamepad.leftStick.pressPoint = -1f; + } + + [Test] + [Category("Actions")] + public void Actions_ButtonIsPressed_UsesPressInteractionWhenControlPressPointUnset() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + InputSystem.settings.buttonReleaseThreshold = 0.8f; + + var gamepad = InputSystem.AddDevice(); + + var action = new InputAction( + type: InputActionType.Button, + binding: "/leftTrigger", + interactions: "press(pressPoint=0.6)"); + action.Enable(); + + Set(gamepad.leftTrigger, 0.55f); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.False); + + Set(gamepad.leftTrigger, 0.65f); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.True); + } + + [Test] + [Category("Actions")] + public void Actions_Vector2IsPressed_ControlPressPointOverridesPressInteraction() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + InputSystem.settings.buttonReleaseThreshold = 0.8f; + + var gamepad = InputSystem.AddDevice(); + + Set(gamepad.leftStick, Vector2.zero); + InputSystem.Update(); + + var action = new InputAction( + type: InputActionType.Value, + expectedControlType: "Vector2", + binding: "/leftStick", + interactions: "press(pressPoint=0.6)"); + gamepad.leftStick.pressPoint = 0.85f; + action.Enable(); + + // Above interaction threshold (0.6) but below control threshold (0.85). + Set(gamepad.leftStick, new Vector2(0.7f, 0f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.False); + + Set(gamepad.leftStick, new Vector2(0.9f, 0f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.True); + + gamepad.leftStick.pressPoint = -1f; + } + + [Test] + [Category("Actions")] + public void Actions_CompositeVector2IsPressed_UsesPressInteractionOnCompositeBinding() + { + // Interaction lives on the composite binding while state changes arrive on part bindings. + // Analog 2DVector + stick half-axes yields composite magnitudes between 0 and 1 so we can + // distinguish defaultButtonPressPoint (0.5) from press(pressPoint=0.6). + InputSystem.settings.defaultButtonPressPoint = 0.5f; + InputSystem.settings.buttonReleaseThreshold = 0.8f; + InputSystem.settings.defaultDeadzoneMin = 0; + InputSystem.settings.defaultDeadzoneMax = 1; + + var gamepad = InputSystem.AddDevice(); + + Set(gamepad.leftStick, Vector2.zero); + InputSystem.Update(); + + var action = new InputAction(type: InputActionType.Value, expectedControlType: "Vector2"); + action.AddCompositeBinding("2DVector(mode=2)", interactions: "press(pressPoint=0.6)") + .With("Up", "/leftStick/up") + .With("Down", "/leftStick/down") + .With("Left", "/leftStick/left") + .With("Right", "/leftStick/right"); + action.Enable(); + + Set(gamepad.leftStick, new Vector2(0f, 0.55f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.False); + + Set(gamepad.leftStick, new Vector2(0f, 0.65f)); + InputSystem.Update(); + Assert.That(action.IsPressed(), Is.True); + } + + [Test] + [Category("Actions")] + public void Actions_Vector2Composite_RespectsButtonPressurePoint() + { + // The stick has deadzones on the up/down/left/right buttons to get rid of stick + // noise. For this test, simplify things by getting rid of deadzones. + InputSystem.settings.defaultDeadzoneMin = 0; + InputSystem.settings.defaultDeadzoneMax = 1; + + var gamepad = InputSystem.AddDevice(); + + // Set up classic WASD control. + var action = new InputAction(); + action.AddCompositeBinding("Dpad") + .With("Up", "/leftstick/up") + .With("Down", "/leftstick/down") + .With("Left", "/leftstick/left") + .With("Right", "/leftstick/right"); + action.Enable(); + + Vector2? value = null; + action.performed += ctx => { value = ctx.ReadValue(); }; + action.canceled += ctx => { value = ctx.ReadValue(); }; + + var pressPoint = gamepad.leftStick.up.pressPointOrDefault; + + // Up. + value = null; + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up }); + InputSystem.Update(); + + Assert.That(value, Is.Not.Null); + Assert.That(value.Value, Is.EqualTo(Vector2.up)); + + // Up (slightly above press point) + value = null; + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up * pressPoint * 1.01f }); + InputSystem.Update(); + + Assert.That(value, Is.Not.Null); + Assert.That(value.Value, Is.EqualTo(Vector2.up)); + + // Up (slightly below press point) + value = null; + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up * pressPoint * 0.99f }); + InputSystem.Update(); + + Assert.That(value, Is.Not.Null); + Assert.That(value.Value, Is.EqualTo(Vector2.zero)); + + // Up left. + value = null; + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up + Vector2.left }); + InputSystem.Update(); + + Assert.That(value, Is.Not.Null); + Assert.That(value.Value.x, Is.EqualTo((Vector2.up + Vector2.left).normalized.x).Within(0.00001)); + Assert.That(value.Value.y, Is.EqualTo((Vector2.up + Vector2.left).normalized.y).Within(0.00001)); + + // Up left (up slightly above press point) + value = null; + InputSystem.QueueStateEvent(gamepad, + new GamepadState { leftStick = Vector2.up * pressPoint * 1.01f + Vector2.left }); + InputSystem.Update(); + + Assert.That(value, Is.Not.Null); + Assert.That(value.Value.x, Is.EqualTo((Vector2.up + Vector2.left).normalized.x).Within(0.00001)); + Assert.That(value.Value.y, Is.EqualTo((Vector2.up + Vector2.left).normalized.y).Within(0.00001)); + + // Up left (up slightly below press point) + value = null; + InputSystem.QueueStateEvent(gamepad, + new GamepadState { leftStick = Vector2.up * pressPoint * 0.99f + Vector2.left }); + InputSystem.Update(); + + Assert.That(value, Is.Not.Null); + Assert.That(value.Value, Is.EqualTo(Vector2.left)); + } + + #endregion + + #region Control extension IsPressed + settings (IActuationPressPoint / default threshold) + + [Test] + [Category("Controls")] + public void Controls_CanDetermineIfControlIsPressed() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + + var gamepad = InputSystem.AddDevice(); + + Set(gamepad.leftStick, Vector2.one); + Set(gamepad.leftTrigger, 0.6f); + Press(gamepad.buttonSouth); + + Assert.That(gamepad.leftTrigger.IsPressed(), Is.True); + Assert.That(gamepad.rightTrigger.IsPressed(), Is.False); + Assert.That(gamepad.buttonSouth.IsPressed(), Is.True); + Assert.That(gamepad.buttonNorth.IsPressed(), Is.False); + Assert.That(gamepad.leftStick.IsPressed(), + Is.True); // Note how this diverges from the actual meaning of "is the left stick pressed?" + Assert.That(gamepad.rightStick.IsPressed(), Is.False); + + // https://fogbugz.unity3d.com/f/cases/1374024/ + // Calling it on the entire device should be false. + Assert.That(gamepad.IsPressed(), Is.False); + } + + [Test] + [Category("Controls")] + public void Controls_CanCustomizeDefaultButtonPressPoint() + { + var gamepad = InputSystem.AddDevice(); + + InputSystem.settings.defaultButtonPressPoint = 0.4f; + + Set(gamepad.leftTrigger, 0.39f); + + Assert.That(gamepad.leftTrigger.isPressed, Is.False); + + Set(gamepad.leftTrigger, 0.4f); + + Assert.That(gamepad.leftTrigger.isPressed, Is.True); + + InputSystem.settings.defaultButtonPressPoint = 0.5f; + + Assert.That(gamepad.leftTrigger.isPressed, Is.False); + + InputSystem.settings.defaultButtonPressPoint = 0; + + Assert.That(gamepad.leftTrigger.isPressed, Is.True); + + // Setting the trigger to 0 requires the system to be "smart" enough to + // figure out that 0 as a default button press point doesn't make sense + // and that instead the press point should clamp off at some low, non-zero value. + // https://fogbugz.unity3d.com/f/cases/1349002/ + Set(gamepad.leftTrigger, 0f); + + Assert.That(gamepad.leftTrigger.isPressed, Is.False); + + Set(gamepad.leftTrigger, 0.001f); + + Assert.That(gamepad.leftTrigger.isPressed, Is.True); + + InputSystem.settings.defaultButtonPressPoint = -1; + Set(gamepad.leftTrigger, 0f); + + Assert.That(gamepad.leftTrigger.isPressed, Is.False); + } + + [Test] + [Category("Controls")] + public void Controls_CanCustomizePressPointOfGamepadTriggers() + { + var json = @" + { + ""name"" : ""CustomGamepad"", + ""extend"" : ""Gamepad"", + ""controls"" : [ + { + ""name"" : ""rightTrigger"", + ""parameters"" : ""pressPoint=0.2"" + } + ] + } + "; + + InputSystem.RegisterLayout(json); + var gamepad = InputDevice.Build("CustomGamepad"); + + Assert.That(gamepad.rightTrigger.pressPoint, Is.EqualTo(0.2f).Within(0.0001f)); + } + + [Test] + [Category("Controls")] + public void Controls_Vector2ExtensionIsPressed_UsesPressPointOrDefault() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + + var gamepad = InputSystem.AddDevice(); + + gamepad.leftStick.pressPoint = 0.75f; + Set(gamepad.leftStick, new Vector2(0.6f, 0f)); + Assert.That(gamepad.leftStick.IsPressed(), Is.False); + + Set(gamepad.leftStick, new Vector2(0.8f, 0f)); + Assert.That(gamepad.leftStick.IsPressed(), Is.True); + + gamepad.leftStick.pressPoint = -1f; + Set(gamepad.leftStick, new Vector2(0.4f, 0f)); + Assert.That(gamepad.leftStick.IsPressed(), Is.False); + + Set(gamepad.leftStick, new Vector2(0.55f, 0f)); + Assert.That(gamepad.leftStick.IsPressed(), Is.True); + } + + #endregion +} \ No newline at end of file diff --git a/Assets/Tests/InputSystem/ActuationPressPointTests.cs.meta b/Assets/Tests/InputSystem/ActuationPressPointTests.cs.meta new file mode 100644 index 0000000000..48093cdb5c --- /dev/null +++ b/Assets/Tests/InputSystem/ActuationPressPointTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8e7d6c5a4f302918273645564738291 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/InputSystem/CoreTests_Actions.cs b/Assets/Tests/InputSystem/CoreTests_Actions.cs index 34cfa9299d..172e63e214 100644 --- a/Assets/Tests/InputSystem/CoreTests_Actions.cs +++ b/Assets/Tests/InputSystem/CoreTests_Actions.cs @@ -21,7 +21,6 @@ using UnityEngine.TestTools; using UnityEngine.TestTools.Utils; using UnityEngine.TestTools.Constraints; - using Is = NUnit.Framework.Is; #pragma warning disable CS0649 @@ -389,7 +388,8 @@ public void Actions_CanBindMultipleShortcutSequencesBasedOnSameModifiers() [TestCase("leftShift", "leftAlt", "space", true)] [TestCase("leftShift", null, "space", false)] [TestCase("leftShift", "leftAlt", "space", false)] - public void Actions_WhenShortcutsEnabled_PressingShortcutSequenceInWrongOrder_DoesNotTriggerShortcut(string modifier1, string modifier2, string binding, bool legacyComposites) + public void Actions_WhenShortcutsEnabled_PressingShortcutSequenceInWrongOrder_DoesNotTriggerShortcut( + string modifier1, string modifier2, string binding, bool legacyComposites) { InputSystem.settings.shortcutKeysConsumeInput = true; @@ -430,21 +430,24 @@ public void Actions_WhenShortcutsEnabled_PressingShortcutSequenceInWrongOrder_Do [TestCase("leftShift", "leftAlt", "space", true)] [TestCase("leftShift", null, "space", false)] [TestCase("leftShift", "leftAlt", "space", false)] - public void Actions_WhenShortcutsDisabled_PressingShortcutSequenceInWrongOrder_DoesNotTriggerShortcutIfOverridden(string modifier1, string modifier2, string binding, bool legacyComposites) + public void Actions_WhenShortcutsDisabled_PressingShortcutSequenceInWrongOrder_DoesNotTriggerShortcutIfOverridden( + string modifier1, string modifier2, string binding, bool legacyComposites) { var keyboard = InputSystem.AddDevice(); var action = new InputAction(); if (!string.IsNullOrEmpty(modifier2)) { - action.AddCompositeBinding((legacyComposites ? "ButtonWithTwoModifiers" : "TwoModifiers") + "(modifiersOrder=1)") + action.AddCompositeBinding((legacyComposites ? "ButtonWithTwoModifiers" : "TwoModifiers") + + "(modifiersOrder=1)") .With("Modifier1", "/" + modifier1) .With("Modifier2", "/" + modifier2) .With(legacyComposites ? "Button" : "Binding", "/" + binding); } else { - action.AddCompositeBinding((legacyComposites ? "ButtonWithOneModifier" : "OneModifier") + "(modifiersOrder=1)") + action.AddCompositeBinding((legacyComposites ? "ButtonWithOneModifier" : "OneModifier") + + "(modifiersOrder=1)") .With("Modifier", "/" + modifier1) .With(legacyComposites ? "Button" : "Binding", "/" + binding); } @@ -473,8 +476,10 @@ public void Actions_WhenShortcutsDisabled_PressingShortcutSequenceInWrongOrder_D [TestCase("leftShift", "leftAlt", "space", true, false)] [TestCase("leftShift", null, "space", false, false)] [TestCase("leftShift", "leftAlt", "space", false, false)] - public void Actions_WhenShortcutsAreEnabled_PressingShortcutSequenceInWrongOrder_DoesNotTriggerShortcut_ExceptIfOverridden(string modifier1, string modifier2, string binding, - bool legacyComposites, bool overrideModifiersNeedToBePressedFirst) + public void + Actions_WhenShortcutsAreEnabled_PressingShortcutSequenceInWrongOrder_DoesNotTriggerShortcut_ExceptIfOverridden( + string modifier1, string modifier2, string binding, + bool legacyComposites, bool overrideModifiersNeedToBePressedFirst) { InputSystem.settings.shortcutKeysConsumeInput = true; @@ -483,14 +488,20 @@ public void Actions_WhenShortcutsAreEnabled_PressingShortcutSequenceInWrongOrder var action = new InputAction(); if (!string.IsNullOrEmpty(modifier2)) { - action.AddCompositeBinding((legacyComposites ? "ButtonWithTwoModifiers" : "TwoModifiers") + (overrideModifiersNeedToBePressedFirst ? "(overrideModifiersNeedToBePressedFirst)" : "(modifiersOrder=2)")) + action.AddCompositeBinding((legacyComposites ? "ButtonWithTwoModifiers" : "TwoModifiers") + + (overrideModifiersNeedToBePressedFirst + ? "(overrideModifiersNeedToBePressedFirst)" + : "(modifiersOrder=2)")) .With("Modifier1", "/" + modifier1) .With("Modifier2", "/" + modifier2) .With(legacyComposites ? "Button" : "Binding", "/" + binding); } else { - action.AddCompositeBinding((legacyComposites ? "ButtonWithOneModifier" : "OneModifier") + (overrideModifiersNeedToBePressedFirst ? "(overrideModifiersNeedToBePressedFirst)" : "(modifiersOrder=2)")) + action.AddCompositeBinding((legacyComposites ? "ButtonWithOneModifier" : "OneModifier") + + (overrideModifiersNeedToBePressedFirst + ? "(overrideModifiersNeedToBePressedFirst)" + : "(modifiersOrder=2)")) .With("Modifier", "/" + modifier1) .With(legacyComposites ? "Button" : "Binding", "/" + binding); } @@ -596,7 +607,8 @@ public void Actions_ReadingValueRightAfterEnabling_AppliesProcessorsFromFirstBin var map = new InputActionMap("map"); map.AddAction("action2", binding: "/buttonNorth"); - var action1 = map.AddAction("action1", binding: "/leftStick/x", processors: "normalize(min=-1,max=1,zero=-1)"); + var action1 = map.AddAction("action1", binding: "/leftStick/x", + processors: "normalize(min=-1,max=1,zero=-1)"); action1.AddBinding("/rightStick/x", processors: "normalize(min=0,max=1)"); map.Enable(); @@ -610,7 +622,8 @@ public void Actions_ReadingValueRightAfterResetting_AppliesProcessorsFromFirstBi var map = new InputActionMap("map"); map.AddAction("action2", binding: "/buttonNorth"); - var action1 = map.AddAction("action1", binding: "/leftStick/x", processors: "normalize(min=-1,max=1,zero=-1)"); + var action1 = map.AddAction("action1", binding: "/leftStick/x", + processors: "normalize(min=-1,max=1,zero=-1)"); action1.AddBinding("/rightStick/x", processors: "normalize(min=0,max=1)"); map.Enable(); @@ -644,7 +657,7 @@ public void Actions_DoNotGetTriggeredByEditorUpdates() [Test] [Category("Actions")] [Description("Tests that that only the latest event after focus is regained is able to trigger the action." + - "Depends on background behavior. (ISXB-1671)")] + "Depends on background behavior. (ISXB-1671)")] [TestCase(InputSettings.BackgroundBehavior.IgnoreFocus)] [TestCase(InputSettings.BackgroundBehavior.ResetAndDisableNonBackgroundDevices)] [TestCase(InputSettings.BackgroundBehavior.ResetAndDisableAllDevices)] @@ -666,7 +679,7 @@ public void Actions_DoNotGetTriggeredByOutOfFocusEventInEditor(InputSettings.Bac ScheduleFocusChangedEvent(applicationHasFocus: false); currentTime += 1.0f; // Queuing an event like it would be in the editor when the GameView is out of focus. - Set(mouse.position, new Vector2(0.234f, 0.345f) , queueEventOnly: true); + Set(mouse.position, new Vector2(0.234f, 0.345f), queueEventOnly: true); currentTime += 1.0f; // Gaining focus like it would happen in the editor when the GameView regains focus. ScheduleFocusChangedEvent(applicationHasFocus: true); @@ -687,7 +700,8 @@ public void Actions_DoNotGetTriggeredByOutOfFocusEventInEditor(InputSettings.Bac InputSystem.Update(InputUpdateType.Dynamic); actions = trace.ToArray(); - Assert.That(actions, Has.Length.EqualTo(backgroundBehavior == InputSettings.BackgroundBehavior.IgnoreFocus ? 2 : 1)); + Assert.That(actions, + Has.Length.EqualTo(backgroundBehavior == InputSettings.BackgroundBehavior.IgnoreFocus ? 2 : 1)); Assert.That(actions[0].phase, Is.EqualTo(InputActionPhase.Performed)); Vector2Control control = (Vector2Control)actions[0].control; // Make sure the value is from the event after focus was regained. @@ -824,7 +838,8 @@ public void Actions_CanTargetSameControlWithMultipleActions() // https://fogbugz.unity3d.com/f/cases/1293808/ [Test] [Category("Actions")] - public void Actions_WhenSeveralBindingsResolveToSameControl_SameControlFeedsIntoActionMultipleTimes_ButIsListedInControlsOnlyOnce() + public void + Actions_WhenSeveralBindingsResolveToSameControl_SameControlFeedsIntoActionMultipleTimes_ButIsListedInControlsOnlyOnce() { var gamepad = InputSystem.AddDevice(); @@ -862,7 +877,9 @@ public void Actions_WhenSeveralBindingsResolveToSameControl_SameControlFeedsInto Assert.That(action1.controls, Is.EquivalentTo(new[] { gamepad.buttonSouth })); Assert.That(action2.controls, Has.Exactly(1).SameAs(gamepad.buttonSouth)); - Assert.That(action2.controls, Is.EquivalentTo(new[] { gamepad.buttonNorth, gamepad.buttonSouth, gamepad.buttonEast, gamepad.buttonWest })); + Assert.That(action2.controls, + Is.EquivalentTo(new[] + { gamepad.buttonNorth, gamepad.buttonSouth, gamepad.buttonEast, gamepad.buttonWest })); Assert.That(action3.controls, Is.EquivalentTo(new[] { gamepad.buttonNorth, gamepad.buttonSouth })); Assert.That(action4.controls, Is.EquivalentTo(new[] { gamepad.buttonSouth })); Assert.That(action5.controls, Is.EquivalentTo(new[] { gamepad.buttonSouth })); @@ -922,7 +939,7 @@ public void Actions_WhenSeveralBindingsResolveToSameControl_SameControlFeedsInto Set(gamepad.leftStick, new Vector2(0, -1)); Assert.That(action6Performed, Is.EqualTo(1)); - Assert.That(action6.ReadValue(), Is.EqualTo(new Vector2(1, 0))); + Assert.That(action6.ReadValue(), Is.EqualTo(new Vector2(1, 0))); } [Test] @@ -948,7 +965,8 @@ public void Actions_WhenDisabled_CancelAllStartedInteractions() var gamepad = InputSystem.AddDevice(); - var action1 = new InputAction("action1", InputActionType.Button, binding: "/buttonSouth", interactions: "Hold"); + var action1 = new InputAction("action1", InputActionType.Button, binding: "/buttonSouth", + interactions: "Hold"); var action2 = new InputAction("action2", InputActionType.Button, binding: "/leftStick"); var action3 = new InputAction("action3", InputActionType.Button, binding: "/rightStick"); @@ -1180,7 +1198,8 @@ public void Actions_ButtonActions_GoBackToStartedWhenHeldBelowReleasePoint() // Make sure both PressInteraction and the default interaction handles this exactly the same way. var buttonAction = new InputAction(type: InputActionType.Button, binding: "/rightTrigger"); - var pressAction = new InputAction(type: InputActionType.Value, binding: "/rightTrigger", interactions: "press"); + var pressAction = new InputAction(type: InputActionType.Value, binding: "/rightTrigger", + interactions: "press"); buttonAction.Enable(); pressAction.Enable(); @@ -1294,9 +1313,12 @@ public void Actions_ValueActionsReactToCurrentStateOfControlWhenEnabled() Set(gamepad.leftStick, new Vector2(0.123f, 0.234f)); Press(gamepad.buttonSouth); - var actionWithoutInteraction = new InputAction("ActionWithoutInteraction", InputActionType.Value, binding: "/leftStick"); - var actionWithHold = new InputAction("ActionWithHold", InputActionType.Value, binding: "/buttonSouth", interactions: "Hold"); - var actionThatShouldNotTrigger = new InputAction("ActionThatShouldNotTrigger", InputActionType.Value, binding: "/rightStick"); + var actionWithoutInteraction = new InputAction("ActionWithoutInteraction", InputActionType.Value, + binding: "/leftStick"); + var actionWithHold = new InputAction("ActionWithHold", InputActionType.Value, binding: "/buttonSouth", + interactions: "Hold"); + var actionThatShouldNotTrigger = new InputAction("ActionThatShouldNotTrigger", InputActionType.Value, + binding: "/rightStick"); actionWithHold.performed += ctx => Assert.Fail("Hold should not complete"); actionThatShouldNotTrigger.started += ctx => Assert.Fail("Action should not start"); @@ -1315,9 +1337,13 @@ public void Actions_ValueActionsReactToCurrentStateOfControlWhenEnabled() InputSystem.QueueDeltaStateEvent(gamepad.leftStick, new Vector2(0.345f, 0.456f)); InputSystem.Update(); - Assert.That(trace1, Started(actionWithoutInteraction, control: gamepad.leftStick, value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f))) - .AndThen(Performed(actionWithoutInteraction, control: gamepad.leftStick, value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)))) - .AndThen(Performed(actionWithoutInteraction, control: gamepad.leftStick, value: new StickDeadzoneProcessor().Process(new Vector2(0.345f, 0.456f))))); + Assert.That(trace1, + Started(actionWithoutInteraction, control: gamepad.leftStick, + value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f))) + .AndThen(Performed(actionWithoutInteraction, control: gamepad.leftStick, + value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)))) + .AndThen(Performed(actionWithoutInteraction, control: gamepad.leftStick, + value: new StickDeadzoneProcessor().Process(new Vector2(0.345f, 0.456f))))); Assert.That(trace2, Started(actionWithHold, control: gamepad.buttonSouth, value: 1f)); } } @@ -1522,24 +1548,24 @@ public void Actions_CanAddAndRemoveCallbacks_FromCallback(string callback) Action delegate1 = null; delegate1 = _ => - { - invocations.Add("delegate1"); - switch (callback) { - case "started": - action.started -= delegate1; - action.started += delegate2; - break; - case "performed": - action.performed -= delegate1; - action.performed += delegate2; - break; - case "canceled": - action.canceled -= delegate1; - action.canceled += delegate2; - break; - } - }; + invocations.Add("delegate1"); + switch (callback) + { + case "started": + action.started -= delegate1; + action.started += delegate2; + break; + case "performed": + action.performed -= delegate1; + action.performed += delegate2; + break; + case "canceled": + action.canceled -= delegate1; + action.canceled += delegate2; + break; + } + }; switch (callback) { @@ -1612,13 +1638,14 @@ public unsafe void Actions_CanTriggerBindingResolutionOnAction_FromCallback(bool Set(gamepad.leftStick, new Vector2(0.234f, 0.345f)); - Assert.That(action.controls, Is.EquivalentTo(new InputControl[] {gamepad.leftStick, mouse.delta})); + Assert.That(action.controls, Is.EquivalentTo(new InputControl[] { gamepad.leftStick, mouse.delta })); } // ReSharper disable once ClassNeverInstantiated.Local private class ConstantFloatTestProcessor : InputProcessor { public const float EXPECTED_VALUE = 0.5f; + public override float Process(float value, InputControl control) { return EXPECTED_VALUE; @@ -1678,26 +1705,17 @@ public void Actions_CanDisableAndEnableOtherAction_FromCallback() var action = new InputAction(binding: "/buttonSouth"); action.performed += - ctx => - { - ++receivedCalls; - }; + ctx => { ++receivedCalls; }; action.Enable(); var disableAction = new InputAction(binding: "/buttonEast"); disableAction.performed += - ctx => - { - action.Disable(); - }; + ctx => { action.Disable(); }; disableAction.Enable(); var enableAction = new InputAction(binding: "/buttonWest"); enableAction.performed += - ctx => - { - action.Enable(); - }; + ctx => { action.Enable(); }; enableAction.Enable(); InputSystem.QueueStateEvent(gamepad, new GamepadState(GamepadButton.South)); @@ -1736,7 +1754,7 @@ public void Actions_CanDisableAndEnable_FromCallbackWhileOtherCompositeBindingIs actionWithModifier.AddCompositeBinding("OneModifier") .With("Binding", "/space") .With("Modifier", "/ctrl"); - actionWithModifier.performed += _ => ++ withModiferReceivedCalls; + actionWithModifier.performed += _ => ++withModiferReceivedCalls; var actionWithoutModifier = map.AddAction("One", type: InputActionType.Button, binding: "/space"); actionWithoutModifier.performed += _ => actionWithModifier.Disable(); @@ -1773,10 +1791,10 @@ public void Actions_WhenEnabled_TriggerNotification() var received = new List(); InputSystem.onActionChange += (obj, change) => - { - received.Add(change); - received.Add(obj); - }; + { + received.Add(change); + received.Add(obj); + }; // Enable map. map.Enable(); @@ -2075,7 +2093,8 @@ public void Actions_CanDistinguishCanceledAndCompletedInCurrentFrame(InputAction var defaultAction = new InputAction(type: actionType, binding: "/buttonSouth"); var pressAction = new InputAction(type: actionType, binding: "/buttonSouth", interactions: "press"); - var holdAction = new InputAction(type: actionType, binding: "/buttonSouth", interactions: "hold(duration=0.5)"); + var holdAction = new InputAction(type: actionType, binding: "/buttonSouth", + interactions: "hold(duration=0.5)"); defaultAction.Enable(); pressAction.Enable(); @@ -2521,7 +2540,7 @@ public void Actions_CanReadPerformedFromAction_AsButton(InputActionType actionTy var isHold = interactions?.StartsWith("hold") ?? false; var isPress = interactions?.StartsWith("press") ?? false; var isButtonLike = (action.type == InputActionType.Value && isPress) || - (action.type == InputActionType.Button && !isHold); + (action.type == InputActionType.Button && !isHold); using (var trace = new InputActionTrace(action)) { @@ -3158,10 +3177,10 @@ public void Actions_CanReadValueFromAction_InCallback() float? receivedValue = null; action.performed += ctx => - { - Assert.That(receivedValue, Is.Null); - receivedValue = ctx.ReadValue(); - }; + { + Assert.That(receivedValue, Is.Null); + receivedValue = ctx.ReadValue(); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState().WithButton(GamepadButton.South)); InputSystem.Update(); @@ -3183,10 +3202,10 @@ public void Actions_CanReadValueFromAction_InCallback_AsButton() bool? receivedValue = null; action.performed += ctx => - { - Assert.That(receivedValue, Is.Null); - receivedValue = ctx.ReadValueAsButton(); - }; + { + Assert.That(receivedValue, Is.Null); + receivedValue = ctx.ReadValueAsButton(); + }; Set(gamepad.leftTrigger, 0.25f); @@ -3228,20 +3247,20 @@ public unsafe void Actions_CanReadValueFromAction_InCallback_WithoutKnowingValue action.performed += ctx => - { - Assert.That(receivedValueData, Is.Null); - Assert.That(ctx.valueType, Is.EqualTo(typeof(Vector2))); - Assert.That(ctx.valueSizeInBytes, Is.EqualTo(sizeof(Vector2))); - - var sizeInBytes = ctx.valueSizeInBytes; - receivedValueData = new byte[sizeInBytes]; - fixed(byte* dataPtr = receivedValueData) { - ctx.ReadValue(dataPtr, sizeInBytes); - } - }; + Assert.That(receivedValueData, Is.Null); + Assert.That(ctx.valueType, Is.EqualTo(typeof(Vector2))); + Assert.That(ctx.valueSizeInBytes, Is.EqualTo(sizeof(Vector2))); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftStick = new Vector2(0.123f, 0.234f)}); + var sizeInBytes = ctx.valueSizeInBytes; + receivedValueData = new byte[sizeInBytes]; + fixed (byte* dataPtr = receivedValueData) + { + ctx.ReadValue(dataPtr, sizeInBytes); + } + }; + + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.123f, 0.234f) }); InputSystem.Update(); Assert.That(receivedValueData, Has.Length.EqualTo(sizeof(Vector2))); @@ -3281,10 +3300,10 @@ public void Actions_CanReadValueTypeFromAction() action.performed += ctx => - { - Assert.That(ctx.valueType, Is.EqualTo(typeof(Vector2))); - Assert.That(ctx.action.activeValueType, Is.EqualTo(typeof(Vector2))); - }; + { + Assert.That(ctx.valueType, Is.EqualTo(typeof(Vector2))); + Assert.That(ctx.action.activeValueType, Is.EqualTo(typeof(Vector2))); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.123f, 0.234f) }); InputSystem.Update(); @@ -3326,10 +3345,10 @@ public void Actions_CanReadValueTypeFromAction_WithDynamicCompositeType() action.performed += ctx => - { - Assert.That(ctx.valueType, Is.EqualTo(typeof(Vector2))); - Assert.That(ctx.action.activeValueType, Is.EqualTo(typeof(Vector2))); - }; + { + Assert.That(ctx.valueType, Is.EqualTo(typeof(Vector2))); + Assert.That(ctx.action.activeValueType, Is.EqualTo(typeof(Vector2))); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.123f, 0.234f) }); InputSystem.Update(); @@ -3341,7 +3360,8 @@ public void Actions_CanReadValueTypeFromAction_WithDynamicCompositeType() Is.EqualTo(new StickDeadzoneProcessor().Process(Vector2.zero)) .Using(Vector2EqualityComparer.Instance)); - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.123f, 0.234f), leftTrigger = 1f }); + InputSystem.QueueStateEvent(gamepad, + new GamepadState { leftStick = new Vector2(0.123f, 0.234f), leftTrigger = 1f }); InputSystem.Update(); // The active control is the most recent change (left trigger), which has a value type of float. @@ -3367,13 +3387,13 @@ public void Actions_ReadingValueOfIncorrectType_ThrowsHelpfulException() var receivedCall = false; action.performed += ctx => - { - receivedCall = true; - Assert.That(() => ctx.ReadValue(), - Throws.InvalidOperationException.With.Message.Contains("buttonSouth") - .And.With.Message.Contains("float") - .And.With.Message.Contains("Vector2")); - }; + { + receivedCall = true; + Assert.That(() => ctx.ReadValue(), + Throws.InvalidOperationException.With.Message.Contains("buttonSouth") + .And.With.Message.Contains("float") + .And.With.Message.Contains("Vector2")); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState().WithButton(GamepadButton.South)); InputSystem.Update(); @@ -3473,7 +3493,8 @@ public void Actions_CanQueryActiveValueType() [TestCase(InputActionType.Value, "Scale(factor=2)")] [TestCase(InputActionType.Button)] [TestCase(InputActionType.Button, "Scale(factor=2)")] - public void Actions_CanQueryMagnitudeFromAction_WithAxisControl(InputActionType actionType, string processors = null) + public void Actions_CanQueryMagnitudeFromAction_WithAxisControl(InputActionType actionType, + string processors = null) { var gamepad = InputSystem.AddDevice(); @@ -3550,7 +3571,8 @@ public void Actions_CanQueryMagnitudeFromAction_WithStickControl() [Category("Actions")] [TestCase(InputActionType.Value)] [TestCase(InputActionType.Value, "Scale(factor=2)")] - public void Actions_CanQueryMagnitudeFromAction_WithCompositeAxisControl(InputActionType actionType, string processors = null) + public void Actions_CanQueryMagnitudeFromAction_WithCompositeAxisControl(InputActionType actionType, + string processors = null) { var keyboard = InputSystem.AddDevice(); @@ -3604,7 +3626,8 @@ public void Actions_CanQueryMagnitudeFromAction_WithCompositeAxisControl(InputAc [Category("Actions")] [TestCase(InputActionType.Value)] [TestCase(InputActionType.Value, "ScaleVector2(x=2,y=2)")] - public void Actions_CanQueryMagnitudeFromAction_WithComposite2DVectorControl(InputActionType actionType, string processors = null) + public void Actions_CanQueryMagnitudeFromAction_WithComposite2DVectorControl(InputActionType actionType, + string processors = null) { var keyboard = InputSystem.AddDevice(); @@ -3687,7 +3710,8 @@ public void Actions_CanQueryMagnitudeFromAction_WithQuaternionControl_ReturnsInv Assert.That(action.activeControl, Is.SameAs(sensor.attitude)); Assert.That(action.phase, Is.EqualTo(InputActionPhase.Started)); - Assert.That(action.ReadValue(), Is.EqualTo(Quaternion.Euler(30f, 60f, 45f)).Using(QuaternionEqualityComparer.Instance)); + Assert.That(action.ReadValue(), + Is.EqualTo(Quaternion.Euler(30f, 60f, 45f)).Using(QuaternionEqualityComparer.Instance)); Assert.That(action.GetControlMagnitude(), Is.EqualTo(-1f)); Set(sensor.attitude, Quaternion.identity); @@ -3714,14 +3738,16 @@ public void Actions_ResettingDevice_CancelsOngoingActionsThatAreDrivenByIt() // Create an action that performs on button *up*. This way we can tell whether // the action is truly cancelled or whether it simply gets triggered by us // resetting the corresponding device state. - var buttonReleaseAction = new InputAction(name: "button", type: InputActionType.Button, binding: "/buttonSouth", + var buttonReleaseAction = new InputAction(name: "button", type: InputActionType.Button, + binding: "/buttonSouth", interactions: "press(behavior=1)"); buttonReleaseAction.Enable(); var valueAction = new InputAction(name: "value", type: InputActionType.Value, binding: "/buttonSouth"); valueAction.Enable(); - var passThroughAction = new InputAction(name: "passthrough", type: InputActionType.PassThrough, binding: "/buttonSouth"); + var passThroughAction = new InputAction(name: "passthrough", type: InputActionType.PassThrough, + binding: "/buttonSouth"); passThroughAction.Enable(); Press(gamepad.buttonSouth); @@ -3748,7 +3774,8 @@ public void Actions_ResettingDevice_CancelsOngoingActionsThatAreDrivenByIt() // does not cause the action to start back up. For pass-through actions, that is different // as *any* value change performs the action. So here, we see *both* a cancellation and then // immediately a performing of the action. - Assert.That(passThroughActionTrace, Canceled(passThroughAction).AndThen(Performed(passThroughAction, value: 0f))); + Assert.That(passThroughActionTrace, + Canceled(passThroughAction).AndThen(Performed(passThroughAction, value: 0f))); } } @@ -3818,11 +3845,12 @@ public void Actions_CanCreateActionAssetWithMultipleActionMaps() // map1/action1 should have been started and performed. Assert.That(trace, - Started(action1, value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(-1, 1), - control: gamepad.leftStick, time: startTime + 0.123) + Started(action1, + value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(-1, 1), + control: gamepad.leftStick, time: startTime + 0.123) .AndThen(Performed(action1, - value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(-1, 1), - control: gamepad.leftStick, time: startTime + 0.123))); + value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(-1, 1), + control: gamepad.leftStick, time: startTime + 0.123))); trace.Clear(); @@ -3839,20 +3867,22 @@ public void Actions_CanCreateActionAssetWithMultipleActionMaps() Assert.That(trace, // map1/action1 should have been canceled. Canceled(action1, value: default(Vector2), control: gamepad.leftStick, time: startTime + 0.234) - // map3/action4 should immediately start as the stick was already actuated - // when we enabled the action. - // NOTE: We get a different value here than what action1 got as we have a different - // processor on the binding. + // map3/action4 should immediately start as the stick was already actuated + // when we enabled the action. + // NOTE: We get a different value here than what action1 got as we have a different + // processor on the binding. .AndThen(Started(action4, - value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(1, -1), - control: gamepad.leftStick, time: startTime + 0.234)) + value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(1, -1), + control: gamepad.leftStick, time: startTime + 0.234)) .AndThen(Performed(action4, value: new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)) * new Vector2(1, -1), control: gamepad.leftStick, time: startTime + 0.234)) // map2/action3 should have been started. - .AndThen(Started(action3, value: 1f, control: gamepad.buttonSouth, time: startTime + 0.345)) + .AndThen(Started(action3, value: 1f, control: gamepad.buttonSouth, + time: startTime + 0.345)) // map3/action5 should have been started. - .AndThen(Started(action5, value: 1f, control: gamepad.buttonSouth, time: startTime + 0.345)) + .AndThen(Started(action5, value: 1f, control: gamepad.buttonSouth, + time: startTime + 0.345)) // map3/action4 should have been performed as the stick has been moved // beyond where it had already moved. .AndThen(Performed(action4, @@ -3868,11 +3898,12 @@ public void Actions_CanCreateActionAssetWithMultipleActionMaps() Assert.That(trace, // map2/action3 should have been canceled. Canceled(action3, value: 0f, control: gamepad.buttonSouth, time: currentTime) - // map3/action4 should have been canceled. + // map3/action4 should have been canceled. .AndThen(Canceled(action4, value: default(Vector2), control: gamepad.leftStick, - time: currentTime)) + time: currentTime)) // map3/action5 should have been canceled. - .AndThen(Canceled(action5, value: 0f, control: gamepad.buttonSouth, time: currentTime))); + .AndThen(Canceled(action5, value: 0f, control: gamepad.buttonSouth, + time: currentTime))); trace.Clear(); @@ -3924,13 +3955,13 @@ public void Actions_ActionIsPerformedWhenSourceControlChangesValue() var action = new InputAction(binding: "/leftStick"); action.performed += ctx => - { - ++receivedCalls; - receivedAction = ctx.action; - receivedControl = ctx.control; + { + ++receivedCalls; + receivedAction = ctx.action; + receivedControl = ctx.control; - Assert.That(ctx.phase, Is.EqualTo(InputActionPhase.Performed)); - }; + Assert.That(ctx.phase, Is.EqualTo(InputActionPhase.Performed)); + }; action.Enable(); // Actuate stick. @@ -3970,21 +4001,24 @@ public void Actions_CanByPassControlActuationChecks_UsingPasshtroughAction() Set(gamepad.leftStick, new Vector2(0.123f, 0.234f)); Assert.That(trace, - Performed(action, gamepad.leftStick, new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)))); + Performed(action, gamepad.leftStick, + new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)))); trace.Clear(); Set(gamepad.leftStick, new Vector2(0.234f, 0.345f)); Assert.That(trace, - Performed(action, gamepad.leftStick, new StickDeadzoneProcessor().Process(new Vector2(0.234f, 0.345f)))); + Performed(action, gamepad.leftStick, + new StickDeadzoneProcessor().Process(new Vector2(0.234f, 0.345f)))); trace.Clear(); Set(gamepad.rightStick, new Vector2(0.123f, 0.234f)); Assert.That(trace, - Performed(action, gamepad.rightStick, new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)))); + Performed(action, gamepad.rightStick, + new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f)))); trace.Clear(); @@ -4064,8 +4098,8 @@ public void Actions_WithMultipleBoundControls_DriveInteractionsFromControlWithGr Set(gamepad.leftStick, new Vector2(0.345f, 0.456f)); Assert.That(trace, Started(stickAction, control: gamepad.leftStick, - value: new StickDeadzoneProcessor().Process(new Vector2(0.345f, 0.456f))) - .AndThen(Performed(stickAction, control: gamepad.leftStick, + value: new StickDeadzoneProcessor().Process(new Vector2(0.345f, 0.456f))) + .AndThen(Performed(stickAction, control: gamepad.leftStick, value: new StickDeadzoneProcessor().Process(new Vector2(0.345f, 0.456f))))); trace.Clear(); @@ -4177,9 +4211,9 @@ public void Actions_WithMultipleBoundControls_DriveInteractionsFromControlWithGr var actions = trace.ToArray(); - #if UNITY_EDITOR +#if UNITY_EDITOR Assert.That(actions, Has.Length.EqualTo(5)); - #endif +#endif Assert.That(actions[0].phase, Is.EqualTo(InputActionPhase.Started)); Assert.That(actions[0].control, Is.SameAs(gamepad.buttonSouth)); @@ -4190,14 +4224,16 @@ public void Actions_WithMultipleBoundControls_DriveInteractionsFromControlWithGr Assert.That(actions[1].action, Is.SameAs(buttonAction)); Assert.That(actions[1].ReadValue(), Is.EqualTo(1).Within(0.00001)); - #if UNITY_EDITOR +#if UNITY_EDITOR Assert.That(actions[2].phase, Is.EqualTo(InputActionPhase.Performed)); - Assert.That(actions[2].control, Is.SameAs(gamepad.buttonWest)); // Control immediately following buttonSouth in list of controls. + Assert.That(actions[2].control, + Is.SameAs(gamepad.buttonWest)); // Control immediately following buttonSouth in list of controls. Assert.That(actions[2].action, Is.SameAs(buttonAction)); Assert.That(actions[2].ReadValue(), Is.EqualTo(1).Within(0.00001)); - #endif +#endif - Assert.That(actions[actions.Length - 2].phase, Is.EqualTo(InputActionPhase.Performed)); // Last control to be actuated. + Assert.That(actions[actions.Length - 2].phase, + Is.EqualTo(InputActionPhase.Performed)); // Last control to be actuated. Assert.That(actions[actions.Length - 2].control, Is.SameAs(gamepad.buttonNorth)); Assert.That(actions[actions.Length - 2].action, Is.SameAs(buttonAction)); Assert.That(actions[actions.Length - 2].ReadValue(), Is.EqualTo(1).Within(0.00001)); @@ -4210,6 +4246,7 @@ public void Actions_WithMultipleBoundControls_DriveInteractionsFromControlWithGr private class ReleaseOnlyTestInteraction : IInputInteraction { private bool m_WaitingForRelease; + public void Process(ref InputInteractionContext context) { var actuated = context.ControlIsActuated(); @@ -4340,7 +4377,9 @@ public void Actions_WithMultipleBoundControls_CanHandleInteractionsThatTriggerOn Release(gamepad.buttonNorth); - Assert.That(trace, Started(action, gamepad.buttonNorth).AndThen(Performed(action, gamepad.buttonNorth)).AndThen(Canceled(action, gamepad.buttonNorth))); + Assert.That(trace, + Started(action, gamepad.buttonNorth).AndThen(Performed(action, gamepad.buttonNorth)) + .AndThen(Canceled(action, gamepad.buttonNorth))); trace.Clear(); @@ -4352,7 +4391,9 @@ public void Actions_WithMultipleBoundControls_CanHandleInteractionsThatTriggerOn Release(gamepad.buttonNorth); - Assert.That(trace, Started(action, gamepad.buttonNorth).AndThen(Performed(action, gamepad.buttonNorth)).AndThen(Canceled(action, gamepad.buttonNorth))); + Assert.That(trace, + Started(action, gamepad.buttonNorth).AndThen(Performed(action, gamepad.buttonNorth)) + .AndThen(Canceled(action, gamepad.buttonNorth))); trace.Clear(); @@ -4363,7 +4404,9 @@ public void Actions_WithMultipleBoundControls_CanHandleInteractionsThatTriggerOn Release(keyboard.aKey); - Assert.That(trace, Started(action, keyboard.aKey).AndThen(Performed(action, keyboard.aKey)).AndThen(Canceled(action, keyboard.aKey))); + Assert.That(trace, + Started(action, keyboard.aKey).AndThen(Performed(action, keyboard.aKey)) + .AndThen(Canceled(action, keyboard.aKey))); trace.Clear(); @@ -4382,13 +4425,17 @@ public void Actions_WithMultipleBoundControls_CanHandleInteractionsThatTriggerOn Release(keyboard.aKey); - Assert.That(trace, Started(action, keyboard.aKey).AndThen(Performed(action, keyboard.aKey)).AndThen(Canceled(action, keyboard.aKey))); + Assert.That(trace, + Started(action, keyboard.aKey).AndThen(Performed(action, keyboard.aKey)) + .AndThen(Canceled(action, keyboard.aKey))); trace.Clear(); Release(gamepad.buttonNorth); - Assert.That(trace, Started(action, gamepad.buttonNorth).AndThen(Performed(action, gamepad.buttonNorth)).AndThen(Canceled(action, gamepad.buttonNorth))); + Assert.That(trace, + Started(action, gamepad.buttonNorth).AndThen(Performed(action, gamepad.buttonNorth)) + .AndThen(Canceled(action, gamepad.buttonNorth))); } } @@ -4514,10 +4561,10 @@ public void Actions_CanListenForStateChangeOnEntireDevice() var action = new InputAction(binding: "/gamepad"); action.performed += ctx => - { - ++receivedCalls; - receivedControl = ctx.control; - }; + { + ++receivedCalls; + receivedControl = ctx.control; + }; action.Enable(); var state = new GamepadState @@ -4547,32 +4594,32 @@ public void Actions_CanMonitorTriggeredActionsOnActionMap() map.actionTriggered += ctx => - { - Assert.That(ctx.action, Is.SameAs(action)); - Assert.That(ctx.control, Is.SameAs(gamepad.leftTrigger)); - - switch (ctx.phase) { - case InputActionPhase.Started: - Assert.That(wasStarted, Is.False); - Assert.That(wasPerformed, Is.False); - Assert.That(wasCanceled, Is.False); - wasStarted = true; - break; - case InputActionPhase.Performed: - Assert.That(wasStarted, Is.True); - Assert.That(wasPerformed, Is.False); - Assert.That(wasCanceled, Is.False); - wasPerformed = true; - break; - case InputActionPhase.Canceled: - Assert.That(wasStarted, Is.True); - Assert.That(wasPerformed, Is.True); - Assert.That(wasCanceled, Is.False); - wasCanceled = true; - break; - } - }; + Assert.That(ctx.action, Is.SameAs(action)); + Assert.That(ctx.control, Is.SameAs(gamepad.leftTrigger)); + + switch (ctx.phase) + { + case InputActionPhase.Started: + Assert.That(wasStarted, Is.False); + Assert.That(wasPerformed, Is.False); + Assert.That(wasCanceled, Is.False); + wasStarted = true; + break; + case InputActionPhase.Performed: + Assert.That(wasStarted, Is.True); + Assert.That(wasPerformed, Is.False); + Assert.That(wasCanceled, Is.False); + wasPerformed = true; + break; + case InputActionPhase.Canceled: + Assert.That(wasStarted, Is.True); + Assert.That(wasPerformed, Is.True); + Assert.That(wasCanceled, Is.False); + wasCanceled = true; + break; + } + }; map.Enable(); @@ -4607,30 +4654,30 @@ public void Actions_WhenTriggered_TriggerGlobalNotification() var receivedChanges = new List(); InputSystem.onActionChange += (a, c) => - { - Assert.That(a, Is.SameAs((InputAction)a)); - - // Notification must come *before* callback. - switch (((InputAction)a).phase) { - case InputActionPhase.Started: - Assert.That(receivedStarted, Is.False); - break; - case InputActionPhase.Canceled: - Assert.That(receivedCanceled, Is.False); - break; - case InputActionPhase.Performed: - Assert.That(receivedPerformed, Is.False); - break; - } + Assert.That(a, Is.SameAs((InputAction)a)); - receivedChanges.Add(c); - }; + // Notification must come *before* callback. + switch (((InputAction)a).phase) + { + case InputActionPhase.Started: + Assert.That(receivedStarted, Is.False); + break; + case InputActionPhase.Canceled: + Assert.That(receivedCanceled, Is.False); + break; + case InputActionPhase.Performed: + Assert.That(receivedPerformed, Is.False); + break; + } + + receivedChanges.Add(c); + }; Set(gamepad.leftTrigger, 0.5f); Assert.That(receivedChanges, - Is.EquivalentTo(new[] {InputActionChange.ActionStarted, InputActionChange.ActionPerformed})); + Is.EquivalentTo(new[] { InputActionChange.ActionStarted, InputActionChange.ActionPerformed })); receivedChanges.Clear(); receivedStarted = false; @@ -4640,7 +4687,7 @@ public void Actions_WhenTriggered_TriggerGlobalNotification() Set(gamepad.leftTrigger, 0); Assert.That(receivedChanges, - Is.EquivalentTo(new[] {InputActionChange.ActionCanceled})); + Is.EquivalentTo(new[] { InputActionChange.ActionCanceled })); } [Test] @@ -4667,7 +4714,7 @@ public void Actions_CanRecordActions() action.performed += trace.RecordAction; - var state = new GamepadState {leftStick = new Vector2(0.123f, 0.234f)}; + var state = new GamepadState { leftStick = new Vector2(0.123f, 0.234f) }; InputSystem.QueueStateEvent(gamepad, state, 0.1234); state.rightStick = new Vector2(0.345f, 0.456f); InputSystem.QueueStateEvent(gamepad, state, 0.2345); @@ -4730,7 +4777,8 @@ public void Actions_CanRecordActions_FromMultipleMaps() trace.SubscribeTo(map1); trace.SubscribeTo(map2); - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.one }.WithButton(GamepadButton.South)); + InputSystem.QueueStateEvent(gamepad, + new GamepadState { leftStick = Vector2.one }.WithButton(GamepadButton.South)); InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A)); InputSystem.Update(); @@ -4771,29 +4819,29 @@ public void Actions_CanRecordActions_AndReadTheDataEvenIfBindingsHaveChanged() action.AddBinding("/leftButton").WithGroup("C"); // Enable only gamepad binding. - action.bindingMask = new InputBinding {groups = "A"}; + action.bindingMask = new InputBinding { groups = "A" }; action.Enable(); using (var trace = new InputActionTrace()) { trace.SubscribeTo(action); - Assert.That(action.controls, Is.EquivalentTo(new[] {gamepad.buttonSouth})); + Assert.That(action.controls, Is.EquivalentTo(new[] { gamepad.buttonSouth })); Press(gamepad.buttonSouth); // Enable both keyboard and gamepad binding. - action.bindingMask = new InputBinding {groups = "B"}; + action.bindingMask = new InputBinding { groups = "B" }; - Assert.That(action.controls, Is.EquivalentTo(new[] {keyboard.aKey, gamepad.buttonSouth})); + Assert.That(action.controls, Is.EquivalentTo(new[] { keyboard.aKey, gamepad.buttonSouth })); Release(gamepad.buttonSouth); Press(keyboard.aKey); // Disable both keyboard and gamepad binding by switching to mouse binding. - action.bindingMask = new InputBinding {groups = "C"}; + action.bindingMask = new InputBinding { groups = "C" }; - Assert.That(action.controls, Is.EquivalentTo(new[] {mouse.leftButton})); + Assert.That(action.controls, Is.EquivalentTo(new[] { mouse.leftButton })); Assert.That(trace, Started(action, gamepad.buttonSouth) @@ -4872,12 +4920,24 @@ public void Actions_CanRecordAllActionsInTheSystem() var actions = trace.ToArray(); Assert.That(actions, Has.Length.EqualTo(6)); - Assert.That(actions, Has.Exactly(1).With.Property("action").SameAs(action1).And.Property("phase").EqualTo(InputActionPhase.Started)); - Assert.That(actions, Has.Exactly(1).With.Property("action").SameAs(action1).And.Property("phase").EqualTo(InputActionPhase.Performed)); - Assert.That(actions, Has.Exactly(1).With.Property("action").SameAs(action2).And.Property("phase").EqualTo(InputActionPhase.Started)); - Assert.That(actions, Has.Exactly(1).With.Property("action").SameAs(action2).And.Property("phase").EqualTo(InputActionPhase.Performed)); - Assert.That(actions, Has.Exactly(1).With.Property("action").SameAs(action3).And.Property("phase").EqualTo(InputActionPhase.Started)); - Assert.That(actions, Has.Exactly(1).With.Property("action").SameAs(action3).And.Property("phase").EqualTo(InputActionPhase.Performed)); + Assert.That(actions, + Has.Exactly(1).With.Property("action").SameAs(action1).And.Property("phase") + .EqualTo(InputActionPhase.Started)); + Assert.That(actions, + Has.Exactly(1).With.Property("action").SameAs(action1).And.Property("phase") + .EqualTo(InputActionPhase.Performed)); + Assert.That(actions, + Has.Exactly(1).With.Property("action").SameAs(action2).And.Property("phase") + .EqualTo(InputActionPhase.Started)); + Assert.That(actions, + Has.Exactly(1).With.Property("action").SameAs(action2).And.Property("phase") + .EqualTo(InputActionPhase.Performed)); + Assert.That(actions, + Has.Exactly(1).With.Property("action").SameAs(action3).And.Property("phase") + .EqualTo(InputActionPhase.Started)); + Assert.That(actions, + Has.Exactly(1).With.Property("action").SameAs(action3).And.Property("phase") + .EqualTo(InputActionPhase.Performed)); trace.Clear(); @@ -4903,8 +4963,8 @@ public void Actions_PressingAndReleasingButtonInSameUpdate_StillTriggersAction() ctx => { ++receivedCalls; }; action.Enable(); - var firstState = new GamepadState {buttons = 1 << (int)GamepadButton.B}; - var secondState = new GamepadState {buttons = 0}; + var firstState = new GamepadState { buttons = 1 << (int)GamepadButton.B }; + var secondState = new GamepadState { buttons = 0 }; InputSystem.QueueStateEvent(gamepad, firstState); InputSystem.QueueStateEvent(gamepad, secondState); @@ -5220,7 +5280,7 @@ public void Actions_CanConvertMultipleActionMapsToAndFromJson() map1.AddAction(name: "action1", binding: "/gamepad/leftStick"); map2.AddAction(name: "action2", binding: "/gamepad/rightStick"); - var json = InputActionMap.ToJson(new[] {map1, map2}); + var json = InputActionMap.ToJson(new[] { map1, map2 }); var sets = InputActionMap.FromJson(json); Assert.That(sets, Has.Length.EqualTo(2)); @@ -5298,7 +5358,8 @@ public void Actions_CanConvertAssetToAndFromJson() static string MinimalJson(string name = null) { if (name != null) - return "{\n \"version\": 0,\n \"name\": \"" + name + "\",\n \"maps\": [],\n \"controlSchemes\": []\n}"; + return "{\n \"version\": 0,\n \"name\": \"" + name + + "\",\n \"maps\": [],\n \"controlSchemes\": []\n}"; return "{\n \"version\": 0,\n \"maps\": [],\n \"controlSchemes\": []\n}"; } @@ -5488,7 +5549,7 @@ public void Actions_CanAddBindingsToActions_ToExistingComposite() .With("Positive", "/d"); Assert.That(action.bindings, Has.Count.EqualTo(3)); - Assert.That(action.controls, Is.EquivalentTo(new[] {keyboard.aKey, keyboard.dKey})); + Assert.That(action.controls, Is.EquivalentTo(new[] { keyboard.aKey, keyboard.dKey })); var composite = action.ChangeCompositeBinding("Axis"); @@ -5500,7 +5561,8 @@ public void Actions_CanAddBindingsToActions_ToExistingComposite() [Test] [Category("Actions")] - [Description("ISXB-494 Changing composite of action inside a map triggered exception that wasn't caught by previous test.")] + [Description( + "ISXB-494 Changing composite of action inside a map triggered exception that wasn't caught by previous test.")] public void Actions_CanChangeBindingPart_ToExistingCompositeInActionMap() { var keyboard = InputSystem.AddDevice(); @@ -5527,19 +5589,24 @@ private void ValidateCompositeBindingsOnAction(InputAction action) { Assert.That(action.bindings, Has.Count.EqualTo(5)); Assert.That(action.bindings, - Has.Exactly(1).With.Property("isComposite").EqualTo(true).And.With.Property("isPartOfComposite").EqualTo(false).And.With + Has.Exactly(1).With.Property("isComposite").EqualTo(true).And.With.Property("isPartOfComposite") + .EqualTo(false).And.With .Property("path").EqualTo("Axis")); Assert.That(action.bindings, - Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite").EqualTo(true).And.With + Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite") + .EqualTo(true).And.With .Property("path").EqualTo("/a")); Assert.That(action.bindings, - Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite").EqualTo(true).And.With + Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite") + .EqualTo(true).And.With .Property("path").EqualTo("/d")); Assert.That(action.bindings, - Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite").EqualTo(true).And.With + Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite") + .EqualTo(true).And.With .Property("path").EqualTo("/leftArrow")); Assert.That(action.bindings, - Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite").EqualTo(true).And.With + Has.Exactly(1).With.Property("isComposite").EqualTo(false).And.With.Property("isPartOfComposite") + .EqualTo(true).And.With .Property("path").EqualTo("/rightArrow")); } @@ -5564,7 +5631,9 @@ public enum Modification public class ModificationCases : IEnumerable { [Preserve] - public ModificationCases() {} + public ModificationCases() + { + } private static readonly Modification[] ModificationAppliesToSingleActionMap = { @@ -5662,7 +5731,8 @@ public void Actions_CanHandleModification(Modification modification, Func(); @@ -5685,6 +5755,7 @@ bool NeedsFullResolve() case Modification.RemoveDeviceGlobally: return false; } + return true; } @@ -5698,6 +5769,7 @@ bool NeedsActionsToBeDisabled() case Modification.RemoveMap: return true; } + return false; } @@ -5860,7 +5932,12 @@ void ApplyAndVerifyModification() // losing its active control. if (modification == Modification.RemoveDevice || modification == Modification.RemoveDeviceGlobally) { - Assert.That(changes, Is.EqualTo(new[] { InputActionChange.ActionCanceled, InputActionChange.BoundControlsAboutToChange, InputActionChange.BoundControlsChanged })); + Assert.That(changes, + Is.EqualTo(new[] + { + InputActionChange.ActionCanceled, InputActionChange.BoundControlsAboutToChange, + InputActionChange.BoundControlsChanged + })); Assert.That(aButtonAction.phase.IsInProgress(), Is.False); Assert.That(aButtonAction.activeControl, Is.Null); Assert.That(aButtonAction.ReadValue(), Is.EqualTo(0f)); @@ -5869,7 +5946,9 @@ void ApplyAndVerifyModification() // should have kept going uninterrupted. else if (!NeedsFullResolve()) { - Assert.That(changes, Is.EqualTo(new[] { InputActionChange.BoundControlsAboutToChange, InputActionChange.BoundControlsChanged })); + Assert.That(changes, + Is.EqualTo(new[] + { InputActionChange.BoundControlsAboutToChange, InputActionChange.BoundControlsChanged })); Assert.That(aButtonAction.phase.IsInProgress(), Is.True); Assert.That(aButtonAction.activeControl, Is.SameAs(gamepad.buttonSouth)); Assert.That(aButtonAction.ReadValue(), Is.EqualTo(1f)); @@ -5880,7 +5959,8 @@ void ApplyAndVerifyModification() Assert.That(changes, Is.EqualTo(new[] { - InputActionChange.ActionCanceled, InputActionChange.ActionDisabled, InputActionChange.BoundControlsAboutToChange, + InputActionChange.ActionCanceled, InputActionChange.ActionDisabled, + InputActionChange.BoundControlsAboutToChange, InputActionChange.BoundControlsChanged, InputActionChange.ActionEnabled })); } @@ -5966,9 +6046,9 @@ public void Actions_CanRestrictMapsToSpecificDevices() Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad1.leftStick)); Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad2.leftStick)); - map.devices = new[] {gamepad2}; + map.devices = new[] { gamepad2 }; - Assert.That(map.devices, Is.EquivalentTo(new[] { gamepad2})); + Assert.That(map.devices, Is.EquivalentTo(new[] { gamepad2 })); Assert.That(action.controls, Has.Count.EqualTo(1)); Assert.That(action.controls, Has.None.SameAs(gamepad1.leftStick)); Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad2.leftStick)); @@ -5990,14 +6070,14 @@ public void Actions_CanRestrictMapsToSpecificDevices_WhileEnabled() var map = new InputActionMap(); var action = map.AddAction("action", binding: "/leftStick"); - map.devices = new[] {gamepad1}; + map.devices = new[] { gamepad1 }; map.Enable(); Assert.That(action.controls, Has.Count.EqualTo(1)); Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad1.leftStick)); - map.devices = new[] {gamepad2}; + map.devices = new[] { gamepad2 }; Assert.That(action.controls, Has.Count.EqualTo(1)); Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad2.leftStick)); @@ -6022,7 +6102,7 @@ public void Actions_CanRestrictAssetsToSpecificDevices() Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad1.leftStick)); Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad2.leftStick)); - asset.devices = new[] {gamepad2}; + asset.devices = new[] { gamepad2 }; Assert.That(asset.devices, Is.EquivalentTo(new[] { gamepad2 })); Assert.That(map.devices, Is.EquivalentTo(asset.devices)); @@ -6059,7 +6139,7 @@ public void Actions_ChangingDevicesWhileEnabled_CancelsOngoingActions() var map = new InputActionMap(); var action = map.AddAction("action", binding: "/leftStick"); - map.devices = new[] {gamepad1}; + map.devices = new[] { gamepad1 }; map.Enable(); using (var trace = new InputActionTrace()) @@ -6089,7 +6169,7 @@ public void Actions_ChangingDevicesWhileEnabled_CancelsOngoingActions() // in the next update. Set(gamepad2.leftStick, new Vector2(0.234f, 0.345f)); - map.devices = new[] {gamepad2}; + map.devices = new[] { gamepad2 }; actions = trace.ToArray(); Assert.That(actions, Has.Length.EqualTo(1)); @@ -6131,7 +6211,7 @@ public void Actions_ChangingBindingMaskWhileEnabled_CancelsOngoingActions() action.AddBinding("/leftStick", groups: "Default"); action.AddBinding("/rightStick", groups: "Lefty"); - map.bindingMask = new InputBinding {groups = "Default"}; + map.bindingMask = new InputBinding { groups = "Default" }; map.Enable(); using (var trace = new InputActionTrace()) @@ -6157,7 +6237,7 @@ public void Actions_ChangingBindingMaskWhileEnabled_CancelsOngoingActions() trace.Clear(); Set(gamepad2.rightStick, new Vector2(0.234f, 0.345f)); - map.bindingMask = new InputBinding {groups = "Lefty"}; + map.bindingMask = new InputBinding { groups = "Lefty" }; actions = trace.ToArray(); Assert.That(actions, Has.Length.EqualTo(1)); @@ -6199,12 +6279,12 @@ public void Actions_CanAddInteractionsToActions() var wasPerformed = false; action.performed += ctx => - { - Assert.That(wasPerformed, Is.False); - Assert.That(ctx.interaction, Is.TypeOf()); - Assert.That(((TapInteraction)ctx.interaction).duration, Is.EqualTo(0.123).Within(0.00001)); - wasPerformed = true; - }; + { + Assert.That(wasPerformed, Is.False); + Assert.That(ctx.interaction, Is.TypeOf()); + Assert.That(((TapInteraction)ctx.interaction).duration, Is.EqualTo(0.123).Within(0.00001)); + wasPerformed = true; + }; Press(gamepad.buttonSouth); currentTime += 0.1f; @@ -6227,10 +6307,10 @@ public void Actions_CanAddProcessorsToActions() Vector2? receivedVector = null; action.performed += ctx => - { - Assert.That(receivedVector, Is.Null); - receivedVector = ctx.ReadValue(); - }; + { + Assert.That(receivedVector, Is.Null); + receivedVector = ctx.ReadValue(); + }; Set(gamepad.leftStick, Vector2.one); @@ -6253,12 +6333,12 @@ public void Actions_IncompatibleProcessorIsIgnored() float? receivedFloat = null; action.performed += ctx => - { - Assert.That(receivedFloat, Is.Null); - // ConstantVector2TestProcessor processes Vector2s. It would throw an exception when - // trying to use it reading a float if not ignored. - receivedFloat = ctx.ReadValue(); - }; + { + Assert.That(receivedFloat, Is.Null); + // ConstantVector2TestProcessor processes Vector2s. It would throw an exception when + // trying to use it reading a float if not ignored. + receivedFloat = ctx.ReadValue(); + }; Set(gamepad.leftStick, Vector2.one); @@ -6289,10 +6369,10 @@ public void Actions_CanAddProcessorsToBindings() Vector2? receivedVector = null; action.performed += ctx => - { - Assert.That(receivedVector, Is.Null); - receivedVector = ctx.ReadValue(); - }; + { + Assert.That(receivedVector, Is.Null); + receivedVector = ctx.ReadValue(); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.one }); InputSystem.Update(); @@ -6356,18 +6436,20 @@ public void Actions_CanAddScaleProcessor() var receivedValues = new List(); action.performed += ctx => - { - if (ctx.control is ButtonControl) - receivedValues.Add(ctx.ReadValue()); - else - receivedValues.Add(ctx.ReadValue()); - }; + { + if (ctx.control is ButtonControl) + receivedValues.Add(ctx.ReadValue()); + else + receivedValues.Add(ctx.ReadValue()); + }; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.5f, 0.5f), leftTrigger = 0.5f }); + InputSystem.QueueStateEvent(gamepad, + new GamepadState { leftStick = new Vector2(0.5f, 0.5f), leftTrigger = 0.5f }); InputSystem.Update(); Assert.That(receivedValues, Has.Count.EqualTo(2)); - Assert.That(receivedValues, Has.Exactly(1).EqualTo(new StickDeadzoneProcessor().Process(new Vector2(0.5f, 0.5f)) * new Vector2(2, 3))); + Assert.That(receivedValues, + Has.Exactly(1).EqualTo(new StickDeadzoneProcessor().Process(new Vector2(0.5f, 0.5f)) * new Vector2(2, 3))); Assert.That(receivedValues, Has.Exactly(1).EqualTo(0.5f * 2)); } @@ -6378,6 +6460,7 @@ public override float Process(float value, InputControl control) return 1.0f; } } + private class ConstantFloat2TestProcessor : InputProcessor { public override float Process(float value, InputControl control) @@ -6421,10 +6504,10 @@ public void Actions_AddingSameNamedProcessorWithDifferentResult_OverridesOrigina float? receivedValue = null; action.performed += ctx => - { - Assert.That(receivedValue, Is.Null); - receivedValue = ctx.ReadValue(); - }; + { + Assert.That(receivedValue, Is.Null); + receivedValue = ctx.ReadValue(); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.5f }); InputSystem.Update(); @@ -6532,7 +6615,7 @@ public void Actions_WhenDeviceIsRemoved_ReadingValueInActionListenersWillNotThro }; action.Enable(); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 1.0f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 1.0f }); InputSystem.Update(); Assert.That(triggerValue, Is.EqualTo(1.0f)); @@ -6553,7 +6636,8 @@ public void Actions_WhenDeviceIsRemoved_DeviceIsRemovedFromDeviceMask() { // Exclude project-wide actions from this test InputSystem.actions?.Disable(); - InputActionState.DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes + InputActionState + .DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes var gamepad = InputSystem.AddDevice(); @@ -6572,10 +6656,10 @@ public void Actions_WhenDeviceIsRemoved_DeviceIsRemovedFromDeviceMask() var controlsChanged = new List(); InputSystem.onActionChange += (o, change) => - { - if (change == InputActionChange.BoundControlsChanged) - controlsChanged.Add((IInputActionCollection)o); - }; + { + if (change == InputActionChange.BoundControlsChanged) + controlsChanged.Add((IInputActionCollection)o); + }; InputSystem.RemoveDevice(gamepad); @@ -6639,15 +6723,15 @@ public void Actions_ControlsUpdate_WhenDeviceUsagesChange() var action = new InputAction(binding: "{Test}/leftButton"); - Assert.That(action.controls, Is.EquivalentTo(new[] {device1.leftButton})); + Assert.That(action.controls, Is.EquivalentTo(new[] { device1.leftButton })); InputSystem.SetDeviceUsage(device2, "Test"); - Assert.That(action.controls, Is.EquivalentTo(new[] {device1.leftButton, device2.leftButton})); + Assert.That(action.controls, Is.EquivalentTo(new[] { device1.leftButton, device2.leftButton })); InputSystem.SetDeviceUsage(device1, null); - Assert.That(action.controls, Is.EquivalentTo(new[] {device2.leftButton})); + Assert.That(action.controls, Is.EquivalentTo(new[] { device2.leftButton })); } // This case is important for keyboards as a configuration change on the keyboard may imply a change in keyboard @@ -6661,13 +6745,13 @@ public void Actions_ControlsUpdate_WhenDeviceConfigurationChanges() // Bind to key generating a 'q' character. var action = new InputAction(binding: "/#(Q)"); - Assert.That(action.controls, Is.EquivalentTo(new[] {keyboard.qKey})); + Assert.That(action.controls, Is.EquivalentTo(new[] { keyboard.qKey })); // Swap 'a' and 'q'. SetKeyInfo(Key.A, "Q"); SetKeyInfo(Key.Q, "A"); - Assert.That(action.controls, Is.EquivalentTo(new[] {keyboard.aKey})); + Assert.That(action.controls, Is.EquivalentTo(new[] { keyboard.aKey })); } [Test] @@ -6685,7 +6769,7 @@ public void Actions_ControlsUpdate_WhenDeviceConfigurationChanges_AndControlIsNo // Rebind the key. SetKeyInfo(Key.Semicolon, "ö"); - Assert.That(action.controls, Is.EquivalentTo(new[] {keyboard.semicolonKey})); + Assert.That(action.controls, Is.EquivalentTo(new[] { keyboard.semicolonKey })); // Rebind the key back. SetKeyInfo(Key.Semicolon, ";"); @@ -6699,7 +6783,8 @@ public void Actions_WhenControlsUpdate_NotificationIsTriggered_ButOnlyAfterBindi { // Exclude project-wide actions from this test InputSystem.actions?.Disable(); - InputActionState.DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes + InputActionState + .DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes var enabledAction = new InputAction("enabledAction", binding: "/leftTrigger"); @@ -6715,10 +6800,10 @@ public void Actions_WhenControlsUpdate_NotificationIsTriggered_ButOnlyAfterBindi var received = new List(); InputSystem.onActionChange += (obj, change) => - { - received.Add(obj); - received.Add(change); - }; + { + received.Add(obj); + received.Add(change); + }; InputSystem.AddDevice(); @@ -6759,7 +6844,8 @@ public void Actions_WhenControlsUpdateInActionMap_NotificationIsTriggered() { // Exclude project-wide actions from this test InputSystem.actions?.Disable(); - InputActionState.DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes + InputActionState + .DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes var actionMap = new InputActionMap("map"); actionMap.AddAction("action", binding: "/leftTrigger"); @@ -6768,10 +6854,10 @@ public void Actions_WhenControlsUpdateInActionMap_NotificationIsTriggered() var received = new List(); InputSystem.onActionChange += (obj, change) => - { - received.Add(obj); - received.Add(change); - }; + { + received.Add(obj); + received.Add(change); + }; InputSystem.AddDevice(); @@ -6789,7 +6875,8 @@ public void Actions_WhenControlsUpdateInActionAsset_NotificationIsTriggered() { // Exclude project-wide actions from this test InputSystem.actions?.Disable(); - InputActionState.DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes + InputActionState + .DestroyAllActionMapStates(); // Required for `onActionChange` to report correct number of changes var asset = ScriptableObject.CreateInstance(); asset.name = "asset"; @@ -6801,10 +6888,10 @@ public void Actions_WhenControlsUpdateInActionAsset_NotificationIsTriggered() var received = new List(); InputSystem.onActionChange += (obj, change) => - { - received.Add(obj); - received.Add(change); - }; + { + received.Add(obj); + received.Add(change); + }; InputSystem.AddDevice(); @@ -6933,7 +7020,8 @@ public void Actions_WhenInProgress_AddingAndRemovingUnusedDevice_DoesNotAffectAc Set(usedGamepad.leftStick, new Vector2(0.6f, 0.6f)); Assert.That(action.phase, Is.EqualTo(InputActionPhase.Started)); - Assert.That(action.ReadValue(), Is.EqualTo(new Vector2(0.6f, 0.6f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(action.ReadValue(), + Is.EqualTo(new Vector2(0.6f, 0.6f)).Using(Vector2EqualityComparer.Instance)); Assert.That(action.activeControl, Is.SameAs(usedGamepad.leftStick)); using (var trace = new InputActionTrace(action)) @@ -6946,7 +7034,8 @@ public void Actions_WhenInProgress_AddingAndRemovingUnusedDevice_DoesNotAffectAc Assert.That(action.controls, Is.EquivalentTo(new[] { usedGamepad.leftStick, unusedGamepad.leftStick })); Assert.That(trace, Is.Empty); Assert.That(action.phase, Is.EqualTo(InputActionPhase.Started)); - Assert.That(action.ReadValue(), Is.EqualTo(new Vector2(0.6f, 0.6f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(action.ReadValue(), + Is.EqualTo(new Vector2(0.6f, 0.6f)).Using(Vector2EqualityComparer.Instance)); Assert.That(action.activeControl, Is.SameAs(usedGamepad.leftStick)); InputSystem.RemoveDevice(unusedGamepad); @@ -6955,7 +7044,8 @@ public void Actions_WhenInProgress_AddingAndRemovingUnusedDevice_DoesNotAffectAc Assert.That(action.controls, Is.EquivalentTo(new[] { usedGamepad.leftStick })); Assert.That(trace, Is.Empty); Assert.That(action.phase, Is.EqualTo(InputActionPhase.Started)); - Assert.That(action.ReadValue(), Is.EqualTo(new Vector2(0.6f, 0.6f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(action.ReadValue(), + Is.EqualTo(new Vector2(0.6f, 0.6f)).Using(Vector2EqualityComparer.Instance)); Assert.That(action.activeControl, Is.SameAs(usedGamepad.leftStick)); // Finally, add an unused device but then remove the actively used one. @@ -7022,13 +7112,13 @@ public void Actions_CanRegisterNewInteraction() var action = new InputAction(binding: "/leftStick/x", interactions: "test(parm1=5.0)"); action.Enable(); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftStick = new Vector2(0.5f, 0.5f)}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.5f, 0.5f) }); InputSystem.Update(); Assert.That(TestInteraction.s_GotInvoked, Is.True); } - #if UNITY_EDITOR +#if UNITY_EDITOR [Test] [Category("Actions")] public void Actions_RegisteringExistingInteractionUnderNewName_CreatesAlias() @@ -7038,7 +7128,7 @@ public void Actions_RegisteringExistingInteractionUnderNewName_CreatesAlias() Assert.That(InputSystem.manager.interactions.aliases.Contains(new InternedString("TestTest"))); } - #endif // UNITY_EDITOR +#endif // UNITY_EDITOR [Test] [Category("Actions")] @@ -7225,7 +7315,8 @@ public void Actions_CanDistinguishMultiTapAndSingleTapOnSameAction() // // Sounds complicated but what it comes down to is that the system must not reset an interaction's state when it // performed until when the whole action performs or cancels. - var action = new InputAction(binding: "/leftButton", interactions: "multitap(tapTime=0.2,tapDelay=0.2),tap(duration=0.2)"); + var action = new InputAction(binding: "/leftButton", + interactions: "multitap(tapTime=0.2,tapDelay=0.2),tap(duration=0.2)"); action.Enable(); using (var trace = new InputActionTrace(action)) @@ -7251,7 +7342,8 @@ public void Actions_CanDistinguishMultiTapAndSingleTapOnSameAction() Assert.That(trace, Canceled(action, control: mouse.leftButton) .AndThen(Started(action, control: mouse.leftButton, time: 1f)) // Note timestamp here! - .AndThen(Performed(action, control: mouse.leftButton, time: 1.1f))); // Note timestamp here! + .AndThen(Performed(action, control: mouse.leftButton, + time: 1.1f))); // Note timestamp here! trace.Clear(); @@ -7515,7 +7607,7 @@ public void Actions_AddingDeviceWillUpdateControlsOnAction() // Make sure it actually triggers correctly. using (var trace = new InputActionTrace(action)) { - InputSystem.QueueStateEvent(gamepad1, new GamepadState {leftTrigger = 0.5f}); + InputSystem.QueueStateEvent(gamepad1, new GamepadState { leftTrigger = 0.5f }); InputSystem.Update(); var actions = trace.ToArray(); @@ -7528,7 +7620,7 @@ public void Actions_AddingDeviceWillUpdateControlsOnAction() // Also make sure that this device creation path gets it right. runtime.ReportNewInputDevice( - new InputDeviceDescription {product = "Test", deviceClass = "Gamepad"}.ToJson()); + new InputDeviceDescription { product = "Test", deviceClass = "Gamepad" }.ToJson()); InputSystem.Update(); var gamepad2 = (Gamepad)InputSystem.devices.First(x => x.description.product == "Test"); @@ -7663,15 +7755,15 @@ public void Actions_CanTargetSingleDeviceWithMultipleActions() var action2Performed = 0; var action3Performed = 0; - action1.performed += _ => ++ action1Performed; - action2.performed += _ => ++ action2Performed; - action3.performed += _ => ++ action3Performed; + action1.performed += _ => ++action1Performed; + action2.performed += _ => ++action2Performed; + action3.performed += _ => ++action3Performed; action1.Enable(); action2.Enable(); action3.Enable(); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftStick = Vector2.one, rightStick = Vector2.one}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.one, rightStick = Vector2.one }); InputSystem.Update(); Assert.That(action1Performed, Is.EqualTo(1)); @@ -7693,16 +7785,16 @@ public void Actions_CanQueryStartAndPerformTime() action.performed += ctx => - { - receivedStartTime = ctx.startTime; - receivedTime = ctx.time; - }; + { + receivedStartTime = ctx.startTime; + receivedTime = ctx.time; + }; var startTime = 0.123; var endTime = 0.123 + InputSystem.settings.defaultSlowTapTime + 1.0; - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 1.0f}, startTime); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.0f}, endTime); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 1.0f }, startTime); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.0f }, endTime); InputSystem.Update(); Assert.That(receivedStartTime, Is.EqualTo(startTime).Within(0.000001)); @@ -7831,20 +7923,41 @@ public void Actions_CanIterateThroughCompositeBindings_WithAccessor() Assert.That(action.ChangeCompositeBinding("Axis").NextCompositeBinding("Axis").bindingIndex, Is.EqualTo(6)); Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").bindingIndex, Is.EqualTo(2)); Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").bindingIndex, Is.EqualTo(4)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").NextPartBinding("Negative").bindingIndex, Is.EqualTo(3)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive").bindingIndex, Is.EqualTo(5)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").NextPartBinding("Negative").NextPartBinding("Negative").bindingIndex, Is.EqualTo(-1)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive").NextPartBinding("Positive").bindingIndex, Is.EqualTo(-1)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive").NextBinding().bindingIndex, Is.EqualTo(6)); - - Assert.That(action.ChangeCompositeBinding("Axis").PreviousCompositeBinding("Axis").bindingIndex, Is.EqualTo(-1)); - Assert.That(action.ChangeCompositeBinding("Axis").NextCompositeBinding("Axis").PreviousCompositeBinding("Axis").bindingIndex, Is.EqualTo(1)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").NextPartBinding("Negative").bindingIndex, + Is.EqualTo(3)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive").bindingIndex, + Is.EqualTo(5)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").NextPartBinding("Negative") + .NextPartBinding("Negative").bindingIndex, Is.EqualTo(-1)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive") + .NextPartBinding("Positive").bindingIndex, Is.EqualTo(-1)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive").NextBinding() + .bindingIndex, Is.EqualTo(6)); + + Assert.That(action.ChangeCompositeBinding("Axis").PreviousCompositeBinding("Axis").bindingIndex, + Is.EqualTo(-1)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextCompositeBinding("Axis").PreviousCompositeBinding("Axis") + .bindingIndex, Is.EqualTo(1)); Assert.That(action.ChangeCompositeBinding("Axis").PreviousPartBinding("Negative").bindingIndex, Is.EqualTo(-1)); Assert.That(action.ChangeCompositeBinding("Axis").PreviousPartBinding("Positive").bindingIndex, Is.EqualTo(-1)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").PreviousPartBinding("Negative").bindingIndex, Is.EqualTo(-1)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").PreviousPartBinding("Positive").bindingIndex, Is.EqualTo(-1)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").NextPartBinding("Negative").PreviousPartBinding("Negative").bindingIndex, Is.EqualTo(2)); - Assert.That(action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive").PreviousPartBinding("Positive").bindingIndex, Is.EqualTo(4)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").PreviousPartBinding("Negative") + .bindingIndex, Is.EqualTo(-1)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").PreviousPartBinding("Positive") + .bindingIndex, Is.EqualTo(-1)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Negative").NextPartBinding("Negative") + .PreviousPartBinding("Negative").bindingIndex, Is.EqualTo(2)); + Assert.That( + action.ChangeCompositeBinding("Axis").NextPartBinding("Positive").NextPartBinding("Positive") + .PreviousPartBinding("Positive").bindingIndex, Is.EqualTo(4)); } [Test] @@ -7915,12 +8028,19 @@ public void Actions_CanIterateThroughBindings_OfActionMap_WithAccessor() Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().binding.path, Is.EqualTo("/a")); Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().valid, Is.True); Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().bindingIndex, Is.EqualTo(3)); - Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().binding.path, Is.EqualTo("/d")); + Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().binding.path, + Is.EqualTo("/d")); Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().valid, Is.True); - Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().bindingIndex, Is.EqualTo(4)); - Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().binding.path, Is.EqualTo("/scroll/x")); - Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().NextBinding().valid, Is.False); - Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().NextBinding().bindingIndex, Is.EqualTo(-1)); + Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().bindingIndex, + Is.EqualTo(4)); + Assert.That(actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().binding.path, + Is.EqualTo("/scroll/x")); + Assert.That( + actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().NextBinding().valid, + Is.False); + Assert.That( + actionMap.ChangeBinding(0).NextBinding().NextBinding().NextBinding().NextBinding().NextBinding() + .bindingIndex, Is.EqualTo(-1)); } [Test] @@ -7944,7 +8064,10 @@ public void Actions_CanChangeExistingBindingOnAction() action.ChangeBindingWithId(action.bindings[2].id) .WithProcessor("Test"); action.ChangeBindingWithPath("/buttonSouth") - .To(new InputBinding {path = "test"}); // No action but given it's a singleton action, the binding will stay associated with the action. + .To(new InputBinding + { + path = "test" + }); // No action but given it's a singleton action, the binding will stay associated with the action. Assert.That(action.bindings[3].path, Is.EqualTo("/1")); Assert.That(action.bindings[3].interactions, Is.EqualTo("Press")); @@ -8175,7 +8298,8 @@ public void Actions_CanAttemptToLookUpNonExistentActionInAssetByPath() Assert.That(asset.FindAction("Map/Action1"), Is.Null); var map = asset.AddActionMap("Map"); - Assert.That(asset.FindAction("Map/Action1"), Is.Null); // ISXB-895 using a path to find non-existent (NullReferenceException) + Assert.That(asset.FindAction("Map/Action1"), + Is.Null); // ISXB-895 using a path to find non-existent (NullReferenceException) } [Test] @@ -8213,10 +8337,7 @@ public void Actions_CanLookUpActionInAssetByName() // Shouldn't allocate. var map1action1 = "map1/action1"; - Assert.That(() => - { - asset.FindAction(map1action1); - }, Is.Not.AllocatingGCMemory()); + Assert.That(() => { asset.FindAction(map1action1); }, Is.Not.AllocatingGCMemory()); } [Test] @@ -8305,9 +8426,12 @@ public void Actions_CanRemoveActionFromMap() Assert.That(map.actions, Has.Count.EqualTo(2)); Assert.That(map.actions, Has.Exactly(1).SameAs(action1)); Assert.That(map.actions, Has.Exactly(1).SameAs(action3)); - Assert.That(action1.bindings, Is.EquivalentTo(new[] {new InputBinding("/buttonSouth", action: "action1")})); - Assert.That(action2.bindings, Is.EquivalentTo(new[] {new InputBinding("/buttonNorth", action: "action2")})); - Assert.That(action3.bindings, Is.EquivalentTo(new[] {new InputBinding("/buttonWest", action: "action3")})); + Assert.That(action1.bindings, + Is.EquivalentTo(new[] { new InputBinding("/buttonSouth", action: "action1") })); + Assert.That(action2.bindings, + Is.EquivalentTo(new[] { new InputBinding("/buttonNorth", action: "action2") })); + Assert.That(action3.bindings, + Is.EquivalentTo(new[] { new InputBinding("/buttonWest", action: "action3") })); Assert.That(map.bindings, Is.EquivalentTo(new[] { new InputBinding("/buttonSouth", action: "action1"), @@ -8413,9 +8537,11 @@ public void Actions_CanRequireSpecificDevicesForControlScheme() .WithOptionalDevice(""); Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements, Has.Count.EqualTo(3)); - Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[0].controlPath, Is.EqualTo("{LeftHand}")); + Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[0].controlPath, + Is.EqualTo("{LeftHand}")); Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[0].isOptional, Is.False); - Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[1].controlPath, Is.EqualTo("{RightHand}")); + Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[1].controlPath, + Is.EqualTo("{RightHand}")); Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[1].isOptional, Is.False); Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[2].controlPath, Is.EqualTo("")); Assert.That(asset.FindControlScheme("scheme").Value.deviceRequirements[2].isOptional, Is.True); @@ -8477,7 +8603,7 @@ public void Actions_CanPickDevicesThatMatchGivenControlScheme() Assert.That(match.isSuccessfulMatch); Assert.That(match.hasMissingRequiredDevices, Is.False); Assert.That(match.hasMissingOptionalDevices, Is.False); - Assert.That(match.devices, Is.EquivalentTo(new[] {keyboard})); + Assert.That(match.devices, Is.EquivalentTo(new[] { keyboard })); Assert.That(match.ToList(), Has.Count.EqualTo(1)); Assert.That(match.ToList()[0].requirementIndex, Is.EqualTo(0)); Assert.That(match.ToList()[0].control, Is.SameAs(keyboard)); @@ -8490,7 +8616,7 @@ public void Actions_CanPickDevicesThatMatchGivenControlScheme() Assert.That(match.isSuccessfulMatch); Assert.That(match.hasMissingRequiredDevices, Is.False); Assert.That(match.hasMissingOptionalDevices, Is.False); - Assert.That(match.devices, Is.EquivalentTo(new[] {keyboard})); + Assert.That(match.devices, Is.EquivalentTo(new[] { keyboard })); Assert.That(match.ToList(), Has.Count.EqualTo(1)); Assert.That(match.ToList()[0].requirementIndex, Is.EqualTo(0)); Assert.That(match.ToList()[0].control, Is.SameAs(keyboard)); @@ -8503,7 +8629,7 @@ public void Actions_CanPickDevicesThatMatchGivenControlScheme() Assert.That(match.isSuccessfulMatch); Assert.That(match.hasMissingRequiredDevices, Is.False); Assert.That(match.hasMissingOptionalDevices); - Assert.That(match.devices, Is.EquivalentTo(new[] {gamepad1})); + Assert.That(match.devices, Is.EquivalentTo(new[] { gamepad1 })); Assert.That(match.ToList(), Has.Count.EqualTo(2)); Assert.That(match.ToList()[0].requirementIndex, Is.EqualTo(0)); Assert.That(match.ToList()[0].control, Is.SameAs(gamepad1)); @@ -8519,7 +8645,7 @@ public void Actions_CanPickDevicesThatMatchGivenControlScheme() Assert.That(match.isSuccessfulMatch); Assert.That(match.hasMissingRequiredDevices, Is.False); Assert.That(match.hasMissingOptionalDevices, Is.False); - Assert.That(match.devices, Is.EquivalentTo(new[] {gamepad1, gamepad2})); + Assert.That(match.devices, Is.EquivalentTo(new[] { gamepad1, gamepad2 })); Assert.That(match.ToList(), Has.Count.EqualTo(2)); Assert.That(match.ToList()[0].requirementIndex, Is.EqualTo(0)); Assert.That(match.ToList()[0].control, Is.SameAs(gamepad1)); @@ -8631,7 +8757,7 @@ public void Actions_CanPickDevicesThatMatchGivenControlScheme() Assert.That(match.isSuccessfulMatch); Assert.That(match.hasMissingRequiredDevices, Is.False); Assert.That(match.hasMissingOptionalDevices, Is.False); - Assert.That(match.devices, Is.EquivalentTo(new[] {gamepad1})); + Assert.That(match.devices, Is.EquivalentTo(new[] { gamepad1 })); Assert.That(match.ToList(), Has.Count.EqualTo(2)); Assert.That(match.ToList()[0].requirementIndex, Is.EqualTo(0)); Assert.That(match.ToList()[0].control, Is.SameAs(gamepad1.leftStick)); @@ -8758,15 +8884,17 @@ public void Actions_CanFindControlSchemeUsingGivenDevice() var mouse = InputSystem.AddDevice(); var touch = InputSystem.AddDevice(); - Assert.That(InputControlScheme.FindControlSchemeForDevice(gamepad, new[] {scheme1, scheme2}), + Assert.That(InputControlScheme.FindControlSchemeForDevice(gamepad, new[] { scheme1, scheme2 }), Is.EqualTo(scheme1)); Assert.That(InputControlScheme.FindControlSchemeForDevice(keyboard, new[] { scheme1, scheme2 }), Is.Null); Assert.That(InputControlScheme.FindControlSchemeForDevice(mouse, new[] { scheme1, scheme2 }), Is.Null); - Assert.That(InputControlScheme.FindControlSchemeForDevice(touch, new[] {scheme1, scheme2}), + Assert.That(InputControlScheme.FindControlSchemeForDevice(touch, new[] { scheme1, scheme2 }), Is.Null); - Assert.That(InputControlScheme.FindControlSchemeForDevices(new InputDevice[] { keyboard, mouse }, new[] { scheme1, scheme2 }), + Assert.That( + InputControlScheme.FindControlSchemeForDevices(new InputDevice[] { keyboard, mouse }, + new[] { scheme1, scheme2 }), Is.EqualTo(scheme2)); } @@ -8788,11 +8916,17 @@ public void Actions_WhenFindingControlSchemeUsingGivenDevice_MostSpecificControl var ps4Controller = InputSystem.AddDevice(); var xboxController = InputSystem.AddDevice(); - Assert.That(InputControlScheme.FindControlSchemeForDevice(genericGamepad, new[] { genericGamepadScheme, ps4GamepadScheme, xboxGamepadScheme, mouseScheme }), + Assert.That( + InputControlScheme.FindControlSchemeForDevice(genericGamepad, + new[] { genericGamepadScheme, ps4GamepadScheme, xboxGamepadScheme, mouseScheme }), Is.EqualTo(genericGamepadScheme)); - Assert.That(InputControlScheme.FindControlSchemeForDevice(ps4Controller, new[] { genericGamepadScheme, ps4GamepadScheme, xboxGamepadScheme, mouseScheme }), + Assert.That( + InputControlScheme.FindControlSchemeForDevice(ps4Controller, + new[] { genericGamepadScheme, ps4GamepadScheme, xboxGamepadScheme, mouseScheme }), Is.EqualTo(ps4GamepadScheme)); - Assert.That(InputControlScheme.FindControlSchemeForDevice(xboxController, new[] { genericGamepadScheme, ps4GamepadScheme, xboxGamepadScheme, mouseScheme }), + Assert.That( + InputControlScheme.FindControlSchemeForDevice(xboxController, + new[] { genericGamepadScheme, ps4GamepadScheme, xboxGamepadScheme, mouseScheme }), Is.EqualTo(xboxGamepadScheme)); #endif } @@ -8818,12 +8952,12 @@ public void Actions_CanMaskOutBindingsByBindingGroup_OnAction() Assert.That(action.controls, Has.Exactly(1).SameAs(keyboard.aKey)); Assert.That(action.controls, Has.Exactly(1).SameAs(mouse.leftButton)); - action.bindingMask = new InputBinding {groups = "gamepad"}; + action.bindingMask = new InputBinding { groups = "gamepad" }; Assert.That(action.controls, Has.Count.EqualTo(2)); Assert.That(action.controls, Has.Exactly(1).SameAs(gamepad.buttonSouth)); Assert.That(action.controls, Has.Exactly(1).SameAs(mouse.leftButton)); - Assert.That(action.bindingMask, Is.EqualTo(new InputBinding {groups = "gamepad"})); + Assert.That(action.bindingMask, Is.EqualTo(new InputBinding { groups = "gamepad" })); action.bindingMask = null; @@ -8841,7 +8975,7 @@ public void Actions_CanMaskOutBindingsByBindingGroup_OnAction_WhenEnabled() var action = new InputAction { - bindingMask = new InputBinding {groups = "a"} + bindingMask = new InputBinding { groups = "a" } }; action.AddBinding("/buttonSouth").WithGroup("a"); @@ -8849,7 +8983,7 @@ public void Actions_CanMaskOutBindingsByBindingGroup_OnAction_WhenEnabled() action.Enable(); - action.bindingMask = new InputBinding {groups = "b"}; + action.bindingMask = new InputBinding { groups = "b" }; using (var trace = new InputActionTrace(action)) { @@ -8892,7 +9026,7 @@ public void Actions_CanMaskOutBindingsByBindingGroup_OnActionMap() Assert.That(action1.controls, Has.Exactly(1).SameAs(keyboard.aKey)); Assert.That(action2.controls, Has.Exactly(1).SameAs(mouse.leftButton)); - map.bindingMask = new InputBinding {groups = "gamepad"}; + map.bindingMask = new InputBinding { groups = "gamepad" }; Assert.That(action1.controls, Has.Count.EqualTo(1)); Assert.That(action1.controls, Has.Exactly(1).SameAs(gamepad.buttonSouth)); @@ -8920,14 +9054,14 @@ public void Actions_CanMaskOutBindingsByBindingGroup_OnAsset() var gamepad = InputSystem.AddDevice(); var keyboard = InputSystem.AddDevice(); - asset.bindingMask = new InputBinding {groups = "gamepad"}; + asset.bindingMask = new InputBinding { groups = "gamepad" }; Assert.That(action1.controls, Has.Count.EqualTo(1)); Assert.That(action1.controls, Has.Exactly(1).SameAs(gamepad.leftStick)); Assert.That(action2.controls, Has.Count.EqualTo(1)); Assert.That(action2.controls, Has.Exactly(1).SameAs(gamepad.rightStick)); - asset.bindingMask = new InputBinding {groups = "keyboard"}; + asset.bindingMask = new InputBinding { groups = "keyboard" }; Assert.That(action1.controls, Has.Count.EqualTo(1)); Assert.That(action1.controls, Has.Exactly(1).SameAs(keyboard.aKey)); @@ -8969,7 +9103,8 @@ public void Actions_WhenMaskingByGroup_BindingsNotInAnyGroupWillBeActive() public void Actions_CanGetDisplayStringForBindings() { Assert.That(new InputBinding("/space").ToDisplayString(), Is.EqualTo("Space")); - Assert.That(new InputBinding("/buttonSouth").ToDisplayString(), Is.EqualTo(GamepadState.ButtonSouthShortDisplayName)); + Assert.That(new InputBinding("/buttonSouth").ToDisplayString(), + Is.EqualTo(GamepadState.ButtonSouthShortDisplayName)); Assert.That(new InputBinding("/leftButton").ToDisplayString(), Is.EqualTo("LMB")); Assert.That(new InputBinding().ToDisplayString(), Is.EqualTo("")); } @@ -8980,7 +9115,8 @@ public void Actions_CanGetDisplayStringForBindings_UsingDisplayNamesFromActualDe { var psController = InputSystem.AddDevice(); - Assert.That(new InputBinding("/buttonSouth").ToDisplayString(control: psController), Is.EqualTo("Cross")); + Assert.That(new InputBinding("/buttonSouth").ToDisplayString(control: psController), + Is.EqualTo("Cross")); } // The following functionality is the basis for associating images with binding strings. For example, when looking at the @@ -8996,7 +9132,8 @@ public void Actions_CanGetDisplayStringForBindings_AndGetDeviceLayoutAndControlP { var psController = InputSystem.AddDevice(); - new InputBinding("/buttonSouth").ToDisplayString(out var layoutA, out var controlA, control: psController); + new InputBinding("/buttonSouth").ToDisplayString(out var layoutA, out var controlA, + control: psController); new InputBinding("/buttonSouth").ToDisplayString(out var layoutB, out var controlB); Assert.That(layoutA, Is.EqualTo("DualShockGamepad")); @@ -9010,8 +9147,9 @@ public void Actions_CanGetDisplayStringForBindings_AndGetDeviceLayoutAndControlP public void Actions_CanGetDisplayStringForBindings_AndIgnoreBindingOverrides() { Assert.That( - new InputBinding { path = "/leftButton", overridePath = "/space" }.ToDisplayString(InputBinding - .DisplayStringOptions.IgnoreBindingOverrides), Is.EqualTo("LMB")); + new InputBinding { path = "/leftButton", overridePath = "/space" }.ToDisplayString( + InputBinding + .DisplayStringOptions.IgnoreBindingOverrides), Is.EqualTo("LMB")); } [Test] @@ -9265,7 +9403,8 @@ public void Actions_WhenGettingDisplayTextForBindingsOnAction_InteractionsAreSho action3.AddBinding("/buttonSouth"); Assert.That(action1.GetBindingDisplayString(), Is.EqualTo("Hold " + GamepadState.ButtonSouthShortDisplayName)); - Assert.That(action2.GetBindingDisplayString(), Is.EqualTo("Hold or Press " + GamepadState.ButtonSouthShortDisplayName)); + Assert.That(action2.GetBindingDisplayString(), + Is.EqualTo("Hold or Press " + GamepadState.ButtonSouthShortDisplayName)); Assert.That(action3.GetBindingDisplayString(), Is.EqualTo("Hold " + GamepadState.ButtonSouthShortDisplayName)); // Can suppress. @@ -9276,7 +9415,8 @@ public void Actions_WhenGettingDisplayTextForBindingsOnAction_InteractionsAreSho [Test] [Category("Actions")] [Ignore("TODO")] - public void TODO_Actions_WhenGettingDisplayTextForBindingsOnAction_CanGetQualificationsForEachIndividualStringComponent() + public void + TODO_Actions_WhenGettingDisplayTextForBindingsOnAction_CanGetQualificationsForEachIndividualStringComponent() { //interaction:Hold gamepad:A //is this actually useful? the use case here is localization but not sure this is the most usable approach @@ -9323,7 +9463,7 @@ public void Actions_CanOverrideBindings() var wasPerformed = false; action.performed += ctx => wasPerformed = true; - InputSystem.QueueStateEvent(gamepad, new GamepadState {rightTrigger = 1}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { rightTrigger = 1 }); InputSystem.Update(); Assert.That(wasPerformed); @@ -9341,13 +9481,13 @@ public void Actions_CanDeactivateBindingsUsingOverrides() var wasPerformed = false; action.performed += ctx => wasPerformed = true; - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 1}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 1 }); InputSystem.Update(); Assert.That(wasPerformed, Is.False); } - #if UNITY_EDITOR +#if UNITY_EDITOR [Test] [Category("Actions")] public void Actions_RegisteringExistingCompositeUnderNewName_CreatesAlias() @@ -9357,9 +9497,9 @@ public void Actions_RegisteringExistingCompositeUnderNewName_CreatesAlias() Assert.That(InputSystem.manager.composites.aliases.Contains(new InternedString("TestTest"))); } - #endif // UNITY_EDITOR +#endif // UNITY_EDITOR - #pragma warning disable CS0649 +#pragma warning disable CS0649 private class CompositeWithParameters : InputBindingComposite { public int intParameter; @@ -9483,7 +9623,8 @@ public void Actions_CanHaveCompositesWithoutControls() // the composite that in fact has no controls bound to its parts. Set(gamepad.leftTrigger, 0.6f); Set(gamepad.rightTrigger, 0.7f); - Set(gamepad.rightTrigger, 0.4f); // Disambiguation now needs to find leftTrigger; should not be thrown off track by the empty composite. + Set(gamepad.rightTrigger, + 0.4f); // Disambiguation now needs to find leftTrigger; should not be thrown off track by the empty composite. Assert.That(action.ReadValue(), Is.EqualTo(0.6f)); } @@ -9525,7 +9666,7 @@ public void Actions_CanCreateAxisComposite() trace.SubscribeTo(action); // Negative. - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.345f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.345f }); InputSystem.Update(); Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: -0.345f) @@ -9534,7 +9675,7 @@ public void Actions_CanCreateAxisComposite() trace.Clear(); // Positive. - InputSystem.QueueStateEvent(gamepad, new GamepadState {rightTrigger = 0.456f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { rightTrigger = 0.456f }); InputSystem.Update(); // Bit of an odd case. leftTrigger and rightTrigger have both changed state here so @@ -9559,13 +9700,13 @@ public void Actions_CanCreateAxisComposite_AndDetermineWhichSideWins() var gamepad = InputSystem.AddDevice(); var action = new InputAction(); - action.AddCompositeBinding($"Axis(whichSideWins={(int) AxisComposite.WhichSideWins.Neither})") + action.AddCompositeBinding($"Axis(whichSideWins={(int)AxisComposite.WhichSideWins.Neither})") .With("Negative", "/leftTrigger", groups: "neither") .With("Positive", "/rightTrigger", groups: "neither"); - action.AddCompositeBinding($"Axis(whichSideWins={(int) AxisComposite.WhichSideWins.Positive})") + action.AddCompositeBinding($"Axis(whichSideWins={(int)AxisComposite.WhichSideWins.Positive})") .With("Negative", "/leftTrigger", groups: "positive") .With("Positive", "/rightTrigger", groups: "positive"); - action.AddCompositeBinding($"Axis(whichSideWins={(int) AxisComposite.WhichSideWins.Negative})") + action.AddCompositeBinding($"Axis(whichSideWins={(int)AxisComposite.WhichSideWins.Negative})") .With("Negative", "/leftTrigger", groups: "negative") .With("Positive", "/rightTrigger", groups: "negative"); @@ -9578,7 +9719,7 @@ public void Actions_CanCreateAxisComposite_AndDetermineWhichSideWins() // Neither wins. // Start with one side actuated, then actuate both. - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.345f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.345f }); InputSystem.Update(); Assert.That(trace, Started(action, value: -0.345f) @@ -9586,7 +9727,7 @@ public void Actions_CanCreateAxisComposite_AndDetermineWhichSideWins() trace.Clear(); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.345f, rightTrigger = 0.543f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.345f, rightTrigger = 0.543f }); InputSystem.Update(); Assert.That(trace, Canceled(action, value: 0f)); @@ -9596,24 +9737,26 @@ public void Actions_CanCreateAxisComposite_AndDetermineWhichSideWins() // Positive wins. action.bindingMask = InputBinding.MaskByGroup("positive"); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.123f, rightTrigger = 0.234f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.123f, rightTrigger = 0.234f }); InputSystem.Update(); // We get a started and performed when switching to the right trigger and then another performed // when the right trigger changes value. Assert.That(trace, - Started(action, value: 0.543f).AndThen(Performed(action, value: 0.543f)).AndThen(Performed(action, value: 0.234f))); + Started(action, value: 0.543f).AndThen(Performed(action, value: 0.543f)) + .AndThen(Performed(action, value: 0.234f))); trace.Clear(); // Negative wins. action.bindingMask = InputBinding.MaskByGroup("negative"); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.567f, rightTrigger = 0.765f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.567f, rightTrigger = 0.765f }); InputSystem.Update(); Assert.That(trace, - Canceled(action, value: 0f).AndThen(Started(action, value: -0.123f)).AndThen(Performed(action, value: -0.123f)) + Canceled(action, value: 0f).AndThen(Started(action, value: -0.123f)) + .AndThen(Performed(action, value: -0.123f)) .AndThen(Performed(action, value: -0.567f))); } } @@ -9799,85 +9942,10 @@ public void Actions_CanCreateVector2Composite_FromAnalogControls() Set(gamepad.leftStick, new Vector2(-0.234f, 0.345f)); - Assert.That(analogAction.ReadValue(), Is.EqualTo(new Vector2(-0.234f, 0.345f)).Using(Vector2EqualityComparer.Instance)); - Assert.That(digitalAction.ReadValue(), Is.EqualTo(new Vector2(-1, 1)).Using(Vector2EqualityComparer.Instance)); - } - - [Test] - [Category("Actions")] - public void Actions_Vector2Composite_RespectsButtonPressurePoint() - { - // The stick has deadzones on the up/down/left/right buttons to get rid of stick - // noise. For this test, simplify things by getting rid of deadzones. - InputSystem.settings.defaultDeadzoneMin = 0; - InputSystem.settings.defaultDeadzoneMax = 1; - - var gamepad = InputSystem.AddDevice(); - - // Set up classic WASD control. - var action = new InputAction(); - action.AddCompositeBinding("Dpad") - .With("Up", "/leftstick/up") - .With("Down", "/leftstick/down") - .With("Left", "/leftstick/left") - .With("Right", "/leftstick/right"); - action.Enable(); - - Vector2? value = null; - action.performed += ctx => { value = ctx.ReadValue(); }; - action.canceled += ctx => { value = ctx.ReadValue(); }; - - var pressPoint = gamepad.leftStick.up.pressPointOrDefault; - - // Up. - value = null; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up }); - InputSystem.Update(); - - Assert.That(value, Is.Not.Null); - Assert.That(value.Value, Is.EqualTo(Vector2.up)); - - // Up (slightly above press point) - value = null; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up * pressPoint * 1.01f }); - InputSystem.Update(); - - Assert.That(value, Is.Not.Null); - Assert.That(value.Value, Is.EqualTo(Vector2.up)); - - // Up (slightly below press point) - value = null; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up * pressPoint * 0.99f }); - InputSystem.Update(); - - Assert.That(value, Is.Not.Null); - Assert.That(value.Value, Is.EqualTo(Vector2.zero)); - - // Up left. - value = null; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up + Vector2.left }); - InputSystem.Update(); - - Assert.That(value, Is.Not.Null); - Assert.That(value.Value.x, Is.EqualTo((Vector2.up + Vector2.left).normalized.x).Within(0.00001)); - Assert.That(value.Value.y, Is.EqualTo((Vector2.up + Vector2.left).normalized.y).Within(0.00001)); - - // Up left (up slightly above press point) - value = null; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up * pressPoint * 1.01f + Vector2.left }); - InputSystem.Update(); - - Assert.That(value, Is.Not.Null); - Assert.That(value.Value.x, Is.EqualTo((Vector2.up + Vector2.left).normalized.x).Within(0.00001)); - Assert.That(value.Value.y, Is.EqualTo((Vector2.up + Vector2.left).normalized.y).Within(0.00001)); - - // Up left (up slightly below press point) - value = null; - InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = Vector2.up * pressPoint * 0.99f + Vector2.left }); - InputSystem.Update(); - - Assert.That(value, Is.Not.Null); - Assert.That(value.Value, Is.EqualTo(Vector2.left)); + Assert.That(analogAction.ReadValue(), + Is.EqualTo(new Vector2(-0.234f, 0.345f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(digitalAction.ReadValue(), + Is.EqualTo(new Vector2(-1, 1)).Using(Vector2EqualityComparer.Instance)); } [Test] @@ -10162,7 +10230,7 @@ public void Actions_Vector2Composite_TriggersActionOnlyOnceWhenMultipleComponent action.Enable(); var performedCount = 0; - action.performed += ctx => ++ performedCount; + action.performed += ctx => ++performedCount; // Interaction should be processed only once. LogAssert.Expect(LogType.Assert, "LogInteraction.Process"); @@ -10335,14 +10403,8 @@ public void Actions_WithCompositeWithMultipleInteractions_Works() IInputInteraction performedInteraction = null; IInputInteraction canceledInteraction = null; - action.performed += ctx => - { - performedInteraction = ctx.interaction; - }; - action.canceled += ctx => - { - canceledInteraction = ctx.interaction; - }; + action.performed += ctx => { performedInteraction = ctx.interaction; }; + action.canceled += ctx => { canceledInteraction = ctx.interaction; }; // PressRelease AW trigger a tap currentTime = 0; @@ -10651,14 +10713,14 @@ public void Actions_CanCreateCompositeWithVector2PartBinding() Assert.That(trace, Started(action, gamepad.leftStick, new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f))) - .AndThen(Performed(action, gamepad.leftStick, new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f))))); + .AndThen(Performed(action, gamepad.leftStick, + new StickDeadzoneProcessor().Process(new Vector2(0.123f, 0.234f))))); } } private class CompositeAskingForSourceControl : InputBindingComposite { - [InputControl(layout = "Button")] - public int button; + [InputControl(layout = "Button")] public int button; public override float ReadValue(ref InputBindingCompositeContext context) { @@ -10780,11 +10842,11 @@ public void Actions_CanCreateButtonWithTwoModifiersComposite() Set(gamepad.leftStick, new Vector2(0, 0.75f)); Assert.That(trace, Started(action, - value: new AxisDeadzoneProcessor().Process(0.75f), - control: gamepad.leftStick.up) + value: new AxisDeadzoneProcessor().Process(0.75f), + control: gamepad.leftStick.up) .AndThen(Performed(action, - value: new AxisDeadzoneProcessor().Process(0.75f), - control: gamepad.leftStick.up))); + value: new AxisDeadzoneProcessor().Process(0.75f), + control: gamepad.leftStick.up))); trace.Clear(); @@ -10795,11 +10857,11 @@ public void Actions_CanCreateButtonWithTwoModifiersComposite() // one of the constituents change. Assert.That(trace, Performed(action, - value: new AxisDeadzoneProcessor().Process(0.75f), - control: gamepad.dpad.up) + value: new AxisDeadzoneProcessor().Process(0.75f), + control: gamepad.dpad.up) .AndThen(Performed(action, - value: new AxisDeadzoneProcessor().Process(0.75f), - control: gamepad.leftTrigger))); + value: new AxisDeadzoneProcessor().Process(0.75f), + control: gamepad.leftTrigger))); trace.Clear(); @@ -11018,7 +11080,8 @@ public void Actions_CanCreateVector3Composite() Set((ButtonControl)device["backward"], 1f); Assert.That(analog.ReadValue(), - Is.EqualTo(new Vector3(0.901f - 0.567f, 0.456f - 0.890f, 0.789f - 1f)).Using(Vector3EqualityComparer.Instance)); + Is.EqualTo(new Vector3(0.901f - 0.567f, 0.456f - 0.890f, 0.789f - 1f)) + .Using(Vector3EqualityComparer.Instance)); Assert.That(digitalNormalized.ReadValue(), Is.EqualTo(Vector3.zero).Using(Vector3EqualityComparer.Instance)); Assert.That(digital.ReadValue(), @@ -11266,7 +11329,7 @@ public void Actions_OnActionWithMultipleBindings_ControlWithHighestActuationIsTr Assert.That(passThroughAction.WasPerformedThisFrame(), Is.True); Assert.That(passThroughAction.activeControl, Is.SameAs(gamepad.rightTrigger)); - Set(gamepad.leftTrigger, 0f); + Set(gamepad.leftTrigger, 0f); Assert.That(buttonAction.WasPerformedThisFrame(), Is.False); Assert.That(buttonAction.WasReleasedThisFrame(), Is.False); @@ -11340,7 +11403,7 @@ public void Actions_ApplyingNullOverride_IsSameAsRemovingOverride() { var action = new InputAction(binding: "/gamepad/leftTrigger"); - action.ApplyBindingOverride(new InputBinding {path = "/gamepad/rightTrigger", interactions = "tap"}); + action.ApplyBindingOverride(new InputBinding { path = "/gamepad/rightTrigger", interactions = "tap" }); action.ApplyBindingOverride(new InputBinding()); Assert.That(action.bindings[0].overridePath, Is.Null); Assert.That(action.bindings[0].overrideInteractions, Is.Null); @@ -11426,7 +11489,7 @@ public void Actions_ApplyingOverride_UpdatesControls() public void Actions_CanRestoreDefaultForSpecificOverride() { var action = new InputAction(binding: "/gamepad/leftTrigger"); - var bindingOverride = new InputBinding {path = "/gamepad/rightTrigger"}; + var bindingOverride = new InputBinding { path = "/gamepad/rightTrigger" }; action.ApplyBindingOverride(bindingOverride); action.RemoveBindingOverride(bindingOverride); @@ -11516,8 +11579,10 @@ public void Actions_CanEnableAndDisableEntireMap_EvenWhenBindingsReferToNonExist // Also try the same for a composite binding. map.AddBinding(new InputBinding { path = "1DAxis", isComposite = true, action = "DoesNotExist" }); - map.AddBinding(new InputBinding { name = "Positive", path = "/leftTrigger", isPartOfComposite = true }); - map.AddBinding(new InputBinding { name = "Negative", path = "/rightTrigger", isPartOfComposite = true }); + map.AddBinding(new InputBinding + { name = "Positive", path = "/leftTrigger", isPartOfComposite = true }); + map.AddBinding( + new InputBinding { name = "Negative", path = "/rightTrigger", isPartOfComposite = true }); Assert.That(() => map.Enable(), Throws.Nothing); @@ -11663,8 +11728,8 @@ public void Actions_DisablingAllActions_RemovesAllTheirStateMonitors() // Not the most elegant test as we reach into internals here but with the // current API, it's not possible to enumerate monitors from outside. Assert.That(InputSystem.manager.m_StateChangeMonitors, - Has.All.Matches( - (InputManager.StateChangeMonitorsForDevice x) => x.memoryRegions.All(r => r.sizeInBits == 0))); + Has.All.Matches((InputManager.StateChangeMonitorsForDevice x) => + x.memoryRegions.All(r => r.sizeInBits == 0))); } // https://fogbugz.unity3d.com/f/cases/1367442/ @@ -11689,19 +11754,19 @@ public void Actions_EnablingAndDisablingRepeatedly_DoesNotAllocate() var kProfilerRegion2 = "Actions_EnablingAndDisablingRepeatedly_DoesNotAllocate_ENABLE"; Assert.That(() => - { - Profiler.BeginSample(kProfilerRegion1); - actions.Disable(); - Profiler.EndSample(); - }, + { + Profiler.BeginSample(kProfilerRegion1); + actions.Disable(); + Profiler.EndSample(); + }, Is.Not.AllocatingGCMemory()); Assert.That(() => - { - Profiler.BeginSample(kProfilerRegion2); - actions.Enable(); - Profiler.EndSample(); - }, + { + Profiler.BeginSample(kProfilerRegion2); + actions.Enable(); + Profiler.EndSample(); + }, Is.Not.AllocatingGCMemory()); } @@ -11728,34 +11793,39 @@ public void Actions_CanDriveFreeLookFromGamepadStickAndPointerDelta() { trace.SubscribeTo(action); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftStick = new Vector2(0.123f, 0.234f)}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.123f, 0.234f) }); InputSystem.Update(); var actions = trace.ToArray(); Assert.That(actions, Has.Length.EqualTo(2)); Assert.That(actions[0].phase, Is.EqualTo(InputActionPhase.Started)); - Assert.That(actions[0].ReadValue(), Is.EqualTo(new Vector2(0.123f, 0.234f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(actions[0].ReadValue(), + Is.EqualTo(new Vector2(0.123f, 0.234f)).Using(Vector2EqualityComparer.Instance)); Assert.That(actions[0].control, Is.SameAs(gamepad.leftStick)); Assert.That(actions[1].phase, Is.EqualTo(InputActionPhase.Performed)); - Assert.That(actions[1].ReadValue(), Is.EqualTo(new Vector2(0.123f, 0.234f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(actions[1].ReadValue(), + Is.EqualTo(new Vector2(0.123f, 0.234f)).Using(Vector2EqualityComparer.Instance)); Assert.That(actions[1].control, Is.SameAs(gamepad.leftStick)); trace.Clear(); InputSystem.QueueStateEvent(gamepad, new GamepadState()); - InputSystem.QueueStateEvent(mouse, new MouseState {delta = new Vector2(0.234f, 0.345f)}); + InputSystem.QueueStateEvent(mouse, new MouseState { delta = new Vector2(0.234f, 0.345f) }); InputSystem.Update(); actions = trace.ToArray(); Assert.That(actions, Has.Length.EqualTo(3)); Assert.That(actions[0].phase, Is.EqualTo(InputActionPhase.Canceled)); - Assert.That(actions[0].ReadValue(), Is.EqualTo(Vector2.zero).Using(Vector2EqualityComparer.Instance)); + Assert.That(actions[0].ReadValue(), + Is.EqualTo(Vector2.zero).Using(Vector2EqualityComparer.Instance)); Assert.That(actions[0].control, Is.SameAs(gamepad.leftStick)); Assert.That(actions[1].phase, Is.EqualTo(InputActionPhase.Started)); - Assert.That(actions[1].ReadValue(), Is.EqualTo(new Vector2(0.234f, 0.345f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(actions[1].ReadValue(), + Is.EqualTo(new Vector2(0.234f, 0.345f)).Using(Vector2EqualityComparer.Instance)); Assert.That(actions[1].control, Is.SameAs(mouse.delta)); Assert.That(actions[2].phase, Is.EqualTo(InputActionPhase.Performed)); - Assert.That(actions[2].ReadValue(), Is.EqualTo(new Vector2(0.234f, 0.345f)).Using(Vector2EqualityComparer.Instance)); + Assert.That(actions[2].ReadValue(), + Is.EqualTo(new Vector2(0.234f, 0.345f)).Using(Vector2EqualityComparer.Instance)); Assert.That(actions[2].control, Is.SameAs(mouse.delta)); trace.Clear(); @@ -11768,7 +11838,8 @@ public void Actions_CanDriveFreeLookFromGamepadStickAndPointerDelta() actions = trace.ToArray(); Assert.That(actions, Has.Length.EqualTo(1)); Assert.That(actions[0].phase, Is.EqualTo(InputActionPhase.Canceled)); - Assert.That(actions[0].ReadValue(), Is.EqualTo(Vector2.zero).Using(Vector2EqualityComparer.Instance)); + Assert.That(actions[0].ReadValue(), + Is.EqualTo(Vector2.zero).Using(Vector2EqualityComparer.Instance)); Assert.That(actions[0].control, Is.SameAs(mouse.delta)); } } @@ -11813,7 +11884,8 @@ public void Process(ref InputInteractionContext context) if (context.control.CheckStateIsAtDefault()) { Debug.Log("TestInteractionCheckingDefaultState.Process(default)"); - Assert.That(context.control.ReadValueAsObject(), Is.EqualTo(new AxisDeadzoneProcessor().Process(0.1234f)).Within(0.00001)); + Assert.That(context.control.ReadValueAsObject(), + Is.EqualTo(new AxisDeadzoneProcessor().Process(0.1234f)).Within(0.00001)); } } @@ -11847,7 +11919,8 @@ public void Actions_InteractionContextRespectsCustomDefaultStates() var gamepad = (Gamepad)InputSystem.AddDevice("CustomGamepad"); Set(gamepad.leftStick, Vector2.zero); // This is non-default for this gamepad. - var action = new InputAction(binding: "/leftStick/x", interactions: "testInteractionCheckingDefaultState"); + var action = new InputAction(binding: "/leftStick/x", + interactions: "testInteractionCheckingDefaultState"); action.Enable(); LogAssert.Expect(LogType.Log, "TestInteractionCheckingDefaultState.Process(default)"); @@ -11960,7 +12033,7 @@ public void Actions_CanUseTouchWithActions() var touchscreen = InputSystem.AddDevice(); - var primaryTouchAction = new InputAction("PrimaryTouch" , binding: "/primaryTouch/position"); + var primaryTouchAction = new InputAction("PrimaryTouch", binding: "/primaryTouch/position"); var touch0Action = new InputAction("Touch0", binding: "/touch0/position"); var touch1Action = new InputAction("Touch1", binding: "/touch1/position"); var positionAction = new InputAction("Position", binding: "/position"); @@ -11987,7 +12060,8 @@ public void Actions_CanUseTouchWithActions() Assert.That(trace, Started(primaryTouchAction, touchscreen.primaryTouch.position, new Vector2(0.123f, 0.234f)) - .AndThen(Performed(primaryTouchAction, touchscreen.primaryTouch.position, new Vector2(0.123f, 0.234f))) + .AndThen(Performed(primaryTouchAction, touchscreen.primaryTouch.position, + new Vector2(0.123f, 0.234f))) .AndThen(Started(positionAction, touchscreen.position, new Vector2(0.123f, 0.234f))) .AndThen(Performed(positionAction, touchscreen.position, new Vector2(0.123f, 0.234f))) .AndThen(Started(touch0Action, touchscreen.touches[0].position, new Vector2(0.123f, 0.234f))) @@ -12105,7 +12179,7 @@ public void Actions_CanDrivePointerInputFromTouchPenAndMouse() // Perform touch move. BeginTouch(1, new Vector2(1, 2), time: 0.3, queueEventOnly: true); // Spare us one extra delta reset. - MoveTouch(1, new Vector2(10, 20), time: 0.4, queueEventOnly: true); // Same here. + MoveTouch(1, new Vector2(10, 20), time: 0.4, queueEventOnly: true); // Same here. EndTouch(1, new Vector2(10, 20), time: 0.5, queueEventOnly: true); // Also releases press. InputSystem.Update(); InputSystem.Update(); // Reset delta. @@ -12115,7 +12189,8 @@ public void Actions_CanDrivePointerInputFromTouchPenAndMouse() .AndThen(Started(pressAction, touchscreen.press, 1, time: 0.3)) .AndThen(Performed(pressAction, touchscreen.press, 1, time: 0.3)) .AndThen(Performed(positionAction, touchscreen.position, new Vector2(10, 20), time: 0.4)) - .AndThen(Performed(pressAction, touchscreen.press, 1, time: 0.4)) // Because `press` is tied to `phase` which changes state twice (but not value). + .AndThen(Performed(pressAction, touchscreen.press, 1, + time: 0.4)) // Because `press` is tied to `phase` which changes state twice (but not value). .AndThen(Started(deltaAction, touchscreen.delta, new Vector2(9, 18), time: 0.4)) .AndThen(Performed(deltaAction, touchscreen.delta, new Vector2(9, 18), time: 0.4)) .AndThen(Canceled(pressAction, touchscreen.press, 0, time: 0.5)) @@ -12440,26 +12515,19 @@ public struct PointerInput public class PointerInputComposite : InputBindingComposite { - [InputControl(layout = "Button")] - public int contact; + [InputControl(layout = "Button")] public int contact; - [InputControl(layout = "Vector2")] - public int position; + [InputControl(layout = "Vector2")] public int position; - [InputControl(layout = "Vector2")] - public int tilt; + [InputControl(layout = "Vector2")] public int tilt; - [InputControl(layout = "Vector2")] - public int radius; + [InputControl(layout = "Vector2")] public int radius; - [InputControl(layout = "Axis")] - public int pressure; + [InputControl(layout = "Axis")] public int pressure; - [InputControl(layout = "Axis")] - public int twist; + [InputControl(layout = "Axis")] public int twist; - [InputControl(layout = "Integer")] - public int inputId; + [InputControl(layout = "Integer")] public int inputId; public override PointerInput ReadValue(ref InputBindingCompositeContext context) { @@ -12489,7 +12557,8 @@ public override PointerInput ReadValue(ref InputBindingCompositeContext context) [Category("Actions")] [TestCase(true)] [TestCase(false)] - public void Actions_WithMultipleCompositeBindings_WithoutEvaluateMagnitude_Works(bool prepopulateTouchesBeforeEnablingAction) + public void Actions_WithMultipleCompositeBindings_WithoutEvaluateMagnitude_Works( + bool prepopulateTouchesBeforeEnablingAction) { InputSystem.RegisterBindingComposite(); @@ -12664,8 +12733,8 @@ public void Actions_CanHandleDeviceDisconnectWithControlSchemesAndReconnect() var action = map.AddAction(name: "Toggle", InputActionType.Button); action.AddBinding("/leftTrigger"); - action.started += context => ++ started; - action.performed += context => ++ performed; + action.started += context => ++started; + action.performed += context => ++performed; action.canceled += (context) => { // In reported issue, map state is changed from cancellation callback. @@ -12703,4 +12772,4 @@ public void Actions_CanHandleDeviceDisconnectWithControlSchemesAndReconnect() InputSystem.Update(); Assert.That(started, Is.EqualTo(2)); } -} +} \ No newline at end of file diff --git a/Assets/Tests/InputSystem/CoreTests_Controls.cs b/Assets/Tests/InputSystem/CoreTests_Controls.cs index 2bcd768c6b..9aef285a5c 100644 --- a/Assets/Tests/InputSystem/CoreTests_Controls.cs +++ b/Assets/Tests/InputSystem/CoreTests_Controls.cs @@ -214,8 +214,8 @@ public void Controls_CanHaveStickDeadzones() InputSystem.RegisterLayout(json); var device = (Gamepad)InputSystem.AddDevice("MyDevice"); - var firstState = new GamepadState {leftStick = new Vector2(0.05f, 0.05f)}; - var secondState = new GamepadState {leftStick = new Vector2(0.5f, 0.5f)}; + var firstState = new GamepadState { leftStick = new Vector2(0.05f, 0.05f) }; + var secondState = new GamepadState { leftStick = new Vector2(0.5f, 0.5f) }; InputSystem.QueueStateEvent(device, firstState); InputSystem.Update(); @@ -257,12 +257,12 @@ public void Controls_CanHaveAxisDeadzones() ////NOTE: Unfortunately, this relies on an internal method ATM. var processor = device.leftTrigger.TryGetProcessor(); - InputSystem.QueueStateEvent(device, new GamepadState {leftTrigger = 0.05f}); + InputSystem.QueueStateEvent(device, new GamepadState { leftTrigger = 0.05f }); InputSystem.Update(); Assert.That(device.leftTrigger.ReadValue(), Is.Zero.Within(0.0001)); - InputSystem.QueueStateEvent(device, new GamepadState {leftTrigger = 0.5f}); + InputSystem.QueueStateEvent(device, new GamepadState { leftTrigger = 0.5f }); InputSystem.Update(); Assert.That(device.leftTrigger.ReadValue(), @@ -284,13 +284,13 @@ public void Controls_CanChangeDefaultDeadzoneValuesOnTheFly() Set(gamepad.leftStick, new Vector2(0.5f, 0.5f)); Assert.That(gamepad.leftStick.ReadValue(), - Is.EqualTo(new StickDeadzoneProcessor {min = 0.1f, max = 0.9f}.Process(new Vector2(0.5f, 0.5f)))); + Is.EqualTo(new StickDeadzoneProcessor { min = 0.1f, max = 0.9f }.Process(new Vector2(0.5f, 0.5f)))); InputSystem.settings.defaultDeadzoneMin = 0.2f; InputSystem.settings.defaultDeadzoneMax = 0.8f; Assert.That(gamepad.leftStick.ReadValue(), - Is.EqualTo(new StickDeadzoneProcessor {min = 0.2f, max = 0.8f}.Process(new Vector2(0.5f, 0.5f)))); + Is.EqualTo(new StickDeadzoneProcessor { min = 0.2f, max = 0.8f }.Process(new Vector2(0.5f, 0.5f)))); } [Test] @@ -299,7 +299,7 @@ public void Controls_SticksProvideAccessToHalfAxes() { var gamepad = InputSystem.AddDevice(); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftStick = new Vector2(0.5f, 0.5f)}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(0.5f, 0.5f) }); InputSystem.Update(); Assert.That(gamepad.leftStick.up.ReadValue(), @@ -311,7 +311,7 @@ public void Controls_SticksProvideAccessToHalfAxes() Assert.That(gamepad.leftStick.left.ReadValue(), Is.EqualTo(new AxisDeadzoneProcessor().Process(0.0f))); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftStick = new Vector2(-0.5f, -0.5f)}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftStick = new Vector2(-0.5f, -0.5f) }); InputSystem.Update(); Assert.That(gamepad.leftStick.up.ReadValue(), @@ -468,7 +468,7 @@ public unsafe void Controls_ValueIsReadFromStateMemoryOnlyWhenControlHasBeenMark gamepad.ApplyParameterChanges(); Assert.That(gamepad.leftTrigger.value, Is.EqualTo(0.5f)); - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.75f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.75f }); InputSystem.Update(); // but this time, we updated state through the system which *does* set the stale flag on controls that @@ -603,15 +603,16 @@ public void Controls_CanReadValueFromStateEvents() var receivedCalls = 0; InputSystem.onEvent += (eventPtr, device) => - { - ++receivedCalls; - float value; - Assert.That(gamepad.leftTrigger.ReadValueFromEvent(eventPtr, out value), Is.True); - Assert.That(value, Is.EqualTo(0.234f).Within(0.00001)); - Assert.That(gamepad.leftTrigger.ReadValueFromEventAsObject(eventPtr), Is.EqualTo(0.234f).Within(0.00001)); - }; - - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.234f}); + { + ++receivedCalls; + float value; + Assert.That(gamepad.leftTrigger.ReadValueFromEvent(eventPtr, out value), Is.True); + Assert.That(value, Is.EqualTo(0.234f).Within(0.00001)); + Assert.That(gamepad.leftTrigger.ReadValueFromEventAsObject(eventPtr), + Is.EqualTo(0.234f).Within(0.00001)); + }; + + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.234f }); InputSystem.Update(); Assert.That(receivedCalls, Is.EqualTo(1)); @@ -644,11 +645,11 @@ public void Controls_ReadingValueFromStateEvent_ReturnsDefaultValueForControlsNo float? value = null; InputSystem.onEvent += (eventPtr, _) => - { - Assert.That(value, Is.Null); - ((AxisControl)device["extraControl"]).ReadValueFromEvent(eventPtr, out var eventValue); - value = eventValue; - }; + { + Assert.That(value, Is.Null); + ((AxisControl)device["extraControl"]).ReadValueFromEvent(eventPtr, out var eventValue); + value = eventValue; + }; InputSystem.QueueStateEvent(device, new GamepadState()); InputSystem.Update(); @@ -666,10 +667,10 @@ public void Controls_CanWriteValueIntoStateEvents() var receivedCalls = 0; InputSystem.onEvent += (eventPtr, device) => - { - ++receivedCalls; - gamepad.leftTrigger.WriteValueIntoEvent(0.1234f, eventPtr); - }; + { + ++receivedCalls; + gamepad.leftTrigger.WriteValueIntoEvent(0.1234f, eventPtr); + }; InputSystem.QueueStateEvent(gamepad, new GamepadState()); InputSystem.Update(); @@ -687,10 +688,10 @@ public void Controls_CanWriteValueIntoDeltaStateEvents() var receivedCalls = 0; InputSystem.onEvent += (eventPtr, device) => - { - ++receivedCalls; - gamepad.leftTrigger.WriteValueIntoEvent(0.1234f, eventPtr); - }; + { + ++receivedCalls; + gamepad.leftTrigger.WriteValueIntoEvent(0.1234f, eventPtr); + }; InputSystem.QueueDeltaStateEvent(gamepad.leftTrigger, 0.8765f); InputSystem.Update(); @@ -758,7 +759,7 @@ public void Controls_DpadVectorsAreCircular() var gamepad = InputSystem.AddDevice(); // Up. - InputSystem.QueueStateEvent(gamepad, new GamepadState {buttons = 1 << (int)GamepadButton.DpadUp}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { buttons = 1 << (int)GamepadButton.DpadUp }); InputSystem.Update(); Assert.That(gamepad.dpad.ReadValue(), Is.EqualTo(Vector2.up)); @@ -775,7 +776,7 @@ public void Controls_DpadVectorsAreCircular() Assert.That(gamepad.dpad.ReadValue().y, Is.EqualTo((Vector2.up + Vector2.left).normalized.y).Within(0.00001)); // Left. - InputSystem.QueueStateEvent(gamepad, new GamepadState {buttons = 1 << (int)GamepadButton.DpadLeft}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { buttons = 1 << (int)GamepadButton.DpadLeft }); InputSystem.Update(); Assert.That(gamepad.dpad.ReadValue(), Is.EqualTo(Vector2.left)); @@ -792,7 +793,7 @@ public void Controls_DpadVectorsAreCircular() Assert.That(gamepad.dpad.ReadValue().y, Is.EqualTo((Vector2.down + Vector2.left).normalized.y).Within(0.00001)); // Down. - InputSystem.QueueStateEvent(gamepad, new GamepadState {buttons = 1 << (int)GamepadButton.DpadDown}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { buttons = 1 << (int)GamepadButton.DpadDown }); InputSystem.Update(); Assert.That(gamepad.dpad.ReadValue(), Is.EqualTo(Vector2.down)); @@ -811,7 +812,7 @@ public void Controls_DpadVectorsAreCircular() Is.EqualTo((Vector2.down + Vector2.right).normalized.y).Within(0.00001)); // Right. - InputSystem.QueueStateEvent(gamepad, new GamepadState {buttons = 1 << (int)GamepadButton.DpadRight}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { buttons = 1 << (int)GamepadButton.DpadRight }); InputSystem.Update(); Assert.That(gamepad.dpad.ReadValue(), Is.EqualTo(Vector2.right)); @@ -947,6 +948,7 @@ public void Controls_FindControl_FindsControlDespiteTurkishCulture() Assert.That(matches, Has.Count.EqualTo(1)); Assert.That(matches, Has.Exactly(1).SameAs(gamepad.leftStick)); } + Thread.CurrentThread.CurrentCulture = culture; } @@ -973,6 +975,7 @@ public void Controls_CanParseControlPath(string path, params string[] parts) case "displayName": return a.displayName == nameAndValue[1]; case "wildcard": return a.isWildcard; } + return false; }); }), Has.All.True); @@ -1153,100 +1156,6 @@ public void Controls_CanFindControlsUsingWildcards_InMiddleOfNames() } } - [Test] - [Category("Controls")] - public void Controls_CanDetermineIfControlIsPressed() - { - InputSystem.settings.defaultButtonPressPoint = 0.5f; - - var gamepad = InputSystem.AddDevice(); - - Set(gamepad.leftStick, Vector2.one); - Set(gamepad.leftTrigger, 0.6f); - Press(gamepad.buttonSouth); - - //// https://jira.unity3d.com/browse/ISX-926 - ////REVIEW: IsPressed() should probably be renamed. As is apparent from the calls here, it's not always - //// readily apparent that the way it is defined ("actuation level at least at button press threshold") - //// does not always connect to what it intuitively means for the specific control. - - Assert.That(gamepad.leftTrigger.IsPressed(), Is.True); - Assert.That(gamepad.rightTrigger.IsPressed(), Is.False); - Assert.That(gamepad.buttonSouth.IsPressed(), Is.True); - Assert.That(gamepad.buttonNorth.IsPressed(), Is.False); - Assert.That(gamepad.leftStick.IsPressed(), Is.True); // Note how this diverges from the actual meaning of "is the left stick pressed?" - Assert.That(gamepad.rightStick.IsPressed(), Is.False); - - // https://fogbugz.unity3d.com/f/cases/1374024/ - // Calling it on the entire device should be false. - Assert.That(gamepad.IsPressed(), Is.False); - } - - [Test] - [Category("Controls")] - public void Controls_CanCustomizeDefaultButtonPressPoint() - { - var gamepad = InputSystem.AddDevice(); - - InputSystem.settings.defaultButtonPressPoint = 0.4f; - - Set(gamepad.leftTrigger, 0.39f); - - Assert.That(gamepad.leftTrigger.isPressed, Is.False); - - Set(gamepad.leftTrigger, 0.4f); - - Assert.That(gamepad.leftTrigger.isPressed, Is.True); - - InputSystem.settings.defaultButtonPressPoint = 0.5f; - - Assert.That(gamepad.leftTrigger.isPressed, Is.False); - - InputSystem.settings.defaultButtonPressPoint = 0; - - Assert.That(gamepad.leftTrigger.isPressed, Is.True); - - // Setting the trigger to 0 requires the system to be "smart" enough to - // figure out that 0 as a default button press point doesn't make sense - // and that instead the press point should clamp off at some low, non-zero value. - // https://fogbugz.unity3d.com/f/cases/1349002/ - Set(gamepad.leftTrigger, 0f); - - Assert.That(gamepad.leftTrigger.isPressed, Is.False); - - Set(gamepad.leftTrigger, 0.001f); - - Assert.That(gamepad.leftTrigger.isPressed, Is.True); - - InputSystem.settings.defaultButtonPressPoint = -1; - Set(gamepad.leftTrigger, 0f); - - Assert.That(gamepad.leftTrigger.isPressed, Is.False); - } - - [Test] - [Category("Controls")] - public void Controls_CanCustomizePressPointOfGamepadTriggers() - { - var json = @" - { - ""name"" : ""CustomGamepad"", - ""extend"" : ""Gamepad"", - ""controls"" : [ - { - ""name"" : ""rightTrigger"", - ""parameters"" : ""pressPoint=0.2"" - } - ] - } - "; - - InputSystem.RegisterLayout(json); - var gamepad = InputDevice.Build("CustomGamepad"); - - Assert.That(gamepad.rightTrigger.pressPoint, Is.EqualTo(0.2f).Within(0.0001f)); - } - [Test] [Category("Controls")] public void Controls_DisplayNameDefaultsToControlName() @@ -1287,12 +1196,16 @@ public void Controls_CanTurnControlPathIntoHumanReadableText() { Assert.That(InputControlPath.ToHumanReadableString("*/{PrimaryAction}"), Is.EqualTo("PrimaryAction [Any]")); Assert.That(InputControlPath.ToHumanReadableString("/leftStick"), Is.EqualTo("Left Stick [Gamepad]")); - Assert.That(InputControlPath.ToHumanReadableString("/leftStick/x"), Is.EqualTo("Left Stick/X [Gamepad]")); + Assert.That(InputControlPath.ToHumanReadableString("/leftStick/x"), + Is.EqualTo("Left Stick/X [Gamepad]")); Assert.That(InputControlPath.ToHumanReadableString("*/leftStick"), Is.EqualTo("leftStick [Any]")); Assert.That(InputControlPath.ToHumanReadableString("*/{PrimaryMotion}/x"), Is.EqualTo("PrimaryMotion/x [Any]")); - Assert.That(InputControlPath.ToHumanReadableString("/buttonSouth"), Is.EqualTo("Button South [Gamepad]")); - Assert.That(InputControlPath.ToHumanReadableString("/buttonSouth"), Is.EqualTo("A [Xbox Controller]")); - Assert.That(InputControlPath.ToHumanReadableString("/touch4/tap"), Is.EqualTo("Touch #4/Tap [Touchscreen]")); + Assert.That(InputControlPath.ToHumanReadableString("/buttonSouth"), + Is.EqualTo("Button South [Gamepad]")); + Assert.That(InputControlPath.ToHumanReadableString("/buttonSouth"), + Is.EqualTo("A [Xbox Controller]")); + Assert.That(InputControlPath.ToHumanReadableString("/touch4/tap"), + Is.EqualTo("Touch #4/Tap [Touchscreen]")); Assert.That(InputControlPath.ToHumanReadableString("{LeftHand}/position"), #if ENABLE_VR || UNITY_GAMECORE // The layout settings for the display name to change from XRController to XR Controller @@ -1312,10 +1225,12 @@ public void Controls_CanTurnControlPathIntoHumanReadableText() // UseShortName. Assert.That( - InputControlPath.ToHumanReadableString("/buttonSouth", InputControlPath.HumanReadableStringOptions.UseShortNames), + InputControlPath.ToHumanReadableString("/buttonSouth", + InputControlPath.HumanReadableStringOptions.UseShortNames), Is.EqualTo(GamepadState.ButtonSouthShortDisplayName + " [Gamepad]")); Assert.That( - InputControlPath.ToHumanReadableString("/leftButton", InputControlPath.HumanReadableStringOptions.UseShortNames), + InputControlPath.ToHumanReadableString("/leftButton", + InputControlPath.HumanReadableStringOptions.UseShortNames), Is.EqualTo("LMB [Mouse]")); } @@ -1328,7 +1243,8 @@ public void Controls_CanTurnControlPathIntoHumanReadableText_UsingDisplayNamesFr // Pretend 'a' key is mapped to 'q' in current keyboard layout. SetKeyInfo(Key.A, "q"); - Assert.That(InputControlPath.ToHumanReadableString("/a", control: Keyboard.current), Is.EqualTo("Q [Keyboard]")); + Assert.That(InputControlPath.ToHumanReadableString("/a", control: Keyboard.current), + Is.EqualTo("Q [Keyboard]")); } private class DeviceWithoutAnyControls : InputDevice @@ -1342,8 +1258,10 @@ public void Controls_CanTurnControlPathIntoHumanReadableText_EvenIfLayoutCannotB // This one will throw as the layout will result in a zero-size memory block. InputSystem.RegisterLayout(); - Assert.That(InputControlPath.ToHumanReadableString("/leftStick"), Is.EqualTo("leftStick [UnknownGamepad]")); - Assert.That(InputControlPath.ToHumanReadableString("/control"), Is.EqualTo("control [DeviceWithoutAnyControls]")); + Assert.That(InputControlPath.ToHumanReadableString("/leftStick"), + Is.EqualTo("leftStick [UnknownGamepad]")); + Assert.That(InputControlPath.ToHumanReadableString("/control"), + Is.EqualTo("control [DeviceWithoutAnyControls]")); } [Test] @@ -1419,7 +1337,7 @@ public void Controls_CanKeepListsOfControls_WithoutAllocatingGCMemory() Assert.That(list[3], Is.SameAs(keyboard)); Assert.That(() => list[4], Throws.TypeOf()); Assert.That(list.ToArray(), - Is.EquivalentTo(new InputControl[] {gamepad.leftStick, null, keyboard.spaceKey, keyboard})); + Is.EquivalentTo(new InputControl[] { gamepad.leftStick, null, keyboard.spaceKey, keyboard })); Assert.That(list.Contains(gamepad.leftStick)); Assert.That(list.Contains(null)); Assert.That(list.Contains(keyboard.spaceKey)); @@ -1436,42 +1354,49 @@ public void Controls_CanKeepListsOfControls_WithoutAllocatingGCMemory() Assert.That(list[0], Is.SameAs(gamepad.leftStick)); Assert.That(list[1], Is.SameAs(keyboard.spaceKey)); Assert.That(() => list[2], Throws.TypeOf()); - Assert.That(list.ToArray(), Is.EquivalentTo(new InputControl[] {gamepad.leftStick, keyboard.spaceKey})); + Assert.That(list.ToArray(), Is.EquivalentTo(new InputControl[] { gamepad.leftStick, keyboard.spaceKey })); Assert.That(list.Contains(gamepad.leftStick)); Assert.That(!list.Contains(null)); Assert.That(list.Contains(keyboard.spaceKey)); Assert.That(!list.Contains(keyboard)); - list.AddRange(new InputControl[] {keyboard.aKey, keyboard.bKey}, count: 1, destinationIndex: 0); + list.AddRange(new InputControl[] { keyboard.aKey, keyboard.bKey }, count: 1, destinationIndex: 0); Assert.That(list.Count, Is.EqualTo(3)); Assert.That(list.Capacity, Is.EqualTo(4)); Assert.That(list, Is.EquivalentTo(new InputControl[] - {keyboard.aKey, gamepad.leftStick, keyboard.spaceKey})); + { keyboard.aKey, gamepad.leftStick, keyboard.spaceKey })); - list.AddRange(new InputControl[] {keyboard.bKey, keyboard.cKey}); + list.AddRange(new InputControl[] { keyboard.bKey, keyboard.cKey }); Assert.That(list.Count, Is.EqualTo(5)); Assert.That(list.Capacity, Is.EqualTo(10)); Assert.That(list, Is.EquivalentTo(new InputControl[] - {keyboard.aKey, gamepad.leftStick, keyboard.spaceKey, keyboard.bKey, keyboard.cKey})); + { keyboard.aKey, gamepad.leftStick, keyboard.spaceKey, keyboard.bKey, keyboard.cKey })); - using (var toAdd = new InputControlList(gamepad.buttonNorth, gamepad.buttonEast, gamepad.buttonWest)) + using (var toAdd = + new InputControlList(gamepad.buttonNorth, gamepad.buttonEast, gamepad.buttonWest)) list.AddSlice(toAdd, count: 1, destinationIndex: 1, sourceIndex: 2); Assert.That(list.Count, Is.EqualTo(6)); Assert.That(list.Capacity, Is.EqualTo(10)); Assert.That(list, Is.EquivalentTo(new InputControl[] - {keyboard.aKey, gamepad.buttonWest, gamepad.leftStick, keyboard.spaceKey, keyboard.bKey, keyboard.cKey})); + { + keyboard.aKey, gamepad.buttonWest, gamepad.leftStick, keyboard.spaceKey, keyboard.bKey, + keyboard.cKey + })); list[0] = keyboard.zKey; Assert.That(list, Is.EquivalentTo(new InputControl[] - {keyboard.zKey, gamepad.buttonWest, gamepad.leftStick, keyboard.spaceKey, keyboard.bKey, keyboard.cKey})); + { + keyboard.zKey, gamepad.buttonWest, gamepad.leftStick, keyboard.spaceKey, keyboard.bKey, + keyboard.cKey + })); list.Clear(); @@ -1580,7 +1505,8 @@ static void CheckChildControls(Type type, HashSet checkedTypes) if (!checkedTypes.Add(type)) return; - foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) + foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | + BindingFlags.DeclaredOnly)) { if (!typeof(InputControl).IsAssignableFrom(property.PropertyType)) continue; @@ -1595,14 +1521,16 @@ static void CheckChildControls(Type type, HashSet checkedTypes) if (typeof(InputDevice).IsAssignableFrom(type)) { // Properties on an InputDevice can be protected, since the precompiled layout will be an inherited class - var inputDeviceMessage = $"A public or protected setter is required on {type.FullName}.{property.Name} in order to support precompiled layouts"; + var inputDeviceMessage = + $"A public or protected setter is required on {type.FullName}.{property.Name} in order to support precompiled layouts"; Assert.That(setMethod, Is.Not.Null, inputDeviceMessage); Assert.That(setMethod.IsPrivate, Is.Not.True, inputDeviceMessage); Assert.That(setMethod.IsAssembly, Is.Not.True, inputDeviceMessage); continue; } - var inputControlMessage = $"A public setter is required on {type.FullName}.{property.Name} in order to support precompiled layouts"; + var inputControlMessage = + $"A public setter is required on {type.FullName}.{property.Name} in order to support precompiled layouts"; Assert.That(setMethod, Is.Not.Null, inputControlMessage); Assert.That(setMethod.IsPublic, Is.True, inputControlMessage); } @@ -1633,4 +1561,4 @@ public void Controls_MatchPathComponent_CollapsesConsecutiveWildcards() $"Index should advance past entire pattern for '{path}'"); } } -} +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/Documentation~/RespondingToActions.md b/Packages/com.unity.inputsystem/Documentation~/RespondingToActions.md index f9f405b16d..ce1063ad6d 100644 --- a/Packages/com.unity.inputsystem/Documentation~/RespondingToActions.md +++ b/Packages/com.unity.inputsystem/Documentation~/RespondingToActions.md @@ -84,9 +84,10 @@ Finally, there are three methods you can use to poll for button presses and rele |Method|Description| |------|-----------| -|[`InputAction.IsPressed()`](xref:UnityEngine.InputSystem.InputAction.IsPressed)|True if the level of [actuation](xref:UnityEngine.InputSystem.InputControl.EvaluateMagnitude) on the action has crossed the [press point](xref:UnityEngine.InputSystem.InputSettings.defaultButtonPressPoint) and did not yet fall to or below the [release threshold](xref:UnityEngine.InputSystem.InputSettings.buttonReleaseThreshold).| -|[`InputAction.WasPressedThisFrame()`](xref:UnityEngine.InputSystem.InputAction.WasPressedThisFrame)|True if the level of [actuation](xref:UnityEngine.InputSystem.InputControl.EvaluateMagnitude) on the action has, at any point during the current frame, reached or gone above the [press point](xref:UnityEngine.InputSystem.InputSettings.defaultButtonPressPoint).| -|[`InputAction.WasReleasedThisFrame()`](xref:UnityEngine.InputSystem.InputAction.WasReleasedThisFrame)|True if the level of [actuation](xref:UnityEngine.InputSystem.InputControl.EvaluateMagnitude) on the action has, at any point during the current frame, gone from being at or above the [press point](xref:UnityEngine.InputSystem.InputSettings.defaultButtonPressPoint) to at or below the [release threshold](xref:UnityEngine.InputSystem.InputSettings.buttonReleaseThreshold).| +|[`InputAction.IsPressed()`](xref:UnityEngine.InputSystem.InputAction.IsPressed)|True if the level of [actuation](xref:UnityEngine.InputSystem.InputControl.EvaluateMagnitude) on the action has crossed the applicable press point and did not yet fall to or below the [release threshold](xref:UnityEngine.InputSystem.InputSettings.buttonReleaseThreshold).| +|[`InputAction.WasPressedThisFrame()`](xref:UnityEngine.InputSystem.InputAction.WasPressedThisFrame)|True if the level of [actuation](xref:UnityEngine.InputSystem.InputControl.EvaluateMagnitude) on the action has, at any point during the current frame, reached or gone above the applicable press point.| +|[`InputAction.WasReleasedThisFrame()`](xref:UnityEngine.InputSystem.InputAction.WasReleasedThisFrame)|True if the level of [actuation](xref:UnityEngine.InputSystem.InputControl.EvaluateMagnitude) on the action has, at any point during the current frame, gone from being at or above the applicable press point to at or below the [release threshold](xref:UnityEngine.InputSystem.InputSettings.buttonReleaseThreshold).| +The applicable press point is chosen from, in order: a positive [pressPoint](xref:UnityEngine.InputSystem.Controls.IActuationPressPoint.pressPoint) on the driving control when it implements [IActuationPressPoint](xref:UnityEngine.InputSystem.Controls.IActuationPressPoint) (for example [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl), [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control), or [StickControl](xref:UnityEngine.InputSystem.Controls.StickControl)); otherwise, if the binding defines a [Press](xref:UnityEngine.InputSystem.Interactions.PressInteraction) interaction with `pressPoint` greater than zero, that value (same as the interaction threshold); otherwise [defaultButtonPressPoint](xref:UnityEngine.InputSystem.InputSettings.defaultButtonPressPoint). On [composites](xref:input-system-action-bindings#composite-bindings), interaction parameters are taken from the composite binding. This example uses three actions called Shield, Teleport and Submit (which are not included in the [default actions](xref:project-wide-actions#the-default-actions)): diff --git a/Packages/com.unity.inputsystem/InputSystem/Controls/IActuationPressPoint.cs b/Packages/com.unity.inputsystem/InputSystem/Controls/IActuationPressPoint.cs new file mode 100644 index 0000000000..79d250b772 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Controls/IActuationPressPoint.cs @@ -0,0 +1,26 @@ +namespace UnityEngine.InputSystem.Controls +{ + /// + /// A control that can supply a custom actuation press threshold (and a resolved default) for + /// press-style checks such as . + /// + /// + /// Implemented by and (including + /// ). A negative or zero means "use default + /// resolution" via ; see each type for details. + /// + /// + /// + public interface IActuationPressPoint + { + /// + /// Layout-configured press threshold, or a value less than or equal to zero when unset. + /// + float pressPoint { get; } + + /// + /// Effective press threshold: when set, otherwise the global default. + /// + float pressPointOrDefault { get; } + } +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Controls/IActuationPressPoint.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Controls/IActuationPressPoint.cs.meta new file mode 100644 index 0000000000..93da388e78 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Controls/IActuationPressPoint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f3c2a1e9d704b5a8c6e7f901234abcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputAction.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputAction.cs index d7cb1eb6aa..1669f9f73a 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputAction.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputAction.cs @@ -604,6 +604,7 @@ public unsafe InputControl activeControl if (controlIndex != InputActionState.kInvalidIndex) return state.controls[controlIndex]; } + return null; } } @@ -686,6 +687,7 @@ public bool wantsInitialStateCheck /// ProfilerMarker for measuring the enabling/disabling of InputActions. /// static readonly ProfilerMarker k_InputActionEnableProfilerMarker = new ProfilerMarker("InputAction.Enable"); + static readonly ProfilerMarker k_InputActionDisableProfilerMarker = new ProfilerMarker("InputAction.Disable"); /// @@ -759,7 +761,7 @@ public InputAction() /// /// public InputAction(string name = null, InputActionType type = default, string binding = null, - string interactions = null, string processors = null, string expectedControlType = null) + string interactions = null, string processors = null, string expectedControlType = null) { m_Name = name; m_Type = type; @@ -834,6 +836,7 @@ public override string ToString() str += control.path; isFirst = false; } + str += "]"; } @@ -1133,13 +1136,13 @@ public unsafe float GetControlMagnitude() public void Reset() { var state = GetOrCreateActionMap().m_State; - state?.ResetActionState(m_ActionIndexInState, toPhase: enabled ? InputActionPhase.Waiting : InputActionPhase.Disabled, hardReset: true); + state?.ResetActionState(m_ActionIndexInState, + toPhase: enabled ? InputActionPhase.Waiting : InputActionPhase.Disabled, hardReset: true); } /// - /// Check whether the current actuation of the action has crossed the button press threshold (see - /// ) and has not yet fallen back below the - /// release threshold (see ). + /// Check whether the current actuation of the action has crossed the press threshold (see remarks) and + /// has not yet fallen back below the release threshold (see ). /// /// True if the action is considered to be in "pressed" state, false otherwise. /// @@ -1155,8 +1158,13 @@ public void Reset() /// to a , the control will be considered "pressed" once the magnitude /// of the Vector2 of the control has crossed the press threshold. /// - /// Finally, note that custom button press points of controls (see ) - /// are respected and will take precedence over . + /// Press threshold (based on for the driving control): controls implementing + /// (including , , and ) + /// use / when a positive + /// control pressPoint is set. If not set on the control but the binding has a + /// with greater than zero, that value is used so this + /// API stays aligned with the interaction. For composite bindings, interaction parameters are read from the composite binding. + /// Otherwise is used. /// /// /// @@ -1171,7 +1179,9 @@ public void Reset() /// was disabled even if the control is still actuated. /// /// + /// /// + /// /// /// /// @@ -1183,6 +1193,7 @@ public unsafe bool IsPressed() var actionStatePtr = &state.actionStates[m_ActionIndexInState]; return actionStatePtr->isPressed; } + return false; } @@ -1199,6 +1210,7 @@ public unsafe bool IsInProgress() var actionStatePtr = &state.actionStates[m_ActionIndexInState]; return actionStatePtr->phase.IsInProgress(); } + return false; } @@ -1213,17 +1225,15 @@ private int ExpectedFrame() } /// - /// Returns true if the action's value crossed the press threshold (see ) - /// at any point in the frame. + /// Returns true if the action's value crossed the press threshold (see remarks) at any point in the frame. /// /// True if the action was pressed this frame. /// /// This method is different from in that it is not bound /// to . Instead, if the action's level of actuation (that is, the level of /// magnitude -- see -- of the control(s) bound - /// to the action) crossed the press threshold (see ) - /// at any point in the frame, this method will return true. It will do so even if there is an - /// interaction on the action that has not yet performed the action in response to the press. + /// to the action) crossed the press threshold at any point in the frame, this method will return true. + /// It will do so even if there is an interaction on the action that has not yet performed the action in response to the press. /// /// This method works with any of action, not just buttons. /// @@ -1232,8 +1242,13 @@ private int ExpectedFrame() /// to a , the control will be considered "pressed" once the magnitude /// of the Vector2 of the control has crossed the press threshold. /// - /// Finally, note that custom button press points of controls (see ) - /// are respected and will take precedence over . + /// Press threshold (based on for the driving control): controls implementing + /// (including , , and ) + /// use / when a positive + /// control pressPoint is set. If not set on the control but the binding has a + /// with greater than zero, that value is used so this + /// API stays aligned with the interaction. For composite bindings, interaction parameters are read from the composite binding. + /// Otherwise is used. /// /// /// @@ -1271,7 +1286,7 @@ public unsafe bool WasPressedThisFrame() } /// - /// Returns true if the action's value crossed the press threshold (see ) + /// Returns true if the action's value crossed the press threshold (see remarks) /// in the MonoBehaviour Update cycle (rendering frame). /// /// True if the action was pressed in the MonoBehaviour Update cycle (rendering frame). @@ -1282,6 +1297,8 @@ public unsafe bool WasPressedThisFrame() /// /// When processing input events manually, updating the InputSystem in the dynamic Update cycle will lead to a delay of one frame for WasPressedThisDynamicUpdate, /// you may want to use WasPressedThisFrame to avoid this, or set the input update mode to InputSettings.UpdateMode.ProcessEventsInDynamicUpdate. + /// + /// Press threshold behavior matches ; see its remarks. /// /// /// @@ -1311,7 +1328,7 @@ public unsafe bool WasPressedThisDynamicUpdate() /// /// Returns true if the action's value crossed the release threshold (see ) - /// at any point in the frame after being in pressed state. + /// at any point in the frame after being in pressed state (see remarks for press threshold). /// /// True if the action was released this frame. /// @@ -1322,8 +1339,13 @@ public unsafe bool WasPressedThisDynamicUpdate() /// to a , the control will be considered "pressed" once the magnitude /// of the Vector2 of the control has crossed the press threshold. /// - /// Finally, note that custom button press points of controls (see ) - /// are respected and will take precedence over . + /// Press threshold (based on for the driving control): controls implementing + /// (including , , and ) + /// use / when a positive + /// control pressPoint is set. If not set on the control but the binding has a + /// with greater than zero, that value is used so this + /// API stays aligned with the interaction. For composite bindings, interaction parameters are read from the composite binding. + /// Otherwise is used. /// /// /// @@ -1362,7 +1384,8 @@ public unsafe bool WasReleasedThisFrame() /// /// Returns true if the action's value crossed the release threshold (see ) - /// at any point in the MonoBehaviour Update cycle (rendering frame). + /// at any point in the MonoBehaviour Update cycle (rendering frame), after having been in the pressed state described by + /// . /// /// True if the action was released in the MonoBehaviour Update cycle (rendering frame). /// @@ -1372,6 +1395,8 @@ public unsafe bool WasReleasedThisFrame() /// /// When processing input events manually, updating the InputSystem in the dynamic Update cycle will lead to a delay of one frame for WasReleasedThisDynamicUpdate, /// you may want to use WasReleasedThisFrame to avoid this, or set the input update mode to InputSettings.UpdateMode.ProcessEventsInDynamicUpdate. + /// + /// Press and release threshold behavior matches ; see its remarks. /// /// /// @@ -1744,8 +1769,10 @@ public unsafe float GetTimeoutCompletionPercentage() if (interactionState.totalTimeoutCompletionTimeRemaining > 0) { - return (interactionState.totalTimeoutCompletionDone + timerCompletion * interactionState.timerDuration) / - (interactionState.totalTimeoutCompletionDone + interactionState.totalTimeoutCompletionTimeRemaining); + return (interactionState.totalTimeoutCompletionDone + + timerCompletion * interactionState.timerDuration) / + (interactionState.totalTimeoutCompletionDone + + interactionState.totalTimeoutCompletionTimeRemaining); } else { @@ -1760,29 +1787,40 @@ public unsafe float GetTimeoutCompletionPercentage() } ////REVIEW: it would be best if these were InternedStrings; however, for serialization, it has to be strings - [Tooltip("Human readable name of the action. Must be unique within its action map (case is ignored). Can be changed " + [Tooltip( + "Human readable name of the action. Must be unique within its action map (case is ignored). Can be changed " + "without breaking references to the action.")] - [SerializeField] internal string m_Name; + [SerializeField] + internal string m_Name; + [Tooltip("Determines how the action triggers.\n" - + "\n" - + "A Value action will start and perform when a control moves from its default value and then " - + "perform on every value change. It will cancel when controls go back to default value. Also, when enabled, a Value " - + "action will respond right away to a control's current value.\n" - + "\n" - + "A Button action will start when a button is pressed and perform when the press threshold (see 'Default Button Press Point' in settings) " - + "is reached. It will cancel when the button is going below the release threshold (see 'Button Release Threshold' in settings). Also, " - + "if a button is already pressed when the action is enabled, the button has to be released first.\n" - + "\n" - + "A Pass-Through action will not explicitly start and will never cancel. Instead, for every value change on any bound control, " - + "the action will perform.")] - [SerializeField] internal InputActionType m_Type; + + "\n" + + "A Value action will start and perform when a control moves from its default value and then " + + "perform on every value change. It will cancel when controls go back to default value. Also, when enabled, a Value " + + "action will respond right away to a control's current value.\n" + + "\n" + + "A Button action will start when a button is pressed and perform when the press threshold (see 'Default Button Press Point' in settings) " + + "is reached. It will cancel when the button is going below the release threshold (see 'Button Release Threshold' in settings). Also, " + + "if a button is already pressed when the action is enabled, the button has to be released first.\n" + + "\n" + + "A Pass-Through action will not explicitly start and will never cancel. Instead, for every value change on any bound control, " + + "the action will perform.")] + [SerializeField] + internal InputActionType m_Type; + [FormerlySerializedAs("m_ExpectedControlLayout")] - [Tooltip("The type of control expected by the action (e.g. \"Digital\" for buttons, \"Vector2\" for sticks). This will limit the controls shown " + [Tooltip( + "The type of control expected by the action (e.g. \"Digital\" for buttons, \"Vector2\" for sticks). This will limit the controls shown " + "when setting up bindings in the UI and will also limit which controls can be bound interactively to the action.")] - [SerializeField] internal string m_ExpectedControlType; - [Tooltip("Unique ID of the action (GUID). Used to reference the action from bindings such that actions can be renamed " + [SerializeField] + internal string m_ExpectedControlType; + + [Tooltip( + "Unique ID of the action (GUID). Used to reference the action from bindings such that actions can be renamed " + "without breaking references.")] - [SerializeField] internal string m_Id; // Can't serialize System.Guid and Unity's GUID is editor only. + [SerializeField] + internal string m_Id; // Can't serialize System.Guid and Unity's GUID is editor only. + [SerializeField] internal string m_Processors; [SerializeField] internal string m_Interactions; @@ -2358,7 +2396,8 @@ public unsafe void ReadValue(void* buffer, int bufferSize) var valueSize = valueSizeInBytes; if (bufferSize < valueSize) throw new ArgumentException( - $"Expected buffer of at least {valueSize} bytes but got buffer of only {bufferSize} bytes", nameof(bufferSize)); + $"Expected buffer of at least {valueSize} bytes but got buffer of only {bufferSize} bytes", + nameof(bufferSize)); UnsafeUtility.MemClear(buffer, valueSizeInBytes); } } @@ -2417,9 +2456,9 @@ public TValue ReadValue() var value = default(TValue); if (m_State != null) { - value = phase.IsInProgress() ? - m_State.ReadValue(bindingIndex, controlIndex) : - m_State.ApplyProcessors(bindingIndex, value); + value = phase.IsInProgress() + ? m_State.ReadValue(bindingIndex, controlIndex) + : m_State.ApplyProcessors(bindingIndex, value); } return value; @@ -2431,9 +2470,9 @@ public TValue ReadValue() /// /// True if the action is considered in "pressed" state, false otherwise. /// - /// If the currently active control is a , the - /// of the button will be taken into account (if set). If there is no custom button press point, the - /// global will be used. + /// The same press rules as apply: on the active control, + /// an explicit on the binding when the control + /// does not set pressPoint, or . /// /// /// @@ -2469,7 +2508,9 @@ public TValue ReadValue() /// /// /// + /// /// + /// public bool ReadValueAsButton() { var value = false; @@ -2571,8 +2612,9 @@ public object ReadValueAsObject() /// public override string ToString() { - return $"{{ action={action} phase={phase} time={time} control={control} value={ReadValueAsObject()} interaction={interaction} }}"; + return + $"{{ action={action} phase={phase} time={time} control={control} value={ReadValueAsObject()} interaction={interaction} }}"; } } } -} +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputActionState.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputActionState.cs index 32b0354752..b13228e78c 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputActionState.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputActionState.cs @@ -5,10 +5,10 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.InputSystem.Controls; +using UnityEngine.InputSystem.Interactions; using UnityEngine.InputSystem.LowLevel; using Unity.Profiling; using UnityEngine.InputSystem.Utilities; - using ProfilerMarker = Unity.Profiling.ProfilerMarker; ////TODO: now that we can bind to controls by display name, we need to re-resolve controls when those change (e.g. when the keyboard layout changes) @@ -125,11 +125,20 @@ internal unsafe class InputActionState : IInputStateChangeMonitor, ICloneable, I private InputEventPtr m_CurrentlyProcessingThisEvent; private Action m_OnBeforeUpdateDelegate; private Action m_OnAfterUpdateDelegate; - private static readonly ProfilerMarker k_InputInitialActionStateCheckMarker = new ProfilerMarker("InitialActionStateCheck"); - private static readonly ProfilerMarker k_InputActionResolveConflictMarker = new ProfilerMarker("InputActionResolveConflict"); + + private static readonly ProfilerMarker k_InputInitialActionStateCheckMarker = + new ProfilerMarker("InitialActionStateCheck"); + + private static readonly ProfilerMarker k_InputActionResolveConflictMarker = + new ProfilerMarker("InputActionResolveConflict"); + private static readonly ProfilerMarker k_InputActionCallbackMarker = new ProfilerMarker("InputActionCallback"); - private static readonly ProfilerMarker k_InputOnActionChangeMarker = new ProfilerMarker("InpustSystem.onActionChange"); - private static readonly ProfilerMarker k_InputOnDeviceChangeMarker = new ProfilerMarker("InpustSystem.onDeviceChange"); + + private static readonly ProfilerMarker k_InputOnActionChangeMarker = + new ProfilerMarker("InpustSystem.onActionChange"); + + private static readonly ProfilerMarker k_InputOnDeviceChangeMarker = + new ProfilerMarker("InpustSystem.onDeviceChange"); /// /// Initialize execution state with given resolved binding information. @@ -168,11 +177,13 @@ private void ComputeControlGroupingIfNecessary() for (var n = compositeBindingIndex + 1; n < totalBindingCount; ++n) { ref var partBinding = ref bindingStates[n]; - if (!partBinding.isPartOfComposite || partBinding.compositeOrCompositeBindingIndex != compositeBindingIndex) + if (!partBinding.isPartOfComposite || + partBinding.compositeOrCompositeBindingIndex != compositeBindingIndex) break; ++complexity; } } + controlGroupingAndComplexity[i * 2 + 1] = (ushort)complexity; // Compute grouping. If already set, skip. @@ -232,7 +243,8 @@ public void Dispose() private void Destroy(bool isFinalizing = false) { - Debug.Assert(!isProcessingControlStateChange, "Must not destroy InputActionState while executing an action callback within it"); + Debug.Assert(!isProcessingControlStateChange, + "Must not destroy InputActionState while executing an action callback within it"); if (!isFinalizing) { @@ -262,6 +274,7 @@ private void Destroy(bool isFinalizing = false) RemoveMapFromGlobalList(); } + memory.Dispose(); } @@ -490,7 +503,8 @@ internal void PrepareForBindingReResolution(bool needFullResolve, NotifyListenersOfActionChange(InputActionChange.BoundControlsAboutToChange); } - public void FinishBindingResolution(bool hasEnabledActions, UnmanagedMemory oldMemory, InputControlList activeControls, bool isFullResolve) + public void FinishBindingResolution(bool hasEnabledActions, UnmanagedMemory oldMemory, + InputControlList activeControls, bool isFullResolve) { // Fire InputBindingComposite.FinishSetup() calls. FinishBindingCompositeSetups(); @@ -517,7 +531,8 @@ public void FinishBindingResolution(bool hasEnabledActions, UnmanagedMemory oldM /// reenable all the actions and controls that were enabled before and then let the next update /// take it from there. /// - private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldState, InputControlList activeControls, bool isFullResolve) + private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldState, + InputControlList activeControls, bool isFullResolve) { Debug.Assert(oldState.isAllocated, "Old state contains no memory"); @@ -544,13 +559,17 @@ private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldStat // // HOWEVER, if isFullResolve==false, then ONLY control indices may have changed. All other // indices must have remained unchanged. - Debug.Assert(oldState.actionCount == memory.actionCount, "Action count in old and new state must be the same"); + Debug.Assert(oldState.actionCount == memory.actionCount, + "Action count in old and new state must be the same"); Debug.Assert(oldState.mapCount == memory.mapCount, "Map count in old and new state must be the same"); if (!isFullResolve) { - Debug.Assert(oldState.bindingCount == memory.bindingCount, "Binding count in old and new state must be the same"); - Debug.Assert(oldState.interactionCount == memory.interactionCount, "Interaction count in old and new state must be the same"); - Debug.Assert(oldState.compositeCount == memory.compositeCount, "Composite count in old and new state must be the same"); + Debug.Assert(oldState.bindingCount == memory.bindingCount, + "Binding count in old and new state must be the same"); + Debug.Assert(oldState.interactionCount == memory.interactionCount, + "Interaction count in old and new state must be the same"); + Debug.Assert(oldState.compositeCount == memory.compositeCount, + "Composite count in old and new state must be the same"); } // Restore action states. @@ -649,7 +668,8 @@ private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldStat var newControlIndex = FindControlIndexOnBinding(bindingIndex, control); // This assert is used by test: Actions_ActiveBindingsHaveCorrectBindingIndicesAfterBindingResolution - Debug.Assert(newControlIndex != kInvalidIndex, "Could not find active control after binding resolution"); + Debug.Assert(newControlIndex != kInvalidIndex, + "Could not find active control after binding resolution"); if (newControlIndex != kInvalidIndex) { newActionState.phase = oldActionState.phase; @@ -665,7 +685,8 @@ private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldStat "Interaction count on binding must not have changed when doing a control-only resolve"); for (var n = 0; n < newBindingState.interactionCount; ++n) { - ref var oldInteractionState = ref oldState.interactionStates[oldBindingState.interactionStartIndex + n]; + ref var oldInteractionState = + ref oldState.interactionStates[oldBindingState.interactionStartIndex + n]; if (!oldInteractionState.phase.IsInProgress()) continue; @@ -674,7 +695,8 @@ private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldStat continue; newControlIndex = FindControlIndexOnBinding(bindingIndex, control); - Debug.Assert(newControlIndex != kInvalidIndex, "Could not find active control on interaction after binding resolution"); + Debug.Assert(newControlIndex != kInvalidIndex, + "Could not find active control on interaction after binding resolution"); ref var newInteractionState = ref interactionStates[newBindingState.interactionStartIndex + n]; newInteractionState.phase = oldInteractionState.phase; @@ -695,8 +717,10 @@ private void RestoreActionStatesAfterReResolvingBindings(UnmanagedMemory oldStat }; StartTimeout(oldInteractionState.timerDuration, ref trigger); - newInteractionState.totalTimeoutCompletionDone = oldInteractionState.totalTimeoutCompletionDone; - newInteractionState.totalTimeoutCompletionTimeRemaining = oldInteractionState.totalTimeoutCompletionTimeRemaining; + newInteractionState.totalTimeoutCompletionDone = + oldInteractionState.totalTimeoutCompletionDone; + newInteractionState.totalTimeoutCompletionTimeRemaining = + oldInteractionState.totalTimeoutCompletionTimeRemaining; } } } @@ -769,7 +793,8 @@ private void ResetActionStatesDrivenBy(InputDevice device) var actionState = &actionStates[actionIndex]; // Skip actions that aren't in progress. - if (actionState->phase == InputActionPhase.Waiting || actionState->phase == InputActionPhase.Disabled) + if (actionState->phase == InputActionPhase.Waiting || + actionState->phase == InputActionPhase.Disabled) continue; // Skip actions not driven from this device. @@ -831,9 +856,11 @@ private bool IsActionBoundToControlFromDevice(InputDevice device, int actionInde /// or . Other phases cannot be transitioned to through resets. /// If true, also wipe state such as for which normally /// persists even if an action is disabled. - public void ResetActionState(int actionIndex, InputActionPhase toPhase = InputActionPhase.Waiting, bool hardReset = false) + public void ResetActionState(int actionIndex, InputActionPhase toPhase = InputActionPhase.Waiting, + bool hardReset = false) { - Debug.Assert(actionIndex >= 0 && actionIndex < totalActionCount, "Action index out of range when resetting action"); + Debug.Assert(actionIndex >= 0 && actionIndex < totalActionCount, + "Action index out of range when resetting action"); Debug.Assert(toPhase == InputActionPhase.Waiting || toPhase == InputActionPhase.Disabled, "Phase must be Waiting or Disabled"); @@ -858,7 +885,8 @@ public void ResetActionState(int actionIndex, InputActionPhase toPhase = InputAc for (var i = 0; i < interactionCount; ++i) { var interactionIndex = interactionStartIndex + i; - ResetInteractionStateAndCancelIfNecessary(mapIndex, bindingIndex, interactionIndex, phaseAfterCanceled: toPhase); + ResetInteractionStateAndCancelIfNecessary(mapIndex, bindingIndex, interactionIndex, + phaseAfterCanceled: toPhase); } } } @@ -866,7 +894,8 @@ public void ResetActionState(int actionIndex, InputActionPhase toPhase = InputAc { // No interactions. Cancel the action directly. - Debug.Assert(actionState->bindingIndex != kInvalidIndex, "Binding index on trigger state is invalid"); + Debug.Assert(actionState->bindingIndex != kInvalidIndex, + "Binding index on trigger state is invalid"); Debug.Assert(bindingStates[actionState->bindingIndex].interactionCount == 0, "Action has been triggered but apparently not from an interaction yet there's interactions on the binding that got triggered?!?"); @@ -913,7 +942,8 @@ public ref TriggerState FetchActionState(InputAction action) Debug.Assert(action.m_ActionMap != null, "Action must have an action map"); Debug.Assert(action.m_ActionMap.m_MapIndexInState != kInvalidIndex, "Action must have index set"); Debug.Assert(maps.Contains(action.m_ActionMap), "Action map must be contained in state"); - Debug.Assert(action.m_ActionIndexInState >= 0 && action.m_ActionIndexInState < totalActionCount, "Action index is out of range"); + Debug.Assert(action.m_ActionIndexInState >= 0 && action.m_ActionIndexInState < totalActionCount, + "Action index is out of range"); return ref actionStates[action.m_ActionIndexInState]; } @@ -947,6 +977,7 @@ public void EnableAllActions(InputActionMap map) actionState->phase = InputActionPhase.Waiting; actionState->inProcessing = false; } + map.m_EnabledActionsCount = actionCount; HookOnBeforeUpdate(); @@ -1056,6 +1087,7 @@ public void DisableAllActions(InputActionMap map) NotifyListenersOfActionChange(InputActionChange.ActionDisabled, map.m_Actions[i]); } } + map.m_EnabledActionsCount = 0; // Make sure that if we happen to get here with one of the hidden action maps we create for singleton @@ -1073,7 +1105,8 @@ public void DisableControls(InputActionMap map) Debug.Assert(maps.Contains(map), "Map must be contained in state"); var mapIndex = map.m_MapIndexInState; - Debug.Assert(mapIndex >= 0 && mapIndex < totalMapCount, "Map index out of range in DisableControls(InputActionMap)"); + Debug.Assert(mapIndex >= 0 && mapIndex < totalMapCount, + "Map index out of range in DisableControls(InputActionMap)"); // Remove state monitors from all controls. var controlCount = mapIndices[mapIndex].controlCount; @@ -1107,7 +1140,8 @@ private void DisableControls(InputAction action) var map = action.m_ActionMap; var mapIndex = map.m_MapIndexInState; - Debug.Assert(mapIndex >= 0 && mapIndex < totalMapCount, "Map index out of range in DisableControls(InputAction)"); + Debug.Assert(mapIndex >= 0 && mapIndex < totalMapCount, + "Map index out of range in DisableControls(InputAction)"); // Go through all bindings in the map and for all that belong to the given action, // disable the associated controls. @@ -1161,12 +1195,14 @@ private void EnableControls(int mapIndex, int controlStartIndex, int numControls continue; var bindingIndex = controlIndexToBindingIndex[controlIndex]; - var mapControlAndBindingIndex = ToCombinedMapAndControlAndBindingIndex(mapIndex, controlIndex, bindingIndex); + var mapControlAndBindingIndex = + ToCombinedMapAndControlAndBindingIndex(mapIndex, controlIndex, bindingIndex); var bindingStatePtr = &bindingStates[bindingIndex]; if (bindingStatePtr->wantsInitialStateCheck) SetInitialStateCheckPending(bindingStatePtr, true); - manager.AddStateChangeMonitor(controls[controlIndex], this, mapControlAndBindingIndex, controlGroupingAndComplexity[controlIndex * 2]); + manager.AddStateChangeMonitor(controls[controlIndex], this, mapControlAndBindingIndex, + controlGroupingAndComplexity[controlIndex * 2]); SetControlEnabled(controlIndex, true); } @@ -1188,7 +1224,8 @@ private void DisableControls(int mapIndex, int controlStartIndex, int numControl continue; var bindingIndex = controlIndexToBindingIndex[controlIndex]; - var mapControlAndBindingIndex = ToCombinedMapAndControlAndBindingIndex(mapIndex, controlIndex, bindingIndex); + var mapControlAndBindingIndex = + ToCombinedMapAndControlAndBindingIndex(mapIndex, controlIndex, bindingIndex); var bindingStatePtr = &bindingStates[bindingIndex]; if (bindingStatePtr->wantsInitialStateCheck) SetInitialStateCheckPending(bindingStatePtr, false); @@ -1278,10 +1315,10 @@ private void UnhookOnBeforeUpdate() private void OnBeforeInitialUpdate() { if (InputState.currentUpdateType == InputUpdateType.BeforeRender - #if UNITY_EDITOR +#if UNITY_EDITOR || InputState.currentUpdateType == InputUpdateType.Editor - #endif - ) +#endif + ) return; // Remove us from the callback as the processing we're doing here is a one-time thing. @@ -1304,7 +1341,8 @@ private void OnBeforeInitialUpdate() if (!bindingState.initialStateCheckPending) continue; - Debug.Assert(!bindingState.isPartOfComposite, "Initial state check flag must be set on composite, not on its parts"); + Debug.Assert(!bindingState.isPartOfComposite, + "Initial state check flag must be set on composite, not on its parts"); bindingState.initialStateCheckPending = false; var controlStartIndex = bindingState.controlStartIndex; @@ -1346,6 +1384,7 @@ private void OnBeforeInitialUpdate() } } } + manager.FireStateChangeNotifications(); k_InputInitialActionStateCheckMarker.End(); @@ -1374,19 +1413,21 @@ private static bool ShouldSkipInitialStateCheck(InputControl control) void IInputStateChangeMonitor.NotifyControlStateChanged(InputControl control, double time, InputEventPtr eventPtr, long mapControlAndBindingIndex) { - #if UNITY_EDITOR +#if UNITY_EDITOR if (InputState.currentUpdateType == InputUpdateType.Editor) return; - #endif +#endif - SplitUpMapAndControlAndBindingIndex(mapControlAndBindingIndex, out var mapIndex, out var controlIndex, out var bindingIndex); + SplitUpMapAndControlAndBindingIndex(mapControlAndBindingIndex, out var mapIndex, out var controlIndex, + out var bindingIndex); ProcessControlStateChange(mapIndex, controlIndex, bindingIndex, time, eventPtr); } void IInputStateChangeMonitor.NotifyTimerExpired(InputControl control, double time, long mapControlAndBindingIndex, int interactionIndex) { - SplitUpMapAndControlAndBindingIndex(mapControlAndBindingIndex, out var mapIndex, out var controlIndex, out var bindingIndex); + SplitUpMapAndControlAndBindingIndex(mapControlAndBindingIndex, out var mapIndex, out var controlIndex, + out var bindingIndex); ProcessTimeout(time, mapIndex, controlIndex, bindingIndex, interactionIndex); } @@ -1456,9 +1497,11 @@ internal static int GetComplexityFromMonitorIndex(long mapControlAndBindingIndex /// Note that we get called for any change in state even if the change in state does not actually /// result in a change of value on the respective control. /// - private void ProcessControlStateChange(int mapIndex, int controlIndex, int bindingIndex, double time, InputEventPtr eventPtr) + private void ProcessControlStateChange(int mapIndex, int controlIndex, int bindingIndex, double time, + InputEventPtr eventPtr) { - Debug.Assert(mapIndex >= 0 && mapIndex < totalMapCount, "Map index out of range in ProcessControlStateChange"); + Debug.Assert(mapIndex >= 0 && mapIndex < totalMapCount, + "Map index out of range in ProcessControlStateChange"); Debug.Assert(controlIndex >= 0 && controlIndex < totalControlCount, "Control index out of range"); Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); @@ -1562,7 +1605,8 @@ private void ProcessControlStateChange(int mapIndex, int controlIndex, int bindi // Check if we should suppress interaction processing notifications m_Suppressed = (eventPtr != null) && eventPtr.handled && - InputSystem.manager.inputEventHandledPolicy == InputEventHandledPolicy.SuppressActionEventNotifications; + InputSystem.manager.inputEventHandledPolicy == + InputEventHandledPolicy.SuppressActionEventNotifications; // Check if we have multiple concurrent actuations on the same action. This may lead us // to ignore certain inputs (e.g. when we get an input of lesser magnitude while already having @@ -1570,7 +1614,9 @@ private void ProcessControlStateChange(int mapIndex, int controlIndex, int bindi // (e.g. when an input of previously greater magnitude has now fallen below the level of another // ongoing input with now higher magnitude). var isConflictingInput = IsConflictingInput(ref trigger, actionIndex); - bindingStatePtr = &bindingStates[trigger.bindingIndex]; // IsConflictingInput may switch us to a different binding. + bindingStatePtr = + &bindingStates[ + trigger.bindingIndex]; // IsConflictingInput may switch us to a different binding. // Process button presses/releases. if (!isConflictingInput) @@ -1596,12 +1642,51 @@ private void ProcessControlStateChange(int mapIndex, int controlIndex, int bindi } } + private BindingState* GetBindingStateForInteractionParameters(BindingState* bindingStatePtr) + { + if (bindingStatePtr->isPartOfComposite) + return &bindingStates[bindingStatePtr->compositeOrCompositeBindingIndex]; + return bindingStatePtr; + } + + private float? TryGetExplicitPressInteractionPressPoint(BindingState* bindingStateForInteractions) + { + var count = bindingStateForInteractions->interactionCount; + if (count == 0) + return null; + var start = bindingStateForInteractions->interactionStartIndex; + for (var i = 0; i < count; ++i) + { + if (interactions[start + i] is PressInteraction press && press.pressPoint > 0) + return press.pressPoint; + } + + return null; + } + + private float GetActuationPressThreshold(InputControl control, BindingState* bindingStatePtr) + { + var bindingForInteractions = GetBindingStateForInteractionParameters(bindingStatePtr); + var explicitPress = TryGetExplicitPressInteractionPressPoint(bindingForInteractions); + + if (control is IActuationPressPoint actuation) + { + if (actuation.pressPoint > 0) + return actuation.pressPointOrDefault; + if (explicitPress.HasValue) + return explicitPress.Value; + return actuation.pressPointOrDefault; + } + + if (explicitPress.HasValue) + return explicitPress.Value; + return ButtonControl.s_GlobalDefaultButtonPressPoint; + } + private void ProcessButtonState(ref TriggerState trigger, int actionIndex, BindingState* bindingStatePtr) { var control = controls[trigger.controlIndex]; - var pressPoint = control.isButton - ? ((ButtonControl)control).pressPointOrDefault - : ButtonControl.s_GlobalDefaultButtonPressPoint; + var pressPoint = GetActuationPressThreshold(control, bindingStatePtr); // NOTE: This method relies on conflict resolution happening *first*. Otherwise, we may inadvertently // detect a "release" from a control that is not actually driving the action. @@ -1746,7 +1831,9 @@ private bool IsConflictingInput(ref TriggerState trigger, int actionIndex) // Find out if we get triggered from the control that is actively driving the action. var isControlCurrentlyDrivingTheAction = triggerControlIndex == actionStateControlIndex || - controls[triggerControlIndex] == controls[actionStateControlIndex]; // Same control, different binding. + controls[triggerControlIndex] == + controls[ + actionStateControlIndex]; // Same control, different binding. // If the control is actuated *more* than the current level of actuation we recorded for the // action, we process the state change normally. If this isn't the control that is already @@ -1966,6 +2053,7 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex "Action index out of range when processing default interaction"); var actionState = &actionStates[actionIndex]; + var bindingStatePtr = &bindingStates[trigger.bindingIndex]; switch (actionState->phase) { case InputActionPhase.Waiting: @@ -1978,13 +2066,15 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex phaseAfterPerformedOrCanceled: InputActionPhase.Waiting); break; } + // Button actions need to cross the button-press threshold. if (trigger.isButton) { var actuation = trigger.magnitude; if (actuation > 0) ChangePhaseOfAction(InputActionPhase.Started, ref trigger); - var threshold = controls[trigger.controlIndex] is ButtonControl button ? button.pressPointOrDefault : ButtonControl.s_GlobalDefaultButtonPressPoint; + var threshold = + GetActuationPressThreshold(controls[trigger.controlIndex], bindingStatePtr); if (actuation >= threshold) { ChangePhaseOfAction(InputActionPhase.Performed, ref trigger, @@ -2014,7 +2104,8 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex if (actionState->isButton) { var actuation = trigger.magnitude; - var threshold = controls[trigger.controlIndex] is ButtonControl button ? button.pressPointOrDefault : ButtonControl.s_GlobalDefaultButtonPressPoint; + var threshold = + GetActuationPressThreshold(controls[trigger.controlIndex], bindingStatePtr); if (actuation >= threshold) { // Button crossed press threshold. Perform. @@ -2042,6 +2133,7 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex phaseAfterPerformedOrCanceled: InputActionPhase.Started); } } + break; } @@ -2050,7 +2142,8 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex if (actionState->isButton) { var actuation = trigger.magnitude; - var pressPoint = controls[trigger.controlIndex] is ButtonControl button ? button.pressPointOrDefault : ButtonControl.s_GlobalDefaultButtonPressPoint; + var pressPoint = + GetActuationPressThreshold(controls[trigger.controlIndex], bindingStatePtr); if (Mathf.Approximately(0f, actuation)) { ChangePhaseOfAction(InputActionPhase.Canceled, ref trigger); @@ -2071,6 +2164,7 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex ChangePhaseOfAction(InputActionPhase.Performed, ref trigger, phaseAfterPerformedOrCanceled: InputActionPhase.Performed); } + break; } @@ -2106,7 +2200,8 @@ private void ProcessTimeout(double time, int mapIndex, int controlIndex, int bin { Debug.Assert(controlIndex >= 0 && controlIndex < totalControlCount, "Control index out of range"); Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); - Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, + "Interaction index out of range"); ref var currentState = ref interactionStates[interactionIndex]; @@ -2115,15 +2210,15 @@ private void ProcessTimeout(double time, int mapIndex, int controlIndex, int bin m_State = this, m_TriggerState = new TriggerState - { - phase = currentState.phase, - time = time, - mapIndex = mapIndex, - controlIndex = controlIndex, - bindingIndex = bindingIndex, - interactionIndex = interactionIndex, - startTime = currentState.startTime - }, + { + phase = currentState.phase, + time = time, + mapIndex = mapIndex, + controlIndex = controlIndex, + bindingIndex = bindingIndex, + interactionIndex = interactionIndex, + startTime = currentState.startTime + }, timerHasExpired = true, }; @@ -2138,7 +2233,8 @@ private void ProcessTimeout(double time, int mapIndex, int controlIndex, int bin internal void SetTotalTimeoutCompletionTime(float seconds, ref TriggerState trigger) { - Debug.Assert(trigger.interactionIndex >= 0 && trigger.interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(trigger.interactionIndex >= 0 && trigger.interactionIndex < totalInteractionCount, + "Interaction index out of range"); ref var interactionState = ref interactionStates[trigger.interactionIndex]; interactionState.totalTimeoutCompletionDone = 0; @@ -2148,8 +2244,10 @@ internal void SetTotalTimeoutCompletionTime(float seconds, ref TriggerState trig internal void StartTimeout(float seconds, ref TriggerState trigger) { Debug.Assert(trigger.mapIndex >= 0 && trigger.mapIndex < totalMapCount, "Map index out of range"); - Debug.Assert(trigger.controlIndex >= 0 && trigger.controlIndex < totalControlCount, "Control index out of range"); - Debug.Assert(trigger.interactionIndex >= 0 && trigger.interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(trigger.controlIndex >= 0 && trigger.controlIndex < totalControlCount, + "Control index out of range"); + Debug.Assert(trigger.interactionIndex >= 0 && trigger.interactionIndex < totalInteractionCount, + "Interaction index out of range"); var manager = InputSystem.manager; var currentTime = trigger.time; @@ -2176,7 +2274,8 @@ internal void StartTimeout(float seconds, ref TriggerState trigger) private void StopTimeout(int interactionIndex) { - Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, + "Interaction index out of range"); ref var interactionState = ref interactionStates[interactionIndex]; @@ -2231,7 +2330,8 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta var interactionIndex = trigger.interactionIndex; var bindingIndex = trigger.bindingIndex; - Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, + "Interaction index out of range"); Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); ////TODO: need to make sure that performed and canceled phase changes happen on the *same* binding&control @@ -2256,7 +2356,9 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta interactionState.performedTime = trigger.time; // See if it affects the phase of an associated action. - var actionIndex = bindingStates[bindingIndex].actionIndex; // We already had to tap this array and entry in ProcessControlStateChange. + var actionIndex = + bindingStates[bindingIndex] + .actionIndex; // We already had to tap this array and entry in ProcessControlStateChange. if (actionIndex != kInvalidIndex) { if (actionStates[actionIndex].phase == InputActionPhase.Waiting) @@ -2265,7 +2367,8 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta if (!ChangePhaseOfAction(newPhase, ref trigger, phaseAfterPerformedOrCanceled)) return; } - else if (newPhase == InputActionPhase.Canceled && actionStates[actionIndex].interactionIndex == trigger.interactionIndex) + else if (newPhase == InputActionPhase.Canceled && + actionStates[actionIndex].interactionIndex == trigger.interactionIndex) { // We're canceling but maybe there's another interaction ready // to go into start phase. *Or* there's an interaction that has @@ -2282,8 +2385,9 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta for (var i = 0; i < numInteractions; ++i) { var index = interactionStartIndex + i; - if (index != trigger.interactionIndex && (interactionStates[index].phase == InputActionPhase.Started || - interactionStates[index].phase == InputActionPhase.Performed)) + if (index != trigger.interactionIndex && + (interactionStates[index].phase == InputActionPhase.Started || + interactionStates[index].phase == InputActionPhase.Performed)) { // Trigger start. var startTime = interactionStates[index].startTime; @@ -2297,7 +2401,8 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta time = startTime, startTime = startTime, }; - if (!ChangePhaseOfAction(InputActionPhase.Started, ref triggerForInteraction, phaseAfterPerformedOrCanceled)) + if (!ChangePhaseOfAction(InputActionPhase.Started, ref triggerForInteraction, + phaseAfterPerformedOrCanceled)) return; // If the interaction has already performed, trigger it now. @@ -2310,10 +2415,12 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta bindingIndex = trigger.bindingIndex, interactionIndex = index, mapIndex = trigger.mapIndex, - time = interactionStates[index].performedTime, // Time when the interaction performed. + time = interactionStates[index] + .performedTime, // Time when the interaction performed. startTime = startTime, }; - if (!ChangePhaseOfAction(InputActionPhase.Performed, ref triggerForInteraction, phaseAfterPerformedOrCanceled)) + if (!ChangePhaseOfAction(InputActionPhase.Performed, ref triggerForInteraction, + phaseAfterPerformedOrCanceled)) return; // We performed the action, @@ -2324,6 +2431,7 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta ResetInteractionState(index); } } + break; } } @@ -2395,8 +2503,10 @@ private bool ChangePhaseOfAction(InputActionPhase newPhase, ref TriggerState tri { Debug.Assert(newPhase != InputActionPhase.Disabled, "Should not disable an action using this method"); Debug.Assert(trigger.mapIndex >= 0 && trigger.mapIndex < totalMapCount, "Map index out of range"); - Debug.Assert(trigger.controlIndex >= 0 && trigger.controlIndex < totalControlCount, "Control index out of range"); - Debug.Assert(trigger.bindingIndex >= 0 && trigger.bindingIndex < totalBindingCount, "Binding index out of range"); + Debug.Assert(trigger.controlIndex >= 0 && trigger.controlIndex < totalControlCount, + "Control index out of range"); + Debug.Assert(trigger.bindingIndex >= 0 && trigger.bindingIndex < totalBindingCount, + "Binding index out of range"); var actionIndex = bindingStates[trigger.bindingIndex].actionIndex; if (actionIndex == kInvalidIndex) @@ -2419,7 +2529,8 @@ private bool ChangePhaseOfAction(InputActionPhase newPhase, ref TriggerState tri { // No constraints on pass-through actions except if there are interactions driving the action. ChangePhaseOfActionInternal(actionIndex, actionState, newPhase, ref trigger, - isDisablingAction: newPhase == InputActionPhase.Canceled && phaseAfterPerformedOrCanceled == InputActionPhase.Disabled); + isDisablingAction: newPhase == InputActionPhase.Canceled && + phaseAfterPerformedOrCanceled == InputActionPhase.Disabled); if (!actionState->inProcessing) return false; } @@ -2443,10 +2554,12 @@ private bool ChangePhaseOfAction(InputActionPhase newPhase, ref TriggerState tri actionState->phase = phaseAfterPerformedOrCanceled; } - else if (actionState->phase != newPhase || newPhase == InputActionPhase.Performed) // We allow Performed to trigger repeatedly. + else if (actionState->phase != newPhase || + newPhase == InputActionPhase.Performed) // We allow Performed to trigger repeatedly. { ChangePhaseOfActionInternal(actionIndex, actionState, newPhase, ref trigger, - isDisablingAction: newPhase == InputActionPhase.Canceled && phaseAfterPerformedOrCanceled == InputActionPhase.Disabled); + isDisablingAction: newPhase == InputActionPhase.Canceled && + phaseAfterPerformedOrCanceled == InputActionPhase.Disabled); if (!actionState->inProcessing) return false; @@ -2613,7 +2726,8 @@ private void CallActionListeners(int actionIndex, InputActionMap actionMap, Inpu return; } - DelegateHelpers.InvokeCallbacksSafe(ref s_GlobalState.onActionChange, action, change, k_InputOnActionChangeMarker, "InputSystem.onActionChange"); + DelegateHelpers.InvokeCallbacksSafe(ref s_GlobalState.onActionChange, action, change, + k_InputOnActionChangeMarker, "InputSystem.onActionChange"); } // Run callbacks (if any) directly on action. @@ -2651,7 +2765,8 @@ internal InputAction GetActionOrNull(int bindingIndex) internal InputAction GetActionOrNull(ref TriggerState trigger) { Debug.Assert(trigger.mapIndex >= 0 && trigger.mapIndex < totalMapCount, "Map index out of range"); - Debug.Assert(trigger.bindingIndex >= 0 && trigger.bindingIndex < totalBindingCount, "Binding index out of range"); + Debug.Assert(trigger.bindingIndex >= 0 && trigger.bindingIndex < totalBindingCount, + "Binding index out of range"); var actionIndex = bindingStates[trigger.bindingIndex].actionIndex; if (actionIndex == kInvalidIndex) @@ -2665,7 +2780,8 @@ internal InputAction GetActionOrNull(ref TriggerState trigger) internal InputControl GetControl(ref TriggerState trigger) { Debug.Assert(trigger.controlIndex != kInvalidIndex, "Control index is invalid"); - Debug.Assert(trigger.controlIndex >= 0 && trigger.controlIndex < totalControlCount, "Control index out of range"); + Debug.Assert(trigger.controlIndex >= 0 && trigger.controlIndex < totalControlCount, + "Control index out of range"); return controls[trigger.controlIndex]; } @@ -2674,7 +2790,8 @@ private IInputInteraction GetInteractionOrNull(ref TriggerState trigger) if (trigger.interactionIndex == kInvalidIndex) return null; - Debug.Assert(trigger.interactionIndex >= 0 && trigger.interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(trigger.interactionIndex >= 0 && trigger.interactionIndex < totalInteractionCount, + "Interaction index out of range"); return interactions[trigger.interactionIndex]; } @@ -2714,10 +2831,13 @@ internal InputActionMap GetActionMap(int bindingIndex) return maps[mapIndex]; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "mapIndex", Justification = "Keep this for future implementation")] - private void ResetInteractionStateAndCancelIfNecessary(int mapIndex, int bindingIndex, int interactionIndex, InputActionPhase phaseAfterCanceled) + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", + MessageId = "mapIndex", Justification = "Keep this for future implementation")] + private void ResetInteractionStateAndCancelIfNecessary(int mapIndex, int bindingIndex, int interactionIndex, + InputActionPhase phaseAfterCanceled) { - Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, + "Interaction index out of range"); Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); // If interaction is currently driving an action and it has been started or performed, @@ -2748,7 +2868,8 @@ private void ResetInteractionStateAndCancelIfNecessary(int mapIndex, int binding private void ResetInteractionState(int interactionIndex) { - Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, "Interaction index out of range"); + Debug.Assert(interactionIndex >= 0 && interactionIndex < totalInteractionCount, + "Interaction index out of range"); // Clean up internal state that the interaction may keep. interactions[interactionIndex].Reset(); @@ -2760,12 +2881,12 @@ private void ResetInteractionState(int interactionIndex) // Reset state record. interactionStates[interactionIndex] = new InteractionState - { - // We never set interactions to disabled. This way we don't have to go through them - // when we disable/enable actions. - phase = InputActionPhase.Waiting, - triggerControlIndex = kInvalidIndex - }; + { + // We never set interactions to disabled. This way we don't have to go through them + // when we disable/enable actions. + phase = InputActionPhase.Waiting, + triggerControlIndex = kInvalidIndex + }; } internal int GetValueSizeInBytes(int bindingIndex, int controlIndex) @@ -2773,7 +2894,8 @@ internal int GetValueSizeInBytes(int bindingIndex, int controlIndex) Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); Debug.Assert(controlIndex >= 0 && controlIndex < totalControlCount, "Control index out of range"); - if (bindingStates[bindingIndex].isPartOfComposite) ////TODO: instead, just have compositeOrCompositeBindingIndex be invalid + if (bindingStates[bindingIndex] + .isPartOfComposite) ////TODO: instead, just have compositeOrCompositeBindingIndex be invalid { var compositeBindingIndex = bindingStates[bindingIndex].compositeOrCompositeBindingIndex; var compositeIndex = bindingStates[compositeBindingIndex].compositeOrCompositeBindingIndex; @@ -2793,7 +2915,8 @@ internal Type GetValueType(int bindingIndex, int controlIndex) Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); Debug.Assert(controlIndex >= 0 && controlIndex < totalControlCount, "Control index out of range"); - if (bindingStates[bindingIndex].isPartOfComposite) ////TODO: instead, just have compositeOrCompositeBindingIndex be invalid + if (bindingStates[bindingIndex] + .isPartOfComposite) ////TODO: instead, just have compositeOrCompositeBindingIndex be invalid { var compositeBindingIndex = bindingStates[bindingIndex].compositeOrCompositeBindingIndex; var compositeIndex = bindingStates[compositeBindingIndex].compositeOrCompositeBindingIndex; @@ -2820,7 +2943,8 @@ internal static bool IsActuated(ref TriggerState trigger, float threshold = 0) ////REVIEW: we can unify the reading paths once we have blittable type constraints - internal void ReadValue(int bindingIndex, int controlIndex, void* buffer, int bufferSize, bool ignoreComposites = false) + internal void ReadValue(int bindingIndex, int controlIndex, void* buffer, int bufferSize, + bool ignoreComposites = false) { Debug.Assert(bindingIndex >= 0 && bindingIndex < totalBindingCount, "Binding index out of range"); Debug.Assert(controlIndex >= 0 && controlIndex < totalControlCount, "Control index out of range"); @@ -2879,7 +3003,8 @@ internal TValue ReadValue(int bindingIndex, int controlIndex, bool ignor if (!ignoreComposites && bindingStates[bindingIndex].isPartOfComposite) { var compositeBindingIndex = bindingStates[bindingIndex].compositeOrCompositeBindingIndex; - Debug.Assert(compositeBindingIndex >= 0 && compositeBindingIndex < totalBindingCount, "Composite binding index is out of range"); + Debug.Assert(compositeBindingIndex >= 0 && compositeBindingIndex < totalBindingCount, + "Composite binding index is out of range"); var compositeIndex = bindingStates[compositeBindingIndex].compositeOrCompositeBindingIndex; var compositeObject = composites[compositeIndex]; Debug.Assert(compositeObject != null, "Composite object is null"); @@ -2901,7 +3026,8 @@ internal TValue ReadValue(int bindingIndex, int controlIndex, bool ignor throw new InvalidOperationException( $"Cannot read value of type '{typeof(TValue).Name}' from composite '{compositeObject}' bound to action '{GetActionOrNull(bindingIndex)}' (composite is a '{compositeIndex.GetType().Name}' with value type '{TypeHelpers.GetNiceTypeName(valueType)}')"); - compositeObject.ReadValue(ref context, UnsafeUtility.AddressOf(ref value), UnsafeUtility.SizeOf()); + compositeObject.ReadValue(ref context, UnsafeUtility.AddressOf(ref value), + UnsafeUtility.SizeOf()); } else { @@ -2931,7 +3057,8 @@ internal TValue ReadValue(int bindingIndex, int controlIndex, bool ignor return ApplyProcessors(bindingIndex, value, controlOfType); } - internal TValue ApplyProcessors(int bindingIndex, TValue value, InputControl controlOfType = null) + internal TValue ApplyProcessors(int bindingIndex, TValue value, + InputControl controlOfType = null) where TValue : struct { if (totalBindingCount == 0) @@ -2955,7 +3082,9 @@ public float EvaluateCompositePartMagnitude(int bindingIndex, int partNumber) { var firstChildBindingIndex = bindingIndex + 1; var currentMagnitude = float.MinValue; - for (var index = firstChildBindingIndex; index < totalBindingCount && bindingStates[index].isPartOfComposite; ++index) + for (var index = firstChildBindingIndex; + index < totalBindingCount && bindingStates[index].isPartOfComposite; + ++index) { if (bindingStates[index].partIndex != partNumber) continue; @@ -2983,7 +3112,9 @@ internal double GetCompositePartPressTime(int bindingIndex, int partNumber) var firstChildBindingIndex = bindingIndex + 1; var pressTime = double.MaxValue; - for (var index = firstChildBindingIndex; index < totalBindingCount && bindingStates[index].isPartOfComposite; ++index) + for (var index = firstChildBindingIndex; + index < totalBindingCount && bindingStates[index].isPartOfComposite; + ++index) { ref var bindingState = ref bindingStates[index]; @@ -3052,7 +3183,9 @@ internal TValue ReadCompositePartValue(int bindingIndex, int // see its state monitor trigger first and in turn trigger processing of the action and composite. Thus only // that one single control would have its value refreshed in controlMagnitudes whereas the other control magnitudes // would be stale. - for (var index = firstChildBindingIndex; index < totalBindingCount && bindingStates[index].isPartOfComposite; ++index) + for (var index = firstChildBindingIndex; + index < totalBindingCount && bindingStates[index].isPartOfComposite; + ++index) { if (bindingStates[index].partIndex != partNumber) continue; @@ -3108,7 +3241,9 @@ internal bool ReadCompositePartValue(int bindingIndex, int partNumber, void* buf // Find the binding in the composite that has both the given part number and // the greatest amount of actuation. var currentMagnitude = float.MinValue; - for (var index = firstChildBindingIndex; index < totalBindingCount && bindingStates[index].isPartOfComposite; ++index) + for (var index = firstChildBindingIndex; + index < totalBindingCount && bindingStates[index].isPartOfComposite; + ++index) { if (bindingStates[index].partIndex != partNumber) continue; @@ -3152,7 +3287,9 @@ internal object ReadCompositePartValueAsObject(int bindingIndex, int partNumber) // the greatest amount of actuation. var currentMagnitude = float.MinValue; object currentValue = null; - for (var index = firstChildBindingIndex; index < totalBindingCount && bindingStates[index].isPartOfComposite; ++index) + for (var index = firstChildBindingIndex; + index < totalBindingCount && bindingStates[index].isPartOfComposite; + ++index) { if (bindingStates[index].partIndex != partNumber) continue; @@ -3194,10 +3331,13 @@ internal object ReadValueAsObject(int bindingIndex, int controlIndex, bool ignor // If the binding that triggered the action is part of a composite, let // the composite determine the value we return. - if (!ignoreComposites && bindingStates[bindingIndex].isPartOfComposite) ////TODO: instead, just have compositeOrCompositeBindingIndex be invalid + if (!ignoreComposites && + bindingStates[bindingIndex] + .isPartOfComposite) ////TODO: instead, just have compositeOrCompositeBindingIndex be invalid { var compositeBindingIndex = bindingStates[bindingIndex].compositeOrCompositeBindingIndex; - Debug.Assert(compositeBindingIndex >= 0 && compositeBindingIndex < totalBindingCount, "Binding index is out of range"); + Debug.Assert(compositeBindingIndex >= 0 && compositeBindingIndex < totalBindingCount, + "Binding index is out of range"); var compositeIndex = bindingStates[compositeBindingIndex].compositeOrCompositeBindingIndex; var compositeObject = composites[compositeIndex]; Debug.Assert(compositeObject != null, "Composite object is null"); @@ -3240,17 +3380,12 @@ internal object ReadValueAsObject(int bindingIndex, int controlIndex, bool ignor internal bool ReadValueAsButton(int bindingIndex, int controlIndex) { - var buttonControl = default(ButtonControl); - if (!bindingStates[bindingIndex].isPartOfComposite) - buttonControl = controls[controlIndex] as ButtonControl; - // Read float value. var floatValue = ReadValue(bindingIndex, controlIndex); - // Compare to press point. - if (buttonControl != null) - return floatValue >= buttonControl.pressPointOrDefault; - return floatValue >= ButtonControl.s_GlobalDefaultButtonPressPoint; + var bindingPtr = &bindingStates[bindingIndex]; + var threshold = GetActuationPressThreshold(controls[controlIndex], bindingPtr); + return floatValue >= threshold; } /// @@ -3286,7 +3421,8 @@ public int triggerControlIndex else { if (value < 0 || value >= ushort.MaxValue) - throw new NotSupportedException("More than ushort.MaxValue-1 controls in a single InputActionState"); + throw new NotSupportedException( + "More than ushort.MaxValue-1 controls in a single InputActionState"); m_TriggerControlIndex = (ushort)value; } } @@ -3411,7 +3547,8 @@ public int controlStartIndex { Debug.Assert(value != kInvalidIndex, "Control state index is invalid"); if (value >= ushort.MaxValue) - throw new NotSupportedException("Total control count in state cannot exceed byte.MaxValue=" + ushort.MaxValue); + throw new NotSupportedException("Total control count in state cannot exceed byte.MaxValue=" + + ushort.MaxValue); m_ControlStartIndex = (ushort)value; } } @@ -3428,7 +3565,8 @@ public int controlCount set { if (value >= byte.MaxValue) - throw new NotSupportedException("Control count per binding cannot exceed byte.MaxValue=" + byte.MaxValue); + throw new NotSupportedException("Control count per binding cannot exceed byte.MaxValue=" + + byte.MaxValue); m_ControlCount = (byte)value; } } @@ -3451,7 +3589,8 @@ public int interactionStartIndex else { if (value >= ushort.MaxValue) - throw new NotSupportedException("Interaction count cannot exceed ushort.MaxValue=" + ushort.MaxValue); + throw new NotSupportedException("Interaction count cannot exceed ushort.MaxValue=" + + ushort.MaxValue); m_InteractionStartIndex = (ushort)value; } } @@ -3466,7 +3605,8 @@ public int interactionCount set { if (value >= byte.MaxValue) - throw new NotSupportedException("Interaction count per binding cannot exceed byte.MaxValue=" + byte.MaxValue); + throw new NotSupportedException("Interaction count per binding cannot exceed byte.MaxValue=" + + byte.MaxValue); m_InteractionCount = (byte)value; } } @@ -3486,7 +3626,8 @@ public int processorStartIndex else { if (value >= ushort.MaxValue) - throw new NotSupportedException("Processor count cannot exceed ushort.MaxValue=" + ushort.MaxValue); + throw new NotSupportedException("Processor count cannot exceed ushort.MaxValue=" + + ushort.MaxValue); m_ProcessorStartIndex = (ushort)value; } } @@ -3498,7 +3639,8 @@ public int processorCount set { if (value >= byte.MaxValue) - throw new NotSupportedException("Processor count per binding cannot exceed byte.MaxValue=" + byte.MaxValue); + throw new NotSupportedException("Processor count per binding cannot exceed byte.MaxValue=" + + byte.MaxValue); m_ProcessorCount = (byte)value; } } @@ -3526,7 +3668,8 @@ public int actionIndex else { if (value >= ushort.MaxValue) - throw new NotSupportedException("Action count cannot exceed ushort.MaxValue=" + ushort.MaxValue); + throw new NotSupportedException("Action count cannot exceed ushort.MaxValue=" + + ushort.MaxValue); m_ActionIndex = (ushort)value; } } @@ -3564,7 +3707,8 @@ public int compositeOrCompositeBindingIndex else { if (value >= ushort.MaxValue) - throw new NotSupportedException("Composite count cannot exceed ushort.MaxValue=" + ushort.MaxValue); + throw new NotSupportedException("Composite count cannot exceed ushort.MaxValue=" + + ushort.MaxValue); m_CompositeOrCompositeBindingIndex = (ushort)value; } } @@ -3677,7 +3821,8 @@ public int partIndex if (partIndex < 0) throw new ArgumentOutOfRangeException(nameof(value), "Part index must not be negative"); if (partIndex > byte.MaxValue) - throw new InvalidOperationException("Part count must not exceed byte.MaxValue=" + byte.MaxValue); + throw new InvalidOperationException("Part count must not exceed byte.MaxValue=" + + byte.MaxValue); m_PartIndex = (byte)value; } } @@ -3700,9 +3845,12 @@ public struct TriggerState [FieldOffset(0)] private byte m_Phase; [FieldOffset(1)] private byte m_Flags; + [FieldOffset(2)] private byte m_MapIndex; + // One byte available here. [FieldOffset(4)] private ushort m_ControlIndex; + // Two bytes available here. ////REVIEW: can we condense these to floats? would save us a whopping 8 bytes [FieldOffset(8)] private double m_Time; @@ -3791,7 +3939,8 @@ public int mapIndex set { if (value < 0 || value > kMaxNumMaps) - throw new NotSupportedException("More than byte.MaxValue InputActionMaps in a single InputActionState"); + throw new NotSupportedException( + "More than byte.MaxValue InputActionMaps in a single InputActionState"); m_MapIndex = (byte)value; } } @@ -3814,7 +3963,8 @@ public int controlIndex else { if (value < 0 || value >= kMaxNumControls) - throw new NotSupportedException("More than ushort.MaxValue-1 controls in a single InputActionState"); + throw new NotSupportedException( + "More than ushort.MaxValue-1 controls in a single InputActionState"); m_ControlIndex = (ushort)value; } } @@ -3832,7 +3982,8 @@ public int bindingIndex set { if (value < 0 || value > kMaxNumBindings) - throw new NotSupportedException("More than ushort.MaxValue bindings in a single InputActionState"); + throw new NotSupportedException( + "More than ushort.MaxValue bindings in a single InputActionState"); m_BindingIndex = (ushort)value; } } @@ -3858,7 +4009,8 @@ public int interactionIndex else { if (value < 0 || value >= ushort.MaxValue) - throw new NotSupportedException("More than ushort.MaxValue-1 interactions in a single InputActionState"); + throw new NotSupportedException( + "More than ushort.MaxValue-1 interactions in a single InputActionState"); m_InteractionIndex = (ushort)value; } } @@ -4207,7 +4359,8 @@ public struct UnmanagedMemory : IDisposable return allocation; } - public void Allocate(int mapCount, int actionCount, int bindingCount, int controlCount, int interactionCount, int compositeCount) + public void Allocate(int mapCount, int actionCount, int bindingCount, int controlCount, + int interactionCount, int compositeCount) { Debug.Assert(basePtr == null, "Memory already allocated! Free first!"); Debug.Assert(mapCount >= 1, "Map count out of range"); @@ -4233,7 +4386,8 @@ public void Allocate(int mapCount, int actionCount, int bindingCount, int contro // cause any misalignment here. TriggerState, InteractionState, and BindingState all // contain doubles so put them first in memory to make sure they get proper alignment. actionStates = (TriggerState*)AllocFromBlob(ref ptr, actionCount * sizeof(TriggerState)); - interactionStates = (InteractionState*)AllocFromBlob(ref ptr, interactionCount * sizeof(InteractionState)); + interactionStates = + (InteractionState*)AllocFromBlob(ref ptr, interactionCount * sizeof(InteractionState)); bindingStates = (BindingState*)AllocFromBlob(ref ptr, bindingCount * sizeof(BindingState)); mapIndices = (ActionMapIndices*)AllocFromBlob(ref ptr, mapCount * sizeof(ActionMapIndices)); controlMagnitudes = (float*)AllocFromBlob(ref ptr, controlCount * sizeof(float)); @@ -4282,14 +4436,21 @@ public void CopyDataFrom(UnmanagedMemory memory) UnsafeUtility.MemCpy(mapIndices, memory.mapIndices, memory.mapCount * sizeof(ActionMapIndices)); UnsafeUtility.MemCpy(actionStates, memory.actionStates, memory.actionCount * sizeof(TriggerState)); UnsafeUtility.MemCpy(bindingStates, memory.bindingStates, memory.bindingCount * sizeof(BindingState)); - UnsafeUtility.MemCpy(interactionStates, memory.interactionStates, memory.interactionCount * sizeof(InteractionState)); + UnsafeUtility.MemCpy(interactionStates, memory.interactionStates, + memory.interactionCount * sizeof(InteractionState)); UnsafeUtility.MemCpy(controlMagnitudes, memory.controlMagnitudes, memory.controlCount * sizeof(float)); - UnsafeUtility.MemCpy(compositeMagnitudes, memory.compositeMagnitudes, memory.compositeCount * sizeof(float)); - UnsafeUtility.MemCpy(controlIndexToBindingIndex, memory.controlIndexToBindingIndex, memory.controlCount * sizeof(int)); - UnsafeUtility.MemCpy(controlGroupingAndComplexity, memory.controlGroupingAndComplexity, memory.controlCount * sizeof(ushort) * 2); - UnsafeUtility.MemCpy(actionBindingIndicesAndCounts, memory.actionBindingIndicesAndCounts, memory.actionCount * sizeof(ushort) * 2); - UnsafeUtility.MemCpy(actionBindingIndices, memory.actionBindingIndices, memory.bindingCount * sizeof(ushort)); - UnsafeUtility.MemCpy(enabledControls, memory.enabledControls, (memory.controlCount + 31) / 32 * sizeof(int)); + UnsafeUtility.MemCpy(compositeMagnitudes, memory.compositeMagnitudes, + memory.compositeCount * sizeof(float)); + UnsafeUtility.MemCpy(controlIndexToBindingIndex, memory.controlIndexToBindingIndex, + memory.controlCount * sizeof(int)); + UnsafeUtility.MemCpy(controlGroupingAndComplexity, memory.controlGroupingAndComplexity, + memory.controlCount * sizeof(ushort) * 2); + UnsafeUtility.MemCpy(actionBindingIndicesAndCounts, memory.actionBindingIndicesAndCounts, + memory.actionCount * sizeof(ushort) * 2); + UnsafeUtility.MemCpy(actionBindingIndices, memory.actionBindingIndices, + memory.bindingCount * sizeof(ushort)); + UnsafeUtility.MemCpy(enabledControls, memory.enabledControls, + (memory.controlCount + 31) / 32 * sizeof(int)); } public UnmanagedMemory Clone() @@ -4335,13 +4496,13 @@ internal struct GlobalState [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void InitializeGlobalActionState() { - #if UNITY_EDITOR +#if UNITY_EDITOR // Appears we shouldn't really reset globals in case the domain reload is enabled. // This is because in that case, we've just had the whole system init'ed via static ctors // Moreover, later in GlobalInialize we skip initialization specifically in this case. if (!(InputSystem.s_IsDomainReloadDisabled?.Invoke() ?? false)) return; - #endif +#endif ResetGlobals(); s_GlobalState = default; @@ -4403,6 +4564,7 @@ private static void CompactGlobalList() s_GlobalState.globalList[i] = default; } } + s_GlobalState.globalList.length = head; } @@ -4429,13 +4591,17 @@ internal void NotifyListenersOfActionChange(InputActionChange change) internal static void NotifyListenersOfActionChange(InputActionChange change, object actionOrMapOrAsset) { - Debug.Assert(actionOrMapOrAsset != null, "Should have action or action map or asset object to notify about"); - Debug.Assert(actionOrMapOrAsset is InputAction || (actionOrMapOrAsset as InputActionMap)?.m_SingletonAction == null, + Debug.Assert(actionOrMapOrAsset != null, + "Should have action or action map or asset object to notify about"); + Debug.Assert( + actionOrMapOrAsset is InputAction || (actionOrMapOrAsset as InputActionMap)?.m_SingletonAction == null, "Must not send notifications for changes made to hidden action maps of singleton actions"); - DelegateHelpers.InvokeCallbacksSafe(ref s_GlobalState.onActionChange, actionOrMapOrAsset, change, k_InputOnActionChangeMarker, "InputSystem.onActionChange"); + DelegateHelpers.InvokeCallbacksSafe(ref s_GlobalState.onActionChange, actionOrMapOrAsset, change, + k_InputOnActionChangeMarker, "InputSystem.onActionChange"); if (change == InputActionChange.BoundControlsChanged) - DelegateHelpers.InvokeCallbacksSafe(ref s_GlobalState.onActionControlsChanged, actionOrMapOrAsset, "onActionControlsChange"); + DelegateHelpers.InvokeCallbacksSafe(ref s_GlobalState.onActionControlsChanged, actionOrMapOrAsset, + "onActionControlsChange"); } /// @@ -4535,6 +4701,7 @@ internal static void OnDeviceChange(InputDevice device, InputDeviceChange change --i; continue; } + var state = (InputActionState)handle.Target; // If this state is not affected by the change, skip. @@ -4644,4 +4811,4 @@ internal static void DestroyAllActionMapStates() #endregion } -} +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs index dee118c96e..d79c2da5ea 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs @@ -17,18 +17,18 @@ namespace UnityEngine.InputSystem.Controls /// for how button presses on such buttons are handled. /// [Serializable] - public class ButtonControl : AxisControl + public class ButtonControl : AxisControl, IActuationPressPoint { private bool m_NeedsToCheckFramePress = false; private uint m_UpdateCountLastPressed = uint.MaxValue; private uint m_UpdateCountLastReleased = uint.MaxValue; private bool m_LastUpdateWasPress; - #if UNITY_EDITOR +#if UNITY_EDITOR // Editor input updates have a separate block of state memory, so must be checked separately private uint m_UpdateCountLastPressedEditor = uint.MaxValue; private uint m_UpdateCountLastReleasedEditor = uint.MaxValue; private bool m_LastUpdateWasPressEditor; - #endif +#endif internal bool needsToCheckFramePress { get; private set; } @@ -67,6 +67,10 @@ public class ButtonControl : AxisControl /// public float pressPointOrDefault => pressPoint > 0 ? pressPoint : s_GlobalDefaultButtonPressPoint; + float IActuationPressPoint.pressPoint => pressPoint; + + float IActuationPressPoint.pressPointOrDefault => pressPointOrDefault; + /// /// Default-initialize the button control. /// @@ -91,6 +95,7 @@ public class ButtonControl : AxisControl /// /// /// + /// public ButtonControl() { m_StateBlock.format = InputStateBlock.FormatBit; @@ -201,10 +206,10 @@ public bool isPressed if (!needsToCheckFramePress) return IsValueConsideredPressed(value); - #if UNITY_EDITOR +#if UNITY_EDITOR if (InputUpdate.s_LatestUpdateType.IsEditorUpdate()) return m_LastUpdateWasPressEditor; - #endif +#endif return m_LastUpdateWasPress; } @@ -218,7 +223,7 @@ private void BeginTestingForFramePresses(bool currentlyPressed, bool pressedLast needsToCheckFramePress = true; device.m_ButtonControlsCheckingPressState.Add(this); - #if UNITY_EDITOR +#if UNITY_EDITOR if (InputUpdate.s_LatestUpdateType.IsEditorUpdate()) { m_LastUpdateWasPressEditor = currentlyPressed; @@ -228,7 +233,7 @@ private void BeginTestingForFramePresses(bool currentlyPressed, bool pressedLast m_UpdateCountLastReleasedEditor = device.m_CurrentUpdateStepCount; } else - #endif +#endif { m_LastUpdateWasPress = currentlyPressed; if (currentlyPressed && !pressedLastFrame) @@ -291,10 +296,10 @@ public bool wasPressedThisFrame return device.wasUpdatedThisFrame && currentlyPressed && !pressedLastFrame; } - #if UNITY_EDITOR +#if UNITY_EDITOR if (InputUpdate.s_LatestUpdateType.IsEditorUpdate()) return InputUpdate.s_UpdateStepCount == m_UpdateCountLastPressedEditor; - #endif +#endif return InputUpdate.s_UpdateStepCount == m_UpdateCountLastPressed; } } @@ -336,10 +341,10 @@ public bool wasReleasedThisFrame return device.wasUpdatedThisFrame && !currentlyPressed && pressedLastFrame; } - #if UNITY_EDITOR +#if UNITY_EDITOR if (InputUpdate.s_LatestUpdateType.IsEditorUpdate()) return InputUpdate.s_UpdateStepCount == m_UpdateCountLastReleasedEditor; - #endif +#endif return InputUpdate.s_UpdateStepCount == m_UpdateCountLastReleased; } } @@ -359,7 +364,7 @@ internal void UpdateWasPressed() } } - #if UNITY_EDITOR +#if UNITY_EDITOR internal void UpdateWasPressedEditor() { var isNowPressed = IsValueConsideredPressed(value); @@ -375,7 +380,7 @@ internal void UpdateWasPressedEditor() } } - #endif // UNITY_EDITOR +#endif // UNITY_EDITOR // We make the current global default button press point available as a static so that we don't have to // constantly make the hop from InputSystem.settings -> InputManager.m_Settings -> defaultButtonPressPoint. @@ -386,4 +391,4 @@ internal void UpdateWasPressedEditor() // to implicitly be pressed all the time. Not useful. internal const float kMinButtonPressPoint = 0.0001f; } -} +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/InputControlExtensions.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/InputControlExtensions.cs index 38282c06c1..0ac5e2593d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/InputControlExtensions.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/InputControlExtensions.cs @@ -46,14 +46,17 @@ public static TControl FindInParentChain(this InputControl control) /// Check whether the given control is considered pressed according to the button press threshold. /// /// Control to check. - /// Optional custom button press point. If not supplied, - /// is used. + /// Optional custom press threshold. If not supplied, controls implementing + /// use ; otherwise + /// is used. /// True if the actuation of the given control is high enough for it to be considered pressed. /// is null. /// - /// This method checks the actuation level of the control as does. For s - /// and other float value controls, this will effectively check whether the float value of the control exceeds the button - /// point threshold. Note that if the control is an axis that can be both positive and negative, the press threshold works in + /// This method checks the actuation level of the control as does. For controls implementing + /// (including and ), + /// the default threshold comes from . For vector controls the threshold + /// applies to . For other float axes, the float value is compared to the threshold. + /// Note that if the control is an axis that can be both positive and negative, the press threshold works in /// both directions, i.e. it can be crossed both in the positive direction and in the negative direction. /// /// @@ -65,11 +68,12 @@ public static bool IsPressed(this InputControl control, float buttonPressPoint = throw new ArgumentNullException(nameof(control)); if (Mathf.Approximately(0, buttonPressPoint)) { - if (control is ButtonControl button) - buttonPressPoint = button.pressPointOrDefault; + if (control is IActuationPressPoint actuation) + buttonPressPoint = actuation.pressPointOrDefault; else buttonPressPoint = ButtonControl.s_GlobalDefaultButtonPressPoint; } + return control.IsActuated(buttonPressPoint); } @@ -210,8 +214,10 @@ public static TValue ReadValueFromEvent(this InputControl contro /// is null. /// is not a or . /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#")] - public static unsafe bool ReadValueFromEvent(this InputControl control, InputEventPtr inputEvent, out TValue value) + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", + MessageId = "2#")] + public static unsafe bool ReadValueFromEvent(this InputControl control, + InputEventPtr inputEvent, out TValue value) where TValue : struct { if (control == null) @@ -249,7 +255,8 @@ public static unsafe object ReadValueFromEventAsObject(this InputControl control return control.ReadValueFromStateAsObject(statePtr); } - public static TValue ReadUnprocessedValueFromEvent(this InputControl control, InputEventPtr eventPtr) + public static TValue ReadUnprocessedValueFromEvent(this InputControl control, + InputEventPtr eventPtr) where TValue : struct { if (control == null) @@ -260,8 +267,10 @@ public static TValue ReadUnprocessedValueFromEvent(this InputControl(this InputControl control, InputEventPtr inputEvent, out TValue value) + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", + MessageId = "2#")] + public static unsafe bool ReadUnprocessedValueFromEvent(this InputControl control, + InputEventPtr inputEvent, out TValue value) where TValue : struct { if (control == null) @@ -279,7 +288,8 @@ public static unsafe bool ReadUnprocessedValueFromEvent(this InputContro } ////REVIEW: this has the opposite argument order of WriteValueFromObjectIntoState; fix! - public static unsafe void WriteValueFromObjectIntoEvent(this InputControl control, InputEventPtr eventPtr, object value) + public static unsafe void WriteValueFromObjectIntoEvent(this InputControl control, InputEventPtr eventPtr, + object value) { if (control == null) throw new ArgumentNullException(nameof(control)); @@ -337,7 +347,8 @@ public static unsafe void WriteValueIntoState(this InputControl control, controlOfType.WriteValueIntoState(value, statePtr); } - public static unsafe void WriteValueIntoState(this InputControl control, TValue value, void* statePtr) + public static unsafe void WriteValueIntoState(this InputControl control, TValue value, + void* statePtr) where TValue : struct { if (control == null) @@ -369,7 +380,8 @@ public static unsafe void WriteValueIntoState(this InputControl /// is null. /// Control's value does not fit within the memory of . /// does not support writing. - public static unsafe void WriteValueIntoState(this InputControl control, TValue value, ref TState state) + public static unsafe void WriteValueIntoState(this InputControl control, TValue value, + ref TState state) where TValue : struct where TState : struct, IInputStateTypeInfo { @@ -403,7 +415,8 @@ public static void WriteValueIntoEvent(this InputControl control, TValue controlOfType.WriteValueIntoEvent(value, eventPtr); } - public static unsafe void WriteValueIntoEvent(this InputControl control, TValue value, InputEventPtr eventPtr) + public static unsafe void WriteValueIntoEvent(this InputControl control, TValue value, + InputEventPtr eventPtr) where TValue : struct { if (control == null) @@ -595,7 +608,8 @@ public static unsafe bool CompareStateIgnoringNoise(this InputControl control, v /// (e.g. if both stick values fall below the deadzone). /// /// - public static unsafe bool CompareState(this InputControl control, void* firstStatePtr, void* secondStatePtr, void* maskPtr = null) + public static unsafe bool CompareState(this InputControl control, void* firstStatePtr, void* secondStatePtr, + void* maskPtr = null) { ////REVIEW: for compound controls, do we want to go check leaves so as to not pick up on non-control noise in the state? //// e.g. from HID input reports; or should we just leave that to maskPtr? @@ -612,7 +626,7 @@ public static unsafe bool CompareState(this InputControl control, void* firstSta return true; return MemoryHelpers.ReadSingleBit(secondPtr, control.m_StateBlock.bitOffset) == - MemoryHelpers.ReadSingleBit(firstPtr, control.m_StateBlock.bitOffset); + MemoryHelpers.ReadSingleBit(firstPtr, control.m_StateBlock.bitOffset); } return MemoryHelpers.MemCmpBitRegion(firstPtr, secondPtr, @@ -704,7 +718,8 @@ public static unsafe bool HasValueChangeInEvent(this InputControl control, Input return GetStatePtrFromStateEventUnchecked(control, eventPtr, eventPtr.type); } - internal static unsafe void* GetStatePtrFromStateEventUnchecked(this InputControl control, InputEventPtr eventPtr, FourCC eventType) + internal static unsafe void* GetStatePtrFromStateEventUnchecked(this InputControl control, + InputEventPtr eventPtr, FourCC eventType) { uint stateOffset; FourCC stateFormat; @@ -732,7 +747,8 @@ public static unsafe bool HasValueChangeInEvent(this InputControl control, Input } else { - throw new ArgumentException($"Event must be a StateEvent or DeltaStateEvent but is a {eventType} instead", + throw new ArgumentException( + $"Event must be a StateEvent or DeltaStateEvent but is a {eventType} instead", nameof(eventPtr)); } @@ -811,7 +827,8 @@ public static unsafe bool ResetToDefaultStateInEvent(this InputControl control, ref var stateBlock = ref control.m_StateBlock; var offset = stateBlock.byteOffset; - MemoryHelpers.MemCpyBitRegion(statePtr + offset, defaultStatePtr + offset, stateBlock.bitOffset, stateBlock.sizeInBits); + MemoryHelpers.MemCpyBitRegion(statePtr + offset, defaultStatePtr + offset, stateBlock.bitOffset, + stateBlock.sizeInBits); return true; } @@ -861,7 +878,8 @@ public static void QueueValueChange(this InputControl control, T /// This can be the case, for example, for s. /// /// - public static unsafe void AccumulateValueInEvent(this InputControl control, void* currentStatePtr, InputEventPtr newState) + public static unsafe void AccumulateValueInEvent(this InputControl control, void* currentStatePtr, + InputEventPtr newState) { if (control == null) throw new ArgumentNullException(nameof(control)); @@ -873,7 +891,8 @@ public static unsafe void AccumulateValueInEvent(this InputControl contro control.WriteValueIntoEvent(oldValue + newValue, newState); } - internal static unsafe void AccumulateValueInEvent(this InputControl control, void* currentStatePtr, InputEventPtr newState) + internal static unsafe void AccumulateValueInEvent(this InputControl control, void* currentStatePtr, + InputEventPtr newState) { if (control == null) throw new ArgumentNullException(nameof(control)); @@ -885,7 +904,8 @@ internal static unsafe void AccumulateValueInEvent(this InputControl co control.WriteValueIntoEvent(oldDelta + newValue, newState); } - public static void FindControlsRecursive(this InputControl parent, IList controls, Func predicate) + public static void FindControlsRecursive(this InputControl parent, IList controls, + Func predicate) where TControl : InputControl { if (parent == null) @@ -945,7 +965,9 @@ internal static string BuildPath(this InputControl control, string deviceLayout, /// /// Flags that control which controls are returned by . /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1714:Flags enums should have plural names", Justification = "False positive: `IgnoreControlsInDefaultState` is a plural form.")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", + "CA1714:Flags enums should have plural names", + Justification = "False positive: `IgnoreControlsInDefaultState` is a plural form.")] [Flags] public enum Enumerate { @@ -1003,14 +1025,16 @@ public enum Enumerate /// /// /// - public static InputEventControlCollection EnumerateControls(this InputEventPtr eventPtr, Enumerate flags, InputDevice device = null, float magnitudeThreshold = 0) + public static InputEventControlCollection EnumerateControls(this InputEventPtr eventPtr, Enumerate flags, + InputDevice device = null, float magnitudeThreshold = 0) { if (!eventPtr.valid) throw new ArgumentNullException(nameof(eventPtr), "Given event pointer must not be null"); var eventType = eventPtr.type; if (eventType != StateEvent.Type && eventType != DeltaStateEvent.Type) - throw new ArgumentException($"Event must be a StateEvent or DeltaStateEvent but is a {eventType} instead", nameof(eventPtr)); + throw new ArgumentException( + $"Event must be a StateEvent or DeltaStateEvent but is a {eventType} instead", nameof(eventPtr)); // Look up device from event, if no device was supplied. if (device == null) @@ -1018,10 +1042,14 @@ public static InputEventControlCollection EnumerateControls(this InputEventPtr e var deviceId = eventPtr.deviceId; device = InputSystem.GetDeviceById(deviceId); if (device == null) - throw new ArgumentException($"Cannot find device with ID {deviceId} referenced by event", nameof(eventPtr)); + throw new ArgumentException($"Cannot find device with ID {deviceId} referenced by event", + nameof(eventPtr)); } - return new InputEventControlCollection { m_Device = device, m_EventPtr = eventPtr, m_Flags = flags, m_MagnitudeThreshold = magnitudeThreshold }; + return new InputEventControlCollection + { + m_Device = device, m_EventPtr = eventPtr, m_Flags = flags, m_MagnitudeThreshold = magnitudeThreshold + }; } /// @@ -1060,10 +1088,11 @@ public static InputEventControlCollection EnumerateControls(this InputEventPtr e /// /// /// - public static InputEventControlCollection EnumerateChangedControls(this InputEventPtr eventPtr, InputDevice device = null, float magnitudeThreshold = 0) + public static InputEventControlCollection EnumerateChangedControls(this InputEventPtr eventPtr, + InputDevice device = null, float magnitudeThreshold = 0) { return eventPtr.EnumerateControls - (Enumerate.IgnoreControlsInCurrentState, device, magnitudeThreshold); + (Enumerate.IgnoreControlsInCurrentState, device, magnitudeThreshold); } /// @@ -1078,7 +1107,8 @@ public static InputEventControlCollection EnumerateChangedControls(this InputEve /// the referenced by the in the event cannot be found. /// /// - public static bool HasButtonPress(this InputEventPtr eventPtr, float magnitude = -1, bool buttonControlsOnly = true) + public static bool HasButtonPress(this InputEventPtr eventPtr, float magnitude = -1, + bool buttonControlsOnly = true) { return eventPtr.GetFirstButtonPressOrNull(magnitude, buttonControlsOnly) != null; } @@ -1104,7 +1134,8 @@ public static bool HasButtonPress(this InputEventPtr eventPtr, float magnitude = /// in the devices state memory. For example, in the gamepad state, button north (bit position 4) will be evaluated before button /// east (bit position 5), so if both buttons were pressed in the given event, button north would be returned. /// Note that the function returns null if the is not a StateEvent or DeltaStateEvent. - public static unsafe InputControl GetFirstButtonPressOrNull(this InputEventPtr eventPtr, float magnitude = -1, bool buttonControlsOnly = true) + public static unsafe InputControl GetFirstButtonPressOrNull(this InputEventPtr eventPtr, float magnitude = -1, + bool buttonControlsOnly = true) { if (eventPtr.type != StateEvent.Type && eventPtr.type != DeltaStateEvent.Type) return null; @@ -1112,20 +1143,23 @@ public static unsafe InputControl GetFirstButtonPressOrNull(this InputEventPtr e if (magnitude < 0) magnitude = InputSystem.settings.defaultButtonPressPoint; - foreach (var control in eventPtr.EnumerateControls(Enumerate.IgnoreControlsInDefaultState, magnitudeThreshold: magnitude)) + foreach (var control in eventPtr.EnumerateControls(Enumerate.IgnoreControlsInDefaultState, + magnitudeThreshold: magnitude)) { // Skip if the value didn't change. For IInputStateCallbackReceiver devices (e.g. Touchscreen), // the event may not carry full device state, so fall back to checking the control was at // default (not pressed) before this event. var stateInEvent = control.GetStatePtrFromStateEvent(eventPtr); var currentState = control.currentStatePtr; - if (stateInEvent != null ? !control.CompareValue(currentState, stateInEvent) - : control.CompareValue(currentState, control.defaultStatePtr)) + if (stateInEvent != null + ? !control.CompareValue(currentState, stateInEvent) + : control.CompareValue(currentState, control.defaultStatePtr)) continue; if (buttonControlsOnly && !control.isButton) continue; return control; } + return null; } @@ -1141,7 +1175,8 @@ public static unsafe InputControl GetFirstButtonPressOrNull(this InputEventPtr e /// Returns an empty enumerable if the is not a or . /// /// - public static IEnumerable GetAllButtonPresses(this InputEventPtr eventPtr, float magnitude = -1, bool buttonControlsOnly = true) + public static IEnumerable GetAllButtonPresses(this InputEventPtr eventPtr, float magnitude = -1, + bool buttonControlsOnly = true) { if (eventPtr.type != StateEvent.Type && eventPtr.type != DeltaStateEvent.Type) yield break; @@ -1149,7 +1184,8 @@ public static IEnumerable GetAllButtonPresses(this InputEventPtr e if (magnitude < 0) magnitude = InputSystem.settings.defaultButtonPressPoint; - foreach (var control in eventPtr.EnumerateControls(Enumerate.IgnoreControlsInDefaultState, magnitudeThreshold: magnitude)) + foreach (var control in eventPtr.EnumerateControls(Enumerate.IgnoreControlsInDefaultState, + magnitudeThreshold: magnitude)) { if (buttonControlsOnly && !control.isButton) continue; @@ -1263,7 +1299,8 @@ public unsafe struct InputEventControlEnumerator : IEnumerator private uint m_EndBitOffset; private float m_MagnitudeThreshold; - internal InputEventControlEnumerator(InputEventPtr eventPtr, InputDevice device, Enumerate flags, float magnitudeThreshold = 0) + internal InputEventControlEnumerator(InputEventPtr eventPtr, InputDevice device, Enumerate flags, + float magnitudeThreshold = 0) { Debug.Assert(eventPtr.valid, "eventPtr should be valid at this point"); Debug.Assert(device != null, "Need to have valid device at this point"); @@ -1302,12 +1339,14 @@ internal InputEventControlEnumerator(InputEventPtr eventPtr, InputDevice device, private bool CheckDefault(uint numBits) { - return MemoryHelpers.MemCmpBitRegion(m_EventState, m_DefaultState, m_CurrentBitOffset, numBits, m_NoiseMask); + return MemoryHelpers.MemCmpBitRegion(m_EventState, m_DefaultState, m_CurrentBitOffset, numBits, + m_NoiseMask); } private bool CheckCurrent(uint numBits) { - return MemoryHelpers.MemCmpBitRegion(m_EventState, m_CurrentState, m_CurrentBitOffset, numBits, m_NoiseMask); + return MemoryHelpers.MemCmpBitRegion(m_EventState, m_CurrentState, m_CurrentBitOffset, numBits, + m_NoiseMask); } public bool MoveNext() @@ -1380,7 +1419,8 @@ public bool MoveNext() // See if we've reached the end. if (m_CurrentBitOffset >= m_EndBitOffset - || m_CurrentIndexInStateOffsetToControlIndexMap >= m_StateOffsetToControlIndexLength) // No more controls. + || m_CurrentIndexInStateOffsetToControlIndexMap >= + m_StateOffsetToControlIndexLength) // No more controls. return false; // No, so find the control at the current bit offset. @@ -1423,8 +1463,10 @@ public bool MoveNext() else { // Otherwise, we may need to check the bit region specifically for the control. - if ((ignoreCurrent && MemoryHelpers.MemCmpBitRegion(m_EventState, m_CurrentState, controlBitOffset - m_CurrentControlStateBitOffset, controlBitSize, m_NoiseMask)) - || (ignoreDefault && MemoryHelpers.MemCmpBitRegion(m_EventState, m_DefaultState, controlBitOffset - m_CurrentControlStateBitOffset, controlBitSize, m_NoiseMask))) + if ((ignoreCurrent && MemoryHelpers.MemCmpBitRegion(m_EventState, m_CurrentState, + controlBitOffset - m_CurrentControlStateBitOffset, controlBitSize, m_NoiseMask)) + || (ignoreDefault && MemoryHelpers.MemCmpBitRegion(m_EventState, m_DefaultState, + controlBitOffset - m_CurrentControlStateBitOffset, controlBitSize, m_NoiseMask))) continue; m_CurrentControl = m_AllControls[controlIndex]; @@ -1439,8 +1481,8 @@ public bool MoveNext() if ((m_Flags & Enumerate.IncludeSyntheticControls) == 0) { var controlHasSharedState = (m_CurrentControl.m_ControlFlags & - (InputControl.ControlFlags.UsesStateFromOtherControl | - InputControl.ControlFlags.IsSynthetic)) != 0; + (InputControl.ControlFlags.UsesStateFromOtherControl | + InputControl.ControlFlags.IsSynthetic)) != 0; // Filter out synthetic and useStateFrom controls. if (controlHasSharedState) @@ -1460,7 +1502,8 @@ public bool MoveNext() // its magnitude based on the data in the event and if it's too low, keep searching. if (m_MagnitudeThreshold != 0) { - var statePtr = m_EventState - (m_CurrentControlStateBitOffset >> 3) - m_Device.m_StateBlock.byteOffset; + var statePtr = m_EventState - (m_CurrentControlStateBitOffset >> 3) - + m_Device.m_StateBlock.byteOffset; var magnitude = m_CurrentControl.EvaluateMagnitude(statePtr); if (magnitude >= 0 && magnitude < m_MagnitudeThreshold) continue; @@ -1489,7 +1532,9 @@ public void Reset() else if (eventType == DeltaStateEvent.Type) { var deltaEvent = DeltaStateEvent.FromUnchecked(m_EventPtr); - m_EventState = (byte*)deltaEvent->deltaState - deltaEvent->stateOffset; // We access m_EventState as if it contains a full state event. + m_EventState = + (byte*)deltaEvent->deltaState - + deltaEvent->stateOffset; // We access m_EventState as if it contains a full state event. m_CurrentBitOffset = deltaEvent->stateOffset * 8; m_EndBitOffset = m_CurrentBitOffset + deltaEvent->deltaStateSizeInBytes * 8; stateFormat = deltaEvent->stateFormat; @@ -1509,7 +1554,8 @@ public void Reset() { var stateOffset = 0u; if (m_Device.hasStateCallbacks && - ((IInputStateCallbackReceiver)m_Device).GetStateOffsetForEvent(null, m_EventPtr, ref stateOffset)) + ((IInputStateCallbackReceiver)m_Device).GetStateOffsetForEvent(null, m_EventPtr, + ref stateOffset)) { m_CurrentControlStateBitOffset = stateOffset * 8; if (m_CurrentState != null) @@ -1562,6 +1608,7 @@ public void Dispose() // Undocumented APIs. Meant to be used only by auto-generated, precompiled layouts. // These APIs exist solely to keep access to the various properties/fields internal // and only allow their contents to be modified in a controlled manner. + #region Undocumented public static ControlBuilder Setup(this InputControl control) @@ -1569,7 +1616,8 @@ public static ControlBuilder Setup(this InputControl control) if (control == null) throw new ArgumentNullException(nameof(control)); if (control.isSetupFinished) - throw new InvalidOperationException($"The setup of {control} cannot be modified; control is already in use"); + throw new InvalidOperationException( + $"The setup of {control} cannot be modified; control is already in use"); return new ControlBuilder { control = control }; } @@ -1579,7 +1627,8 @@ public static DeviceBuilder Setup(this InputDevice device, int controlCount, int if (device == null) throw new ArgumentNullException(nameof(device)); if (device.isSetupFinished) - throw new InvalidOperationException($"The setup of {device} cannot be modified; control is already in use"); + throw new InvalidOperationException( + $"The setup of {device} cannot be modified; control is already in use"); if (controlCount < 1) throw new ArgumentOutOfRangeException(nameof(controlCount)); if (usageCount < 0) @@ -1596,6 +1645,7 @@ public static DeviceBuilder Setup(this InputDevice device, int controlCount, int device.m_UsagesForEachControl = new InternedString[usageCount]; device.m_UsageToControl = new InputControl[usageCount]; } + if (aliasCount > 0) device.m_AliasesForEachControl = new InternedString[aliasCount]; @@ -1609,12 +1659,12 @@ public struct ControlBuilder [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder At(InputDevice device, int index) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (device == null) throw new ArgumentNullException(nameof(device)); if (index < 0 || index >= device.m_ChildrenForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(index)); - #endif +#endif device.m_ChildrenForEachControl[index] = control; control.m_Device = device; return this; @@ -1623,12 +1673,12 @@ public ControlBuilder At(InputDevice device, int index) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithParent(InputControl parent) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (parent == null) throw new ArgumentNullException(nameof(parent)); if (parent == control) throw new ArgumentException("Control cannot be its own parent", nameof(parent)); - #endif +#endif control.m_Parent = parent; return this; } @@ -1636,10 +1686,10 @@ public ControlBuilder WithParent(InputControl parent) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithName(string name) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - #endif +#endif control.m_Name = new InternedString(name); return this; } @@ -1647,10 +1697,10 @@ public ControlBuilder WithName(string name) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithDisplayName(string displayName) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (string.IsNullOrEmpty(displayName)) throw new ArgumentNullException(nameof(displayName)); - #endif +#endif control.m_DisplayNameFromLayout = new InternedString(displayName); return this; } @@ -1658,10 +1708,10 @@ public ControlBuilder WithDisplayName(string displayName) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithShortDisplayName(string shortDisplayName) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (string.IsNullOrEmpty(shortDisplayName)) throw new ArgumentNullException(nameof(shortDisplayName)); - #endif +#endif control.m_ShortDisplayNameFromLayout = new InternedString(shortDisplayName); return this; } @@ -1669,10 +1719,10 @@ public ControlBuilder WithShortDisplayName(string shortDisplayName) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithLayout(InternedString layout) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (layout.IsEmpty()) throw new ArgumentException("Layout name cannot be empty", nameof(layout)); - #endif +#endif control.m_Layout = layout; return this; } @@ -1680,12 +1730,12 @@ public ControlBuilder WithLayout(InternedString layout) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithUsages(int startIndex, int count) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (startIndex < 0 || startIndex >= control.device.m_UsagesForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(startIndex)); if (count < 0 || startIndex + count > control.device.m_UsagesForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(count)); - #endif +#endif control.m_UsageStartIndex = startIndex; control.m_UsageCount = count; return this; @@ -1694,12 +1744,12 @@ public ControlBuilder WithUsages(int startIndex, int count) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithAliases(int startIndex, int count) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (startIndex < 0 || startIndex >= control.device.m_AliasesForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(startIndex)); if (count < 0 || startIndex + count > control.device.m_AliasesForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(count)); - #endif +#endif control.m_AliasStartIndex = startIndex; control.m_AliasCount = count; return this; @@ -1708,12 +1758,12 @@ public ControlBuilder WithAliases(int startIndex, int count) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ControlBuilder WithChildren(int startIndex, int count) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (startIndex < 0 || startIndex >= control.device.m_ChildrenForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(startIndex)); if (count < 0 || startIndex + count > control.device.m_ChildrenForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(count)); - #endif +#endif control.m_ChildStartIndex = startIndex; control.m_ChildCount = count; return this; @@ -1747,10 +1797,10 @@ public ControlBuilder WithProcessor(TProcessor processor) where TValue : struct where TProcessor : InputProcessor { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (processor == null) throw new ArgumentNullException(nameof(processor)); - #endif +#endif ////REVIEW: have a parameterized version of ControlBuilder so we don't need the cast? ////TODO: size array to exact needed size before-hand ((InputControl)control).m_ProcessorStack.Append(processor); @@ -1801,10 +1851,10 @@ public struct DeviceBuilder [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithName(string name) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - #endif +#endif device.m_Name = new InternedString(name); return this; } @@ -1812,10 +1862,10 @@ public DeviceBuilder WithName(string name) [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithDisplayName(string displayName) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (string.IsNullOrEmpty(displayName)) throw new ArgumentNullException(nameof(displayName)); - #endif +#endif device.m_DisplayNameFromLayout = new InternedString(displayName); return this; } @@ -1823,10 +1873,10 @@ public DeviceBuilder WithDisplayName(string displayName) [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithShortDisplayName(string shortDisplayName) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (string.IsNullOrEmpty(shortDisplayName)) throw new ArgumentNullException(nameof(shortDisplayName)); - #endif +#endif device.m_ShortDisplayNameFromLayout = new InternedString(shortDisplayName); return this; } @@ -1834,10 +1884,10 @@ public DeviceBuilder WithShortDisplayName(string shortDisplayName) [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithLayout(InternedString layout) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (layout.IsEmpty()) throw new ArgumentException("Layout name cannot be empty", nameof(layout)); - #endif +#endif device.m_Layout = layout; return this; } @@ -1845,12 +1895,12 @@ public DeviceBuilder WithLayout(InternedString layout) [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithChildren(int startIndex, int count) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (startIndex < 0 || startIndex >= device.device.m_ChildrenForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(startIndex)); if (count < 0 || startIndex + count > device.device.m_ChildrenForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(count)); - #endif +#endif device.m_ChildStartIndex = startIndex; device.m_ChildCount = count; return this; @@ -1873,14 +1923,14 @@ public DeviceBuilder IsNoisy(bool value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithControlUsage(int controlIndex, InternedString usage, InputControl control) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (controlIndex < 0 || controlIndex >= device.m_UsagesForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(controlIndex)); if (usage.IsEmpty()) throw new ArgumentException(nameof(usage)); if (control == null) throw new ArgumentNullException(nameof(control)); - #endif +#endif device.m_UsagesForEachControl[controlIndex] = usage; device.m_UsageToControl[controlIndex] = control; return this; @@ -1889,12 +1939,12 @@ public DeviceBuilder WithControlUsage(int controlIndex, InternedString usage, In [MethodImpl(MethodImplOptions.AggressiveInlining)] public DeviceBuilder WithControlAlias(int controlIndex, InternedString alias) { - #if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (controlIndex < 0 || controlIndex >= device.m_AliasesForEachControl.Length) throw new ArgumentOutOfRangeException(nameof(controlIndex)); if (alias.IsEmpty()) throw new ArgumentException(nameof(alias)); - #endif +#endif device.m_AliasesForEachControl[controlIndex] = alias; return this; } @@ -1912,7 +1962,7 @@ public unsafe DeviceBuilder WithControlTree(byte[] controlTreeNodes, ushort[] co var sizeOfNode = UnsafeUtility.SizeOf(); var numNodes = controlTreeNodes.Length / sizeOfNode; device.m_ControlTreeNodes = new InputDevice.ControlBitRangeNode[numNodes]; - fixed(byte* nodePtr = controlTreeNodes) + fixed (byte* nodePtr = controlTreeNodes) { for (var i = 0; i < numNodes; i++) { @@ -1945,4 +1995,4 @@ public void Finish() #endregion } -} +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/StickControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/StickControl.cs index 2ecea7f7a5..05950417df 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/StickControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/StickControl.cs @@ -36,6 +36,10 @@ namespace UnityEngine.InputSystem.Controls /// In terms of memory, a stick controls is still just from one value for the X axis /// and one value for the Y axis. /// + /// Stick magnitude uses the same / + /// mechanism as for + /// press-style polling (for example ). + /// /// Unlike dpads (see ), sticks will usually have deadzone processors /// (see ) applied to them to get rid of noise around the /// resting point of the stick. The X and Y axis also have deadzones applied to them by @@ -68,7 +72,8 @@ public class StickControl : Vector2Control /// /// The control is marked as . /// - [InputControl(useStateFrom = "y", processors = "axisDeadzone", parameters = "clamp=2,clampMin=0,clampMax=1", synthetic = true, displayName = "Up")] + [InputControl(useStateFrom = "y", processors = "axisDeadzone", parameters = "clamp=2,clampMin=0,clampMax=1", + synthetic = true, displayName = "Up")] // Set min&max on XY axes. We do this here as the documentation generator will not be happy // if we place this above the doc comment. // Also puts AxisDeadzones on the axes. @@ -83,7 +88,8 @@ public class StickControl : Vector2Control /// /// The control is marked as . /// - [InputControl(useStateFrom = "y", processors = "axisDeadzone", parameters = "clamp=2,clampMin=-1,clampMax=0,invert", synthetic = true, displayName = "Down")] + [InputControl(useStateFrom = "y", processors = "axisDeadzone", + parameters = "clamp=2,clampMin=-1,clampMax=0,invert", synthetic = true, displayName = "Down")] public ButtonControl down { get; set; } /// @@ -93,7 +99,8 @@ public class StickControl : Vector2Control /// /// The control is marked as . /// - [InputControl(useStateFrom = "x", processors = "axisDeadzone", parameters = "clamp=2,clampMin=-1,clampMax=0,invert", synthetic = true, displayName = "Left")] + [InputControl(useStateFrom = "x", processors = "axisDeadzone", + parameters = "clamp=2,clampMin=-1,clampMax=0,invert", synthetic = true, displayName = "Left")] public ButtonControl left { get; set; } /// @@ -103,7 +110,8 @@ public class StickControl : Vector2Control /// /// The control is marked as . /// - [InputControl(useStateFrom = "x", processors = "axisDeadzone", parameters = "clamp=2,clampMin=0,clampMax=1", synthetic = true, displayName = "Right")] + [InputControl(useStateFrom = "x", processors = "axisDeadzone", parameters = "clamp=2,clampMin=0,clampMax=1", + synthetic = true, displayName = "Right")] public ButtonControl right { get; set; } protected override void FinishSetup() @@ -116,4 +124,4 @@ protected override void FinishSetup() right = GetChildControl("right"); } } -} +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/Vector2Control.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/Vector2Control.cs index 995f034605..29a82fdf2c 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/Vector2Control.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/Vector2Control.cs @@ -20,7 +20,7 @@ namespace UnityEngine.InputSystem.Controls /// /// Normalization is not implied. The X and Y coordinates can be in any range or units. /// - public class Vector2Control : InputControl + public class Vector2Control : InputControl, IActuationPressPoint { /// /// Horizontal position of the control. @@ -36,6 +36,30 @@ public class Vector2Control : InputControl [InputControl(offset = 4, displayName = "Y")] public AxisControl y { get; set; } + /// + /// Minimum vector magnitude before the control is considered pressed for purposes such as + /// when this control drives the action. + /// + /// + /// By default, this property is set to -1. If the value of the property is negative, + /// is used unless a + /// on the binding sets an explicit + /// pressPoint (see remarks). + /// + /// + /// + /// + public float pressPoint = -1; + + /// + /// Return if set, otherwise return . + /// + public float pressPointOrDefault => pressPoint > 0 ? pressPoint : ButtonControl.s_GlobalDefaultButtonPressPoint; + + float IActuationPressPoint.pressPoint => pressPoint; + + float IActuationPressPoint.pressPointOrDefault => pressPointOrDefault; + /// /// Default-initialize the control. /// @@ -103,4 +127,4 @@ protected override FourCC CalculateOptimizedControlDataType() return InputStateBlock.FormatInvalid; } } -} +} \ No newline at end of file