Skip to content

Commit

Permalink
FIX: PlayerInput.Instantiate not handling control schemes correctly (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Rene Damm committed Aug 23, 2019
1 parent 8d26e0a commit 9150693
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 21 deletions.
85 changes: 85 additions & 0 deletions Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs
Expand Up @@ -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<Keyboard>();

// 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<Gamepad>();

const string kActions = @"
{
""maps"" : [
{
""name"" : ""gameplay"",
""actions"" : [
{ ""name"" : ""fire"", ""type"" : ""button"" }
],
""bindings"" : [
{ ""path"" : ""<Gamepad>/buttonSouth"", ""action"" : ""fire"", ""groups"" : ""Gamepad"" },
{ ""path"" : ""<Keyboard>/leftCtrl"", ""action"" : ""fire"", ""groups"" : ""KeyboardWASD"" },
{ ""path"" : ""<Keyboard>/rightCtrl"", ""action"" : ""fire"", ""groups"" : ""KeyboardArrows"" }
]
}
],
""controlSchemes"" : [
{
""name"" : ""Gamepad"",
""bindingGroup"" : ""Gamepad"",
""devices"" : [
{ ""devicePath"" : ""<Gamepad>"" }
]
},
{
""name"" : ""Keyboard WASD"",
""bindingGroup"" : ""KeyboardWASD"",
""devices"" : [
{ ""devicePath"" : ""<Keyboard>"" }
]
},
{
""name"" : ""Keyboard Arrows"",
""bindingGroup"" : ""KeyboardArrows"",
""devices"" : [
{ ""devicePath"" : ""<Keyboard>"" }
]
}
]
}";

var prefab = new GameObject();
prefab.SetActive(false);
prefab.AddComponent<MessageListener>();
prefab.AddComponent<PlayerInput>();
prefab.GetComponent<PlayerInput>().actions = InputActionAsset.FromJson(kActions);
prefab.GetComponent<PlayerInput>().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<MessageListener>().messages,
Is.EquivalentTo(new[] {new Message { name = "OnFire", value = 1f }}));
Assert.That(player2.GetComponent<MessageListener>().messages, Is.Empty);

Release(keyboard.leftCtrlKey);
player1.GetComponent<MessageListener>().messages.Clear();

Press(keyboard.rightCtrlKey);

Assert.That(player1.GetComponent<MessageListener>().messages, Is.Empty);
Assert.That(player2.GetComponent<MessageListener>().messages,
Is.EquivalentTo(new[] {new Message { name = "OnFire", value = 1f }}));
}

[Test]
[Category("PlayerInput")]
public void PlayerInput_CanAutoSwitchControlSchemesInSinglePlayer_WithDevicePluggedInAfterStart()
Expand Down
3 changes: 3 additions & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Expand Up @@ -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.
Expand Down
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 9150693

Please sign in to comment.