Skip to content

Commit 25151d2

Browse files
author
Rene Damm
authored
FIX: Pasting binding with invalid control schemes (case 1276106, #1445).
1 parent cca1e3b commit 25151d2

6 files changed

Lines changed: 102 additions & 1 deletion

File tree

Assets/Tests/InputSystem/CoreTests_Editor.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,87 @@ public void Editor_ActionTree_CanCopyPasteBinding_IntoDifferentAction()
12591259
}
12601260
}
12611261

1262+
[Test]
1263+
[Category("Editor")]
1264+
public void Editor_ActionTree_CanCopyPasteBinding_IntoDifferentAsset()
1265+
{
1266+
var asset1 = ScriptableObject.CreateInstance<InputActionAsset>();
1267+
asset1.AddControlScheme("Gamepad").WithRequiredDevice<Gamepad>();
1268+
asset1.AddControlScheme("Keyboard").WithRequiredDevice<Keyboard>();
1269+
1270+
var map1 = asset1.AddActionMap("map");
1271+
var action1 = map1.AddAction("actionOnlyInFirstAsset");
1272+
var action2 = map1.AddAction("actionInBothAssets");
1273+
action1.AddBinding("<Gamepad>/leftStick", groups: "Gamepad");
1274+
action1.AddBinding("<Keyboard>/a", groups: "Keyboard");
1275+
action2.AddBinding("*/{Back}", groups: "Gamepad;Keyboard");
1276+
1277+
var asset2 = ScriptableObject.CreateInstance<InputActionAsset>();
1278+
asset2.AddControlScheme("Gamepad").WithRequiredDevice<Gamepad>();
1279+
asset2.AddControlScheme("Mouse").WithRequiredDevice<Mouse>();
1280+
1281+
var map2 = asset2.AddActionMap("map");
1282+
map2.AddAction("actionOnlyInSecondAsset");
1283+
map2.AddAction("actionInBothAssets");
1284+
1285+
var serializedObject1 = new SerializedObject(asset1);
1286+
var tree1 = new InputActionTreeView(serializedObject1)
1287+
{
1288+
onBuildTree = () => InputActionTreeView.BuildFullTree(serializedObject1),
1289+
};
1290+
tree1.Reload();
1291+
1292+
var serializedObject2 = new SerializedObject(asset2);
1293+
var tree2 = new InputActionTreeView(serializedObject2)
1294+
{
1295+
onBuildTree = () => InputActionTreeView.BuildFullTree(serializedObject2),
1296+
onBindingAdded = prop => InputActionSerializationHelpers.RemoveUnusedBindingGroups(prop, asset2.controlSchemes)
1297+
};
1298+
tree2.Reload();
1299+
1300+
using (new EditorHelpers.FakeSystemCopyBuffer())
1301+
{
1302+
// Copy <Gamepad>/leftStick binging from first asset.
1303+
tree1.SelectItem(tree1.FindItemByPropertyPath("m_ActionMaps.Array.data[0].m_Bindings.Array.data[0]"));
1304+
tree1.CopySelectedItemsToClipboard();
1305+
1306+
// Paste it onto actionOnlyInSecondAsset.
1307+
tree2.SelectItem("map/actionOnlyInSecondAsset");
1308+
tree2.PasteDataFromClipboard();
1309+
1310+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children, Has.Count.EqualTo(1));
1311+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children[0].As<BindingTreeItem>().path, Is.EqualTo("<Gamepad>/leftStick"));
1312+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children[0].As<BindingTreeItem>().groups, Is.EqualTo("Gamepad"));
1313+
1314+
// Copy <Keyboard>/a binging from first asset.
1315+
tree1.SelectItem(tree1.FindItemByPropertyPath("m_ActionMaps.Array.data[0].m_Bindings.Array.data[1]"));
1316+
tree1.CopySelectedItemsToClipboard();
1317+
1318+
// Paste it onto actionOnlyInSecondAsset in second asset.
1319+
tree2.SelectItem("map/actionOnlyInSecondAsset");
1320+
tree2.PasteDataFromClipboard();
1321+
1322+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children, Has.Count.EqualTo(2));
1323+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children[0].As<BindingTreeItem>().path, Is.EqualTo("<Gamepad>/leftStick"));
1324+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children[0].As<BindingTreeItem>().groups, Is.EqualTo("Gamepad"));
1325+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children[1].As<BindingTreeItem>().path, Is.EqualTo("<Keyboard>/a"));
1326+
Assert.That(tree2["map/actionOnlyInSecondAsset"].children[1].As<BindingTreeItem>().groups, Is.EqualTo(""));
1327+
1328+
// Copy */{Back} binging from first asset.
1329+
tree1.SelectItem(tree1.FindItemByPropertyPath("m_ActionMaps.Array.data[0].m_Bindings.Array.data[2]"));
1330+
tree1.CopySelectedItemsToClipboard();
1331+
1332+
// Paste it onto actionInBothAssets in second asset.
1333+
// NOTE: Apparently, we don't currently support just pasting it straight onto the map.
1334+
tree2.SelectItem("map/actionInBothAssets");
1335+
tree2.PasteDataFromClipboard();
1336+
1337+
Assert.That(tree2["map/actionInBothAssets"].children, Has.Count.EqualTo(1));
1338+
Assert.That(tree2["map/actionInBothAssets"].children[0].As<BindingTreeItem>().path, Is.EqualTo("*/{Back}"));
1339+
Assert.That(tree2["map/actionInBothAssets"].children[0].As<BindingTreeItem>().groups, Is.EqualTo("Gamepad"));
1340+
}
1341+
}
1342+
12621343
[Test]
12631344
[Category("Editor")]
12641345
public void Editor_ActionTree_CannotCopyPasteBinding_IntoActionMap()

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ however, it has to be formatted properly to pass verification tests.
4242
- Fixed `InputAction.IsPressed`/`WasPressed`/`WasReleased` returning incorrect results when binding multiple buttons on the same action and pressing/releasing them simultaneously.
4343
- Fixed interactions involving timeouts (such as `HoldInteraction`) performing erroneous delayed triggers on actions when input is composed of multiple controls ([1251231](https://issuetracker.unity3d.com/issues/input-system-composites-hold-interaction-can-be-performed-when-no-keys-are-hold)).
4444
* For example, if you bind `Shift+B` using a `OneModifierComposite` and put a `HoldInteraction` on the binding, then depending on the order in which the keys are pressed, you would sometimes see the action spuriously getting triggered when in fact no input was received.
45+
- Fixed control schemes of bindings not getting updates when being pasted from one `.inputactions` asset into another ([case 1276106](https://issuetracker.unity3d.com/issues/input-system-control-schemes-are-not-resolved-when-copying-bindings-between-inputactionassets)).
46+
* For example, if you copied a binding from an asset that had a "Gamepad" control scheme into an asset that had none, the resulting binding would be unusable.
47+
* All associations with control schemes that do not exist in the target asset are now removed from bindings upon pasting.
4548

4649
## [1.2.0] - 2021-10-22
4750

Packages/com.unity.inputsystem/InputSystem/Actions/InputBinding.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ public static InputBinding MaskByGroups(params string[] groups)
435435
[SerializeField] private string m_Path;
436436
[SerializeField] private string m_Interactions;
437437
[SerializeField] private string m_Processors;
438-
[SerializeField] private string m_Groups;
438+
[SerializeField] internal string m_Groups;
439439
[SerializeField] private string m_Action;
440440
[SerializeField] internal Flags m_Flags;
441441

Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputActionEditorWindow.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ private void InitializeTrees()
377377
{
378378
onSelectionChanged = OnActionTreeSelectionChanged,
379379
onSerializedObjectModified = ApplyAndReloadTrees,
380+
onBindingAdded = p => InputActionSerializationHelpers.RemoveUnusedBindingGroups(p, m_Toolbar.controlSchemes),
380381
drawMinusButton = false,
381382
title = ("Actions", "A list of InputActions in the InputActionMap selected in the left pane. Also, for each InputAction, the list "
382383
+ "of bindings that determine the controls that can trigger the action.\n\nThe name of each action must be unique within its InputActionMap."),

Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputActionTreeView.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,8 +888,12 @@ private SerializedProperty PasteBlock(string tag, string data, SerializedPropert
888888
// If we have a binding group to set for new bindings, overwrite the binding's
889889
// group with it.
890890
if (!string.IsNullOrEmpty(bindingGroupForNewBindings))
891+
{
891892
InputActionSerializationHelpers.ChangeBinding(property,
892893
groups: bindingGroupForNewBindings);
894+
}
895+
896+
onBindingAdded?.Invoke(property);
893897
}
894898

895899
return property;
@@ -1108,6 +1112,7 @@ public void AddNewBinding(SerializedProperty actionProperty, SerializedProperty
11081112
{
11091113
var bindingProperty = InputActionSerializationHelpers.AddBinding(actionProperty, actionMapProperty,
11101114
groups: bindingGroupForNewBindings);
1115+
onBindingAdded?.Invoke(bindingProperty);
11111116
OnNewItemAdded(bindingProperty);
11121117
}
11131118

@@ -1125,6 +1130,7 @@ public void AddNewComposite(SerializedProperty actionProperty, SerializedPropert
11251130
nameof(compositeName));
11261131
var compositeProperty = InputActionSerializationHelpers.AddCompositeBinding(actionProperty,
11271132
actionMapProperty, compositeName, compositeType, groups: bindingGroupForNewBindings);
1133+
onBindingAdded?.Invoke(compositeProperty);
11281134
OnNewItemAdded(compositeProperty);
11291135
}
11301136

@@ -1410,6 +1416,7 @@ private bool ReloadIfSerializedObjectHasBeenChanged()
14101416
public Action<ActionTreeItemBase> onDoubleClick { get; set; }
14111417
public Action<ActionTreeItemBase> onBeginRename { get; set; }
14121418
public Func<TreeViewItem> onBuildTree { get; set; }
1419+
public Action<SerializedProperty> onBindingAdded { get; set; }
14131420

14141421
public bool drawHeader { get; set; }
14151422
public bool drawPlusButton { get; set; }

Packages/com.unity.inputsystem/InputSystem/Editor/Internal/InputActionSerializationHelpers.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,15 @@ public static void ReplaceBindingGroup(SerializedObject asset, string oldBinding
624624
}
625625
}
626626
}
627+
628+
public static void RemoveUnusedBindingGroups(SerializedProperty binding, ReadOnlyArray<InputControlScheme> controlSchemes)
629+
{
630+
var groupsProperty = binding.FindPropertyRelative(nameof(InputBinding.m_Groups));
631+
groupsProperty.stringValue = string.Join(InputBinding.kSeparatorString,
632+
groupsProperty.stringValue
633+
.Split(InputBinding.Separator)
634+
.Where(g => controlSchemes.Any(c => c.bindingGroup.Equals(g, StringComparison.InvariantCultureIgnoreCase))));
635+
}
627636
}
628637
}
629638
#endif // UNITY_EDITOR

0 commit comments

Comments
 (0)