diff --git a/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs b/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs index 8c0606809c..be52673469 100644 --- a/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs +++ b/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs @@ -530,6 +530,91 @@ public void PlayerInput_CanAutoSwitchControlSchemesInSinglePlayer() Assert.That(listener.messages, Is.EquivalentTo(new[] {new Message("OnFire", 1f)})); } + // Test setup where two players both use the keyboard but with two different control + // schemes. + [Test] + [Category("PlayerInput")] + public void PlayerInput_CanSetUpSplitKeyboardPlay() + { + var keyboard = InputSystem.AddDevice(); + + // We add a gamepad device and scheme just to add noise and make sure + // this isn't throwing the thing off the rails. + InputSystem.AddDevice(); + + const string kActions = @" + { + ""maps"" : [ + { + ""name"" : ""gameplay"", + ""actions"" : [ + { ""name"" : ""fire"", ""type"" : ""button"" } + ], + ""bindings"" : [ + { ""path"" : ""/buttonSouth"", ""action"" : ""fire"", ""groups"" : ""Gamepad"" }, + { ""path"" : ""/leftCtrl"", ""action"" : ""fire"", ""groups"" : ""KeyboardWASD"" }, + { ""path"" : ""/rightCtrl"", ""action"" : ""fire"", ""groups"" : ""KeyboardArrows"" } + ] + } + ], + ""controlSchemes"" : [ + { + ""name"" : ""Gamepad"", + ""bindingGroup"" : ""Gamepad"", + ""devices"" : [ + { ""devicePath"" : """" } + ] + }, + { + ""name"" : ""Keyboard WASD"", + ""bindingGroup"" : ""KeyboardWASD"", + ""devices"" : [ + { ""devicePath"" : """" } + ] + }, + { + ""name"" : ""Keyboard Arrows"", + ""bindingGroup"" : ""KeyboardArrows"", + ""devices"" : [ + { ""devicePath"" : """" } + ] + } + ] + }"; + + var prefab = new GameObject(); + prefab.SetActive(false); + prefab.AddComponent(); + prefab.AddComponent(); + prefab.GetComponent().actions = InputActionAsset.FromJson(kActions); + prefab.GetComponent().defaultActionMap = "gameplay"; + + var player1 = PlayerInput.Instantiate(prefab, controlScheme: "Keyboard WASD", pairWithDevice: keyboard); + var player2 = PlayerInput.Instantiate(prefab, controlScheme: "Keyboard Arrows", pairWithDevice: keyboard); + + Assert.That(player1.devices, Is.EquivalentTo(new[] { keyboard })); + Assert.That(player2.devices, Is.EquivalentTo(new[] { keyboard })); + Assert.That(player1.controlScheme, Is.EqualTo("Keyboard WASD")); + Assert.That(player2.controlScheme, Is.EqualTo("Keyboard Arrows")); + Assert.That(player1.actions["fire"].controls, Is.EquivalentTo(new[] { keyboard.leftCtrlKey })); + Assert.That(player2.actions["fire"].controls, Is.EquivalentTo(new[] { keyboard.rightCtrlKey })); + + Press(keyboard.leftCtrlKey); + + Assert.That(player1.GetComponent().messages, + Is.EquivalentTo(new[] {new Message { name = "OnFire", value = 1f }})); + Assert.That(player2.GetComponent().messages, Is.Empty); + + Release(keyboard.leftCtrlKey); + player1.GetComponent().messages.Clear(); + + Press(keyboard.rightCtrlKey); + + Assert.That(player1.GetComponent().messages, Is.Empty); + Assert.That(player2.GetComponent().messages, + Is.EquivalentTo(new[] {new Message { name = "OnFire", value = 1f }})); + } + [Test] [Category("PlayerInput")] public void PlayerInput_CanAutoSwitchControlSchemesInSinglePlayer_WithDevicePluggedInAfterStart() diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 200f3f64d0..6c93cc51a6 100755 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -15,6 +15,9 @@ however, it has to be formatted properly to pass verification tests. #### Actions +- `PlayerInput.Instantiate` now correctly sets up a given control scheme, if specified. + * When passing a `controlScheme:` argument, the result used to be a correctly assigned control scheme at the `InputUser` level but no restrictions being actually applied to the bindings, i.e. every single binding was active regardless of the specified control scheme. + ### Changed - `InputUser.onUnpairedDeviceUsed` now receives a 2nd argument which is the event that triggered the callback. diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/Users/InputUser.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/Users/InputUser.cs index ca7028c9e8..72de46082b 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Plugins/Users/InputUser.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/Users/InputUser.cs @@ -469,7 +469,7 @@ public void AssociateActionsWithUser(IInputActionCollection actions) { actions.devices = pairedDevices; if (s_AllUserData[userIndex].controlScheme != null) - ActivateControlScheme(s_AllUserData[userIndex].controlScheme.Value); + ActivateControlSchemeInternal(userIndex, s_AllUserData[userIndex].controlScheme.Value); } } @@ -508,34 +508,40 @@ public ControlSchemeChangeSyntax ActivateControlScheme(string schemeName) public ControlSchemeChangeSyntax ActivateControlScheme(InputControlScheme scheme) { var userIndex = index; // Throws if user is invalid. + + if (s_AllUserData[userIndex].controlScheme != scheme || + (scheme == default && s_AllUserData[userIndex].controlScheme != null)) + { + ActivateControlSchemeInternal(userIndex, scheme); + Notify(userIndex, InputUserChange.ControlSchemeChanged, null); + } + + return new ControlSchemeChangeSyntax {m_UserIndex = userIndex}; + } + + private void ActivateControlSchemeInternal(int userIndex, InputControlScheme scheme) + { var isEmpty = scheme == default; - if (s_AllUserData[userIndex].controlScheme != scheme || (isEmpty && s_AllUserData[userIndex].controlScheme != null)) + if (isEmpty) + s_AllUserData[userIndex].controlScheme = null; + else + s_AllUserData[userIndex].controlScheme = scheme; + + if (s_AllUserData[userIndex].actions != null) { if (isEmpty) - s_AllUserData[userIndex].controlScheme = null; + { + s_AllUserData[userIndex].actions.bindingMask = null; + s_AllUserData[userIndex].controlSchemeMatch.Dispose(); + s_AllUserData[userIndex].controlSchemeMatch = new InputControlScheme.MatchResult(); + } else - s_AllUserData[userIndex].controlScheme = scheme; - - if (s_AllUserData[userIndex].actions != null) { - if (isEmpty) - { - s_AllUserData[userIndex].actions.bindingMask = null; - s_AllUserData[userIndex].controlSchemeMatch.Dispose(); - s_AllUserData[userIndex].controlSchemeMatch = new InputControlScheme.MatchResult(); - } - else - { - s_AllUserData[userIndex].actions.bindingMask = new InputBinding {groups = scheme.bindingGroup}; - UpdateControlSchemeMatch(userIndex); - } + s_AllUserData[userIndex].actions.bindingMask = new InputBinding {groups = scheme.bindingGroup}; + UpdateControlSchemeMatch(userIndex); } - - Notify(userIndex, InputUserChange.ControlSchemeChanged, null); } - - return new ControlSchemeChangeSyntax {m_UserIndex = userIndex}; } public void PauseHaptics()