diff --git a/Assets/Tests/InputSystem/ActuationPressPointTests.cs b/Assets/Tests/InputSystem/ActuationPressPointTests.cs new file mode 100644 index 0000000000..a499e3cf85 --- /dev/null +++ b/Assets/Tests/InputSystem/ActuationPressPointTests.cs @@ -0,0 +1,676 @@ +using System; +using NUnit.Framework; +using Unity.PerformanceTesting; +using UnityEngine; +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.Controls; +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 + + #region Performance (GetActuationPressThreshold vs legacy resolution) + + // Run these with Window > Analysis > Test Report (Performance) or test-framework-performance. + // Sample groups use the default time unit (milliseconds) in the performance report. + // Each test uses MeasurementCount(1000) for comparable sample counts across runs. + // GetActuationPressThreshold.* samples only exist on branches that include that API; Legacy.* + // mirror develop's control-only resolution (no binding interaction scan) for side-by-side timing. + + // Matches InputActionState.ProcessButtonState on develop (before actuation press alignment work): + // press point from ButtonControl when control is flagged as a button, otherwise global default. + private static float LegacyProcessButtonStateStylePressPoint(InputControl control) + { + return control.isButton + ? ((ButtonControl)control).pressPointOrDefault + : ButtonControl.s_GlobalDefaultButtonPressPoint; + } + + // Matches InputActionState.ProcessDefaultInteraction button branches on develop: + // concrete ButtonControl pattern, else global default (Vector2 / stick used this path too). + private static float LegacyDefaultInteractionButtonStylePressPoint(InputControl control) + { + return control is ButtonControl button ? button.pressPointOrDefault : ButtonControl.s_GlobalDefaultButtonPressPoint; + } + + private static unsafe bool TryGetStateBindingForControl(InputAction action, InputControl control, + out InputActionState state, out int bindingIndexInState) + { + state = null; + bindingIndexInState = -1; + + var map = action.GetOrCreateActionMap(); + map.ResolveBindingsIfNecessary(); + state = map.m_State; + if (state == null) + return false; + + var actionIndex = action.m_ActionIndexInState; + for (var i = 0; i < state.totalControlCount; ++i) + { + if (state.controls[i] != control) + continue; + var bindingIndex = state.controlIndexToBindingIndex[i]; + if (state.bindingStates[bindingIndex].actionIndex != actionIndex) + continue; + bindingIndexInState = bindingIndex; + return true; + } + + return false; + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public unsafe void Performance_GetActuationPressThreshold_GamepadButton_NoInteractions() + { + var gamepad = InputSystem.AddDevice(); + var action = new InputAction(type: InputActionType.Button, binding: "/buttonSouth"); + action.Enable(); + Assert.That(TryGetStateBindingForControl(action, gamepad.buttonSouth, out var state, out var bindingIndex), + Is.True); + + Measure.Method(() => + { + var bindingPtr = &state.bindingStates[bindingIndex]; + _ = state.GetActuationPressThreshold(gamepad.buttonSouth, bindingPtr); + }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("GetActuationPressThreshold.Button.NoInteractions") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_Legacy_ProcessButtonStateStyle_GamepadButton() + { + var gamepad = InputSystem.AddDevice(); + + Measure.Method(() => { _ = LegacyProcessButtonStateStylePressPoint(gamepad.buttonSouth); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("Legacy.ProcessButtonStateStyle.Button") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_Legacy_DefaultInteractionStyle_GamepadButton() + { + var gamepad = InputSystem.AddDevice(); + + Measure.Method(() => { _ = LegacyDefaultInteractionButtonStylePressPoint(gamepad.buttonSouth); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("Legacy.DefaultInteractionStyle.Button") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public unsafe void Performance_GetActuationPressThreshold_GamepadStick_NoInteractions() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + + var gamepad = InputSystem.AddDevice(); + var action = new InputAction( + type: InputActionType.Value, + expectedControlType: "Vector2", + binding: "/leftStick"); + action.Enable(); + Assert.That(TryGetStateBindingForControl(action, gamepad.leftStick, out var state, out var bindingIndex), + Is.True); + + Measure.Method(() => + { + var bindingPtr = &state.bindingStates[bindingIndex]; + _ = state.GetActuationPressThreshold(gamepad.leftStick, bindingPtr); + }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("GetActuationPressThreshold.Vector2.NoInteractions") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_Legacy_ProcessButtonStateStyle_GamepadStick() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + + Measure.Method(() => { _ = LegacyProcessButtonStateStylePressPoint(gamepad.leftStick); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("Legacy.ProcessButtonStateStyle.Vector2") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public unsafe void Performance_GetActuationPressThreshold_TriggerWithPressInteraction_ScansInteractions() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + + var gamepad = InputSystem.AddDevice(); + var action = new InputAction( + type: InputActionType.Button, + binding: "/leftTrigger", + interactions: "press(pressPoint=0.65),SlowTap(duration=0.4)"); + action.Enable(); + Assert.That(TryGetStateBindingForControl(action, gamepad.leftTrigger, out var state, out var bindingIndex), + Is.True); + + Measure.Method(() => + { + var bindingPtr = &state.bindingStates[bindingIndex]; + _ = state.GetActuationPressThreshold(gamepad.leftTrigger, bindingPtr); + }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("GetActuationPressThreshold.WithInteractions.Scan") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_Legacy_DefaultInteractionStyle_GamepadTrigger() + { + var gamepad = InputSystem.AddDevice(); + + Measure.Method(() => { _ = LegacyDefaultInteractionButtonStylePressPoint(gamepad.leftTrigger); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("Legacy.DefaultInteractionStyle.Axis") + .Run(); + } + + #endregion + + #region Performance (InputControlExtensions.IsPressed — develop vs current) + + // Develop used `control is ButtonControl` for default press-point resolution; current uses + // `control is IActuationPressPoint`. Legacy helper mirrors develop's IsPressed body when the + // optional threshold is omitted (same as default 0). Current tests call the real extension method. + + /// + /// Matches InputControlExtensions.IsPressed on develop when is 0 + /// (default threshold path only). + /// + private static bool LegacyIsPressedDevelopStyle(InputControl control, float buttonPressPoint = 0) + { + if (control == null) + throw new ArgumentNullException(nameof(control)); + if (Mathf.Approximately(0, buttonPressPoint)) + { + if (control is ButtonControl button) + buttonPressPoint = button.pressPointOrDefault; + else + buttonPressPoint = ButtonControl.s_GlobalDefaultButtonPressPoint; + } + + return control.IsActuated(buttonPressPoint); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_IsPressed_Current_GamepadButtonSouth() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + Set(gamepad.buttonSouth, 0f); + InputSystem.Update(); + + Measure.Method(() => { _ = gamepad.buttonSouth.IsPressed(); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("IsPressed.Current.ButtonSouth") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_IsPressed_LegacyDevelopStyle_GamepadButtonSouth() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + Set(gamepad.buttonSouth, 0f); + InputSystem.Update(); + + Measure.Method(() => { _ = LegacyIsPressedDevelopStyle(gamepad.buttonSouth); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("IsPressed.LegacyDevelopStyle.ButtonSouth") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_IsPressed_Current_GamepadLeftStick() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + Set(gamepad.leftStick, Vector2.zero); + InputSystem.Update(); + + Measure.Method(() => { _ = gamepad.leftStick.IsPressed(); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("IsPressed.Current.LeftStick") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_IsPressed_LegacyDevelopStyle_GamepadLeftStick() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + Set(gamepad.leftStick, Vector2.zero); + InputSystem.Update(); + + Measure.Method(() => { _ = LegacyIsPressedDevelopStyle(gamepad.leftStick); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("IsPressed.LegacyDevelopStyle.LeftStick") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_IsPressed_Current_GamepadLeftTrigger() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + Set(gamepad.leftTrigger, 0f); + InputSystem.Update(); + + Measure.Method(() => { _ = gamepad.leftTrigger.IsPressed(); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("IsPressed.Current.LeftTrigger") + .Run(); + } + + [Test, Performance] + [Category("Performance")] + [Category("ActuationPressPoint")] + public void Performance_IsPressed_LegacyDevelopStyle_GamepadLeftTrigger() + { + InputSystem.settings.defaultButtonPressPoint = 0.5f; + var gamepad = InputSystem.AddDevice(); + Set(gamepad.leftTrigger, 0f); + InputSystem.Update(); + + Measure.Method(() => { _ = LegacyIsPressedDevelopStyle(gamepad.leftTrigger); }) + .MeasurementCount(1000) + .WarmupCount(5) + .SampleGroup("IsPressed.LegacyDevelopStyle.LeftTrigger") + .Run(); + } + + #endregion +} 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..72631c2d13 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 @@ -473,8 +472,8 @@ 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; @@ -666,7 +665,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); @@ -922,7 +921,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] @@ -1678,26 +1677,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)); @@ -3850,7 +3840,8 @@ public void Actions_CanCreateActionAssetWithMultipleActionMaps() 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)) // map3/action4 should have been performed as the stick has been moved @@ -3869,10 +3860,10 @@ public void Actions_CanCreateActionAssetWithMultipleActionMaps() // map2/action3 should have been canceled. Canceled(action3, value: 0f, control: gamepad.buttonSouth, time: currentTime) // map3/action4 should have been canceled. - .AndThen(Canceled(action4, value: default(Vector2), control: gamepad.leftStick, - time: currentTime)) + .AndThen(Canceled(action4, value: default(Vector2), control: gamepad.leftStick, 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(); @@ -4177,9 +4168,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,12 +4181,12 @@ 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].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].control, Is.SameAs(gamepad.buttonNorth)); @@ -4639,8 +4630,7 @@ public void Actions_WhenTriggered_TriggerGlobalNotification() Set(gamepad.leftTrigger, 0); - Assert.That(receivedChanges, - Is.EquivalentTo(new[] {InputActionChange.ActionCanceled})); + Assert.That(receivedChanges, Is.EquivalentTo(new[] {InputActionChange.ActionCanceled})); } [Test] @@ -4778,22 +4768,22 @@ public void Actions_CanRecordActions_AndReadTheDataEvenIfBindingsHaveChanged() { 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) @@ -4903,8 +4893,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 +5210,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)); @@ -5488,7 +5478,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"); @@ -5530,16 +5520,20 @@ private void ValidateCompositeBindingsOnAction(InputAction action) 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 +5558,9 @@ public enum Modification public class ModificationCases : IEnumerable { [Preserve] - public ModificationCases() {} + public ModificationCases() + { + } private static readonly Modification[] ModificationAppliesToSingleActionMap = { @@ -5685,6 +5681,7 @@ bool NeedsFullResolve() case Modification.RemoveDeviceGlobally: return false; } + return true; } @@ -5698,6 +5695,7 @@ bool NeedsActionsToBeDisabled() case Modification.RemoveMap: return true; } + return false; } @@ -5860,7 +5858,11 @@ 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 +5871,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)); @@ -5966,9 +5970,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 +5994,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 +6026,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 +6063,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 +6093,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 +6135,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 +6161,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)); @@ -6378,6 +6382,7 @@ public override float Process(float value, InputControl control) return 1.0f; } } + private class ConstantFloat2TestProcessor : InputProcessor { public override float Process(float value, InputControl control) @@ -6532,7 +6537,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)); @@ -6639,15 +6644,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 +6666,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 +6690,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, ";"); @@ -7022,13 +7027,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 +7043,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")] @@ -7515,7 +7520,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 +7533,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"); @@ -7671,7 +7676,7 @@ public void Actions_CanTargetSingleDeviceWithMultipleActions() 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)); @@ -7701,8 +7706,8 @@ public void Actions_CanQueryStartAndPerformTime() 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)); @@ -7836,7 +7841,6 @@ public void Actions_CanIterateThroughCompositeBindings_WithAccessor() 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)); @@ -7944,7 +7948,7 @@ 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")); @@ -8213,10 +8217,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] @@ -8304,10 +8305,10 @@ public void Actions_CanRemoveActionFromMap() Assert.That(asset.FindAction("action2"), Is.Null); 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(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(map.bindings, Is.EquivalentTo(new[] { new InputBinding("/buttonSouth", action: "action1"), @@ -8477,7 +8478,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 +8491,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 +8504,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 +8520,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 +8632,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,13 +8759,13 @@ 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 }), Is.EqualTo(scheme2)); @@ -8818,12 +8819,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 +8842,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 +8850,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 +8893,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 +8921,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)); @@ -9010,8 +9011,8 @@ 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] @@ -9323,7 +9324,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 +9342,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 +9358,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; @@ -9525,7 +9526,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 +9535,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 +9560,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 +9579,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 +9587,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,7 +9597,7 @@ 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 @@ -9609,11 +9610,12 @@ public void Actions_CanCreateAxisComposite_AndDetermineWhichSideWins() // 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))); } } @@ -9803,83 +9805,6 @@ public void Actions_CanCreateVector2Composite_FromAnalogControls() 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)); - } - [Test] [Category("Actions")] public void Actions_Vector2Composite_WithKeyboardKeys_CancelOnRelease() @@ -10335,14 +10260,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; @@ -10657,8 +10576,7 @@ public void Actions_CanCreateCompositeWithVector2PartBinding() private class CompositeAskingForSourceControl : InputBindingComposite { - [InputControl(layout = "Button")] - public int button; + [InputControl(layout = "Button")] public int button; public override float ReadValue(ref InputBindingCompositeContext context) { @@ -11266,7 +11184,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 +11258,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 +11344,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); @@ -11663,8 +11581,7 @@ 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/ @@ -11728,7 +11645,7 @@ 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(); @@ -11743,7 +11660,7 @@ public void Actions_CanDriveFreeLookFromGamepadStickAndPointerDelta() 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(); @@ -11960,7 +11877,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"); @@ -12105,7 +12022,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. @@ -12440,26 +12357,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) { diff --git a/Assets/Tests/InputSystem/CoreTests_Controls.cs b/Assets/Tests/InputSystem/CoreTests_Controls.cs index 2bcd768c6b..9776706bff 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 @@ -611,7 +611,7 @@ public void Controls_CanReadValueFromStateEvents() Assert.That(gamepad.leftTrigger.ReadValueFromEventAsObject(eventPtr), Is.EqualTo(0.234f).Within(0.00001)); }; - InputSystem.QueueStateEvent(gamepad, new GamepadState {leftTrigger = 0.234f}); + InputSystem.QueueStateEvent(gamepad, new GamepadState { leftTrigger = 0.234f }); InputSystem.Update(); Assert.That(receivedCalls, Is.EqualTo(1)); @@ -758,7 +758,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 +775,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 +792,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 +811,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 +947,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 +974,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 +1155,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() @@ -1419,7 +1327,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,27 +1344,27 @@ 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)) list.AddSlice(toAdd, count: 1, destinationIndex: 1, sourceIndex: 2); @@ -1465,13 +1373,17 @@ public void Controls_CanKeepListsOfControls_WithoutAllocatingGCMemory() 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(); diff --git a/Packages/com.unity.inputsystem/Documentation~/Interactions.md b/Packages/com.unity.inputsystem/Documentation~/Interactions.md index 9d2541929c..2d976e14eb 100644 --- a/Packages/com.unity.inputsystem/Documentation~/Interactions.md +++ b/Packages/com.unity.inputsystem/Documentation~/Interactions.md @@ -172,6 +172,8 @@ If you haven't specifically added an Interaction to a Binding or its Action, the You can use a [`PressInteraction`](xref:UnityEngine.InputSystem.Interactions.PressInteraction) to explicitly force button-like interactions. Use the [`behavior`](xref:UnityEngine.InputSystem.Interactions.PressInteraction.behavior) parameter to select if the Interaction should trigger on button press, release, or both. +If you stack several `Press` interactions on the same binding, each still runs with its own parameters. Separately, [`IsPressed`](xref:UnityEngine.InputSystem.InputAction.IsPressed), [`WasPressedThisFrame`](xref:UnityEngine.InputSystem.InputAction.WasPressedThisFrame), and [`WasReleasedThisFrame`](xref:UnityEngine.InputSystem.InputAction.WasReleasedThisFrame) pick a single actuation threshold by scanning interactions in list order and using the `pressPoint` from the first `Press` interaction whose `pressPoint` is greater than zero. + |__Parameters__|Type|Default value| |---|---|---| |[`pressPoint`](xref:UnityEngine.InputSystem.Interactions.PressInteraction.pressPoint)|`float`|[`InputSettings.defaultButtonPressPoint`](xref:UnityEngine.InputSystem.InputSettings.defaultButtonPressPoint)| diff --git a/Packages/com.unity.inputsystem/Documentation~/RespondingToActions.md b/Packages/com.unity.inputsystem/Documentation~/RespondingToActions.md index f9f405b16d..3255f27ffd 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 lists one or more [Press](xref:UnityEngine.InputSystem.Interactions.PressInteraction) interactions, the `pressPoint` from the first in the binding's interaction order whose `pressPoint` is greater than zero (any interactions before it that are not `Press`, or `Press` with the default `pressPoint` of zero, are skipped for this step); 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.meta b/Packages/com.unity.inputsystem/InputSystem/Controls.meta new file mode 100644 index 0000000000..19d6acb751 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Controls.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 68167dadba7084e39b7561492a905ea0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: 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..cb120af43e --- /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. + /// + /// + /// + internal 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; } + } +} 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/Plugins.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins.meta new file mode 100644 index 0000000000..51b217a626 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe7bfd1c21cf2427da597939cddc7eef +folderAsset: yes +DefaultImporter: + externalObjects: {} + 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..f5baebb1f2 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputAction.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputAction.cs @@ -1137,9 +1137,8 @@ public void Reset() } /// - /// 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 +1154,15 @@ 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. If the binding lists several + /// instances, the first in interaction list order with an explicit + /// greater than zero is used. For composite bindings, interaction parameters are read from the composite binding. + /// Otherwise is used. /// /// /// @@ -1171,7 +1177,9 @@ public void Reset() /// was disabled even if the control is still actuated. /// /// + /// /// + /// /// /// /// @@ -1213,17 +1221,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 +1238,15 @@ 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. If the binding lists several + /// instances, the first in interaction list order with an explicit + /// greater than zero is used. For composite bindings, interaction parameters are read from the composite binding. + /// Otherwise is used. /// /// /// @@ -1271,7 +1284,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 +1295,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 +1326,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 +1337,15 @@ 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. If the binding lists several + /// instances, the first in interaction list order with an explicit + /// greater than zero is used. 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,7 +1769,7 @@ public unsafe float GetTimeoutCompletionPercentage() if (interactionState.totalTimeoutCompletionTimeRemaining > 0) { - return (interactionState.totalTimeoutCompletionDone + timerCompletion * interactionState.timerDuration) / + return (interactionState.totalTimeoutCompletionDone + timerCompletion * interactionState.timerDuration) / (interactionState.totalTimeoutCompletionDone + interactionState.totalTimeoutCompletionTimeRemaining); } else @@ -2431,9 +2456,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 +2494,9 @@ public TValue ReadValue() /// /// /// + /// /// + /// public bool ReadValueAsButton() { var value = false; diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputActionState.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/InputActionState.cs index 32b0354752..d570b9258e 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) @@ -1278,9 +1278,9 @@ private void UnhookOnBeforeUpdate() private void OnBeforeInitialUpdate() { if (InputState.currentUpdateType == InputUpdateType.BeforeRender - #if UNITY_EDITOR +#if UNITY_EDITOR || InputState.currentUpdateType == InputUpdateType.Editor - #endif +#endif ) return; @@ -1374,10 +1374,10 @@ 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); ProcessControlStateChange(mapIndex, controlIndex, bindingIndex, time, eventPtr); @@ -1596,12 +1596,56 @@ private void ProcessControlStateChange(int mapIndex, int controlIndex, int bindi } } + private BindingState* GetBindingStateForInteractionParameters(BindingState* bindingStatePtr) + { + if (bindingStatePtr->isPartOfComposite) + return &bindingStates[bindingStatePtr->compositeOrCompositeBindingIndex]; + return bindingStatePtr; + } + + // Resolves the explicit press threshold used to keep IsPressed / WasPressedThisFrame / WasReleasedThisFrame aligned + // with PressInteraction when the driving control does not set IActuationPressPoint.pressPoint. When multiple + // PressInteraction instances exist on the binding, uses the first in interaction list order with pressPoint > 0. + private bool TryGetExplicitPressInteractionPressPoint(BindingState* bindingStateForInteractions, ref float explicitPressInteraction) + { + var count = bindingStateForInteractions->interactionCount; + if (count == 0) + return false; + var start = bindingStateForInteractions->interactionStartIndex; + for (var i = 0; i < count; ++i) + { + if (interactions[start + i] is PressInteraction press && press.pressPoint > 0) + { + explicitPressInteraction = press.pressPoint; + return true; + } + } + + return false; + } + + internal float GetActuationPressThreshold(InputControl control, BindingState* bindingStatePtr) + { + var bindingForInteractions = GetBindingStateForInteractionParameters(bindingStatePtr); + float explicitPressThreshold = 0.0f; + var hasExplicitPressThreshold = TryGetExplicitPressInteractionPressPoint(bindingForInteractions, ref explicitPressThreshold); + + if (control is IActuationPressPoint actuation) + { + if (actuation.pressPoint > 0) + return actuation.pressPointOrDefault; + if (hasExplicitPressThreshold) + return explicitPressThreshold; + return actuation.pressPointOrDefault; + } + + return hasExplicitPressThreshold ? explicitPressThreshold : 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. @@ -1966,6 +2010,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: @@ -1984,7 +2029,7 @@ private void ProcessDefaultInteraction(ref TriggerState trigger, int actionIndex 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 +2059,7 @@ 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. @@ -2050,7 +2095,7 @@ 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); @@ -3240,17 +3285,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; } /// @@ -4335,13 +4375,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; diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/Interactions/PressInteraction.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/Interactions/PressInteraction.cs index b9eb9e4b47..cd0ab6192f 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/Interactions/PressInteraction.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Actions/Interactions/PressInteraction.cs @@ -25,6 +25,14 @@ namespace UnityEngine.InputSystem.Interactions /// behavior available out of the box when binding type actions to button-type controls /// () corresponds to using a press modifier with /// set to and left at default. + /// + /// When several instances are stacked on the same binding, each still runs with its own + /// parameters during interaction processing. Separately, button-style press tracking on the action (for example + /// , , and ) + /// resolves a single actuation threshold by scanning interactions on the binding in list order and using the + /// of the first in that sequence whose is greater than zero. + /// Earlier interactions that are not a , or that leave at the default of zero, are skipped + /// for this lookup. If none match, the control or project default applies instead. /// [DisplayName("Press")] public class PressInteraction : IInputInteraction diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs index dee118c96e..b9313985a0 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; } @@ -61,6 +61,7 @@ public class ButtonControl : AxisControl /// /// public float pressPoint = -1; + float IActuationPressPoint.pressPoint => pressPoint; /// /// Return if set, otherwise return . @@ -91,6 +92,7 @@ public class ButtonControl : AxisControl /// /// /// + /// public ButtonControl() { m_StateBlock.format = InputStateBlock.FormatBit; @@ -201,10 +203,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 +220,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 +230,7 @@ private void BeginTestingForFramePresses(bool currentlyPressed, bool pressedLast m_UpdateCountLastReleasedEditor = device.m_CurrentUpdateStepCount; } else - #endif +#endif { m_LastUpdateWasPress = currentlyPressed; if (currentlyPressed && !pressedLastFrame) @@ -291,10 +293,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 +338,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 +361,7 @@ internal void UpdateWasPressed() } } - #if UNITY_EDITOR +#if UNITY_EDITOR internal void UpdateWasPressedEditor() { var isNowPressed = IsValueConsideredPressed(value); @@ -375,7 +377,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. diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/InputControlExtensions.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/InputControlExtensions.cs index 38282c06c1..305af98a43 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,8 +68,8 @@ 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; } @@ -1021,7 +1024,10 @@ public static InputEventControlCollection EnumerateControls(this InputEventPtr e 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 + }; } /// @@ -1119,8 +1125,9 @@ public static unsafe InputControl GetFirstButtonPressOrNull(this InputEventPtr e // 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; @@ -1609,12 +1616,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 +1630,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 +1643,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 +1654,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 +1665,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 +1676,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 +1687,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 +1701,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 +1715,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 +1754,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 +1808,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 +1819,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 +1830,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 +1841,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 +1852,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 +1880,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 +1896,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; } diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/StickControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/StickControl.cs index 2ecea7f7a5..782964985c 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 diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/Vector2Control.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/Vector2Control.cs index 995f034605..7236658276 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,27 @@ 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.0f; + float IActuationPressPoint.pressPoint => pressPoint; + + /// + /// Return if set, otherwise return . + /// + public float pressPointOrDefault => pressPoint > 0.0f ? pressPoint : ButtonControl.s_GlobalDefaultButtonPressPoint; + /// /// Default-initialize the control. ///