123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- #if UNITY_EDITOR
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Text;
- using UnityEditor;
- using UnityEngine.InputSystem.Layouts;
- using UnityEngine.InputSystem.Utilities;
-
- ////TODO: resolving bindings to actions needs to take "{id}" form into account
-
- namespace UnityEngine.InputSystem.Editor
- {
- // Helpers for doctoring around in InputActions using SerializedProperties.
- internal static class InputActionSerializationHelpers
- {
- public static string GetName(SerializedProperty element)
- {
- using (var nameProperty = element.FindPropertyRelative("m_Name"))
- {
- Debug.Assert(nameProperty != null, $"Cannot find m_Name property in {element.propertyPath}");
- return nameProperty.stringValue;
- }
- }
-
- public static Guid GetId(SerializedProperty element)
- {
- using (var idProperty = element.FindPropertyRelative("m_Id"))
- {
- Debug.Assert(idProperty != null, $"Cannot find m_Id property in {element.propertyPath}");
- return new Guid(idProperty.stringValue);
- }
- }
-
- public static int GetIndex(SerializedProperty arrayProperty, Guid id)
- {
- Debug.Assert(arrayProperty.isArray, $"Property {arrayProperty.propertyPath} is not an array");
- for (var i = 0; i < arrayProperty.arraySize; ++i)
- {
- using (var element = arrayProperty.GetArrayElementAtIndex(i))
- if (GetId(element) == id)
- return i;
- }
- return -1;
- }
-
- public static int GetIndex(SerializedProperty arrayProperty, SerializedProperty arrayElement)
- {
- return GetIndex(arrayProperty, GetId(arrayElement));
- }
-
- public static int GetIndex(SerializedProperty arrayElement)
- {
- var arrayProperty = arrayElement.GetArrayPropertyFromElement();
- return GetIndex(arrayProperty, arrayElement);
- }
-
- /// <summary>
- /// Starting with the given binding, find the composite that the binding belongs to. The given binding
- /// must either be the composite or be part of a composite.
- /// </summary>
- public static int GetCompositeStartIndex(SerializedProperty bindingArrayProperty, int bindingIndex)
- {
- for (var i = bindingIndex; i >= 0; --i)
- {
- var bindingProperty = bindingArrayProperty.GetArrayElementAtIndex(i);
- var bindingFlags = (InputBinding.Flags)bindingProperty.FindPropertyRelative("m_Flags").intValue;
- if ((bindingFlags & InputBinding.Flags.Composite) != 0)
- return i;
- Debug.Assert((bindingFlags & InputBinding.Flags.PartOfComposite) != 0,
- "Binding is neither a composite nor part of a composite");
- }
- return -1;
- }
-
- public static int GetCompositePartCount(SerializedProperty bindingArrayProperty, int bindingIndex)
- {
- var compositeStartIndex = GetCompositeStartIndex(bindingArrayProperty, bindingIndex);
- if (compositeStartIndex == -1)
- return 0;
-
- var numParts = 0;
- for (var i = compositeStartIndex + 1; i < bindingArrayProperty.arraySize; ++i, ++numParts)
- {
- var bindingProperty = bindingArrayProperty.GetArrayElementAtIndex(i);
- var bindingFlags = (InputBinding.Flags)bindingProperty.FindPropertyRelative("m_Flags").intValue;
- if ((bindingFlags & InputBinding.Flags.PartOfComposite) == 0)
- break;
- }
-
- return numParts;
- }
-
- public static int ConvertBindingIndexOnActionToBindingIndexInArray(SerializedProperty bindingArrayProperty, string actionName,
- int bindingIndexOnAction)
- {
- var bindingCount = bindingArrayProperty.arraySize;
- var indexOnAction = -1;
- var indexInArray = 0;
- for (; indexInArray < bindingCount; ++indexInArray)
- {
- var bindingActionName = bindingArrayProperty.GetArrayElementAtIndex(indexInArray).FindPropertyRelative("m_Action")
- .stringValue;
- if (actionName.Equals(bindingActionName, StringComparison.InvariantCultureIgnoreCase))
- {
- ++indexOnAction;
- if (indexOnAction == bindingIndexOnAction)
- return indexInArray;
- }
- }
- return indexInArray;
- }
-
- #if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
- public static void AddActionMaps(SerializedObject asset, SerializedObject sourceAsset)
- {
- Debug.Assert(asset.targetObject is InputActionAsset);
- Debug.Assert(sourceAsset.targetObject is InputActionAsset);
-
- var mapArrayPropertySrc = sourceAsset.FindProperty(nameof(InputActionAsset.m_ActionMaps));
- var mapArrayPropertyDst = asset.FindProperty(nameof(InputActionAsset.m_ActionMaps));
-
- // Copy each action map from source and paste at the end of destination
- var buffer = new StringBuilder();
- for (var i = 0; i < mapArrayPropertySrc.arraySize; ++i)
- {
- buffer.Clear();
- var mapProperty = mapArrayPropertySrc.GetArrayElementAtIndex(i);
- CopyPasteHelper.CopyItems(new List<SerializedProperty> {mapProperty}, buffer, typeof(InputActionMap), mapProperty);
- CopyPasteHelper.PasteItems(buffer.ToString(), new[] { mapArrayPropertyDst.arraySize - 1 }, mapArrayPropertyDst);
- }
- }
-
- public static void AddControlSchemes(SerializedObject asset, SerializedObject sourceAsset)
- {
- Debug.Assert((asset.targetObject is InputActionAsset));
- Debug.Assert((sourceAsset.targetObject is InputActionAsset));
-
- var src = sourceAsset.FindProperty(nameof(InputActionAsset.m_ControlSchemes));
- var dst = asset.FindProperty(nameof(InputActionAsset.m_ControlSchemes));
-
- var buffer = new StringBuilder();
- src.CopyToJson(buffer, ignoreObjectReferences: true);
- dst.RestoreFromJson(buffer.ToString());
- }
-
- #endif
-
- public static SerializedProperty AddActionMap(SerializedObject asset, int index = -1)
- {
- if (!(asset.targetObject is InputActionAsset))
- throw new InvalidOperationException(
- $"Can only add action maps to InputActionAsset objects (actual object is {asset.targetObject}");
-
- var mapArrayProperty = asset.FindProperty("m_ActionMaps");
- var name = FindUniqueName(mapArrayProperty, "New action map");
- if (index < 0)
- index = mapArrayProperty.arraySize;
-
- mapArrayProperty.InsertArrayElementAtIndex(index);
- var mapProperty = mapArrayProperty.GetArrayElementAtIndex(index);
-
- mapProperty.FindPropertyRelative("m_Name").stringValue = name;
- mapProperty.FindPropertyRelative("m_Id").stringValue = Guid.NewGuid().ToString();
- mapProperty.FindPropertyRelative("m_Actions").ClearArray();
- mapProperty.FindPropertyRelative("m_Bindings").ClearArray();
- // NB: This isn't always required: If there's already values in the mapArrayProperty, then inserting a new
- // element will duplicate the values from the adjacent element to the new element.
- // However, if the array has been emptied - i.e. if all action maps have been deleted -
- // then the m_Asset property is null, and needs setting here.
- if (mapProperty.FindPropertyRelative("m_Asset").objectReferenceValue == null)
- mapProperty.FindPropertyRelative("m_Asset").objectReferenceValue = asset.targetObject;
-
- return mapProperty;
- }
-
- public static void DeleteActionMap(SerializedObject asset, Guid id)
- {
- var mapArrayProperty = asset.FindProperty("m_ActionMaps");
- var mapIndex = GetIndex(mapArrayProperty, id);
- if (mapIndex == -1)
- throw new ArgumentException($"No map with id {id} in {asset}", nameof(id));
- mapArrayProperty.DeleteArrayElementAtIndex(mapIndex);
- }
-
- public static void DeleteAllActionMaps(SerializedObject asset)
- {
- Debug.Assert(asset.targetObject is InputActionAsset);
-
- var mapArrayProperty = asset.FindProperty("m_ActionMaps");
- while (mapArrayProperty.arraySize > 0)
- mapArrayProperty.DeleteArrayElementAtIndex(0);
- }
-
- public static void MoveActionMap(SerializedObject asset, int fromIndex, int toIndex)
- {
- var mapArrayProperty = asset.FindProperty("m_ActionMaps");
- mapArrayProperty.MoveArrayElement(fromIndex, toIndex);
- }
-
- public static void MoveAction(SerializedProperty actionMap, int fromIndex, int toIndex)
- {
- var actionArrayProperty = actionMap.FindPropertyRelative(nameof(InputActionMap.m_Actions));
- actionArrayProperty.MoveArrayElement(fromIndex, toIndex);
- }
-
- public static void MoveBinding(SerializedProperty actionMap, int fromIndex, int toIndex)
- {
- var arrayProperty = actionMap.FindPropertyRelative(nameof(InputActionMap.m_Bindings));
- arrayProperty.MoveArrayElement(fromIndex, toIndex);
- }
-
- // Append a new action to the end of the set.
- public static SerializedProperty AddAction(SerializedProperty actionMap, int index = -1)
- {
- var actionsArrayProperty = actionMap.FindPropertyRelative("m_Actions");
- if (index < 0)
- index = actionsArrayProperty.arraySize;
-
- var actionName = FindUniqueName(actionsArrayProperty, "New action");
-
- actionsArrayProperty.InsertArrayElementAtIndex(index);
- var actionProperty = actionsArrayProperty.GetArrayElementAtIndex(index);
-
- actionProperty.FindPropertyRelative("m_Name").stringValue = actionName;
- actionProperty.FindPropertyRelative("m_Type").intValue = (int)InputActionType.Button; // Default to creating button actions.
- actionProperty.FindPropertyRelative("m_Id").stringValue = Guid.NewGuid().ToString();
- actionProperty.FindPropertyRelative("m_ExpectedControlType").stringValue = "Button";
- actionProperty.FindPropertyRelative("m_Flags").intValue = 0;
- actionProperty.FindPropertyRelative("m_Interactions").stringValue = "";
- actionProperty.FindPropertyRelative("m_Processors").stringValue = "";
-
- return actionProperty;
- }
-
- public static void DeleteActionAndBindings(SerializedProperty actionMap, Guid actionId)
- {
- using (var actionsArrayProperty = actionMap.FindPropertyRelative("m_Actions"))
- using (var bindingsArrayProperty = actionMap.FindPropertyRelative("m_Bindings"))
- {
- // Find index of action.
- var actionIndex = GetIndex(actionsArrayProperty, actionId);
- if (actionIndex == -1)
- throw new ArgumentException($"No action with ID {actionId} in {actionMap.propertyPath}",
- nameof(actionId));
-
- using (var actionsProperty = actionsArrayProperty.GetArrayElementAtIndex(actionIndex))
- {
- var actionName = GetName(actionsProperty);
- var actionIdString = actionId.ToString();
-
- // Delete all bindings that refer to the action by ID or name.
- for (var i = 0; i < bindingsArrayProperty.arraySize; ++i)
- {
- using (var bindingProperty = bindingsArrayProperty.GetArrayElementAtIndex(i))
- using (var bindingActionProperty = bindingProperty.FindPropertyRelative("m_Action"))
- {
- var targetAction = bindingActionProperty.stringValue;
- if (targetAction.Equals(actionName, StringComparison.InvariantCultureIgnoreCase) ||
- targetAction == actionIdString)
- {
- bindingsArrayProperty.DeleteArrayElementAtIndex(i);
- --i;
- }
- }
- }
- }
-
- actionsArrayProperty.DeleteArrayElementAtIndex(actionIndex);
- }
- }
-
- // Equivalent to InputAction.AddBinding().
- public static SerializedProperty AddBinding(SerializedProperty actionProperty,
- SerializedProperty actionMapProperty = null, SerializedProperty afterBinding = null,
- string groups = "", string path = "", string name = "",
- string interactions = "", string processors = "",
- InputBinding.Flags flags = InputBinding.Flags.None)
- {
- var bindingsArrayProperty = actionMapProperty != null
- ? actionMapProperty.FindPropertyRelative("m_Bindings")
- : actionProperty.FindPropertyRelative("m_SingletonActionBindings");
- var bindingsCount = bindingsArrayProperty.arraySize;
- var actionName = actionProperty.FindPropertyRelative("m_Name").stringValue;
-
- int bindingIndex;
- if (afterBinding != null)
- {
- // If we're supposed to put the binding right after another binding, find the
- // binding's index. Also, if it's a composite, skip past all its parts.
- bindingIndex = GetIndex(bindingsArrayProperty, afterBinding);
- if (IsCompositeBinding(afterBinding))
- bindingIndex += GetCompositePartCount(bindingsArrayProperty, bindingIndex);
- ++bindingIndex; // Put it *after* the binding.
- }
- else
- {
- // Find the index of the last binding for the action in the array.
- var indexOfLastBindingForAction = -1;
- for (var i = 0; i < bindingsCount; ++i)
- {
- var bindingProperty = bindingsArrayProperty.GetArrayElementAtIndex(i);
- var bindingActionName = bindingProperty.FindPropertyRelative("m_Action").stringValue;
- if (actionName.Equals(bindingActionName, StringComparison.InvariantCultureIgnoreCase))
- indexOfLastBindingForAction = i;
- }
-
- // Insert after last binding or at end of array.
- bindingIndex = indexOfLastBindingForAction != -1 ? indexOfLastBindingForAction + 1 : bindingsCount;
- }
-
- ////TODO: bind using {id} rather than action name
- return AddBindingToBindingArray(bindingsArrayProperty,
- bindingIndex: bindingIndex,
- actionName: actionName,
- groups: groups,
- path: path,
- name: name,
- interactions: interactions,
- processors: processors,
- flags: flags);
- }
-
- public static SerializedProperty AddBindingToBindingArray(SerializedProperty bindingsArrayProperty, int bindingIndex = -1,
- string actionName = "", string groups = "", string path = "", string name = "", string interactions = "", string processors = "",
- InputBinding.Flags flags = InputBinding.Flags.None)
- {
- Debug.Assert(bindingsArrayProperty != null);
- Debug.Assert(bindingsArrayProperty.isArray, "SerializedProperty is not an array of bindings");
- Debug.Assert(bindingIndex == -1 || (bindingIndex >= 0 && bindingIndex <= bindingsArrayProperty.arraySize));
-
- if (bindingIndex == -1)
- bindingIndex = bindingsArrayProperty.arraySize;
-
- bindingsArrayProperty.InsertArrayElementAtIndex(bindingIndex);
-
- var newBindingProperty = bindingsArrayProperty.GetArrayElementAtIndex(bindingIndex);
- newBindingProperty.FindPropertyRelative("m_Path").stringValue = path;
- newBindingProperty.FindPropertyRelative("m_Groups").stringValue = groups;
- newBindingProperty.FindPropertyRelative("m_Interactions").stringValue = interactions;
- newBindingProperty.FindPropertyRelative("m_Processors").stringValue = processors;
- newBindingProperty.FindPropertyRelative("m_Flags").intValue = (int)flags;
- newBindingProperty.FindPropertyRelative("m_Action").stringValue = actionName;
- newBindingProperty.FindPropertyRelative("m_Name").stringValue = name;
- newBindingProperty.FindPropertyRelative("m_Id").stringValue = Guid.NewGuid().ToString();
-
- ////FIXME: this likely leaves m_Bindings in the map for singleton actions unsync'd in some cases
-
- return newBindingProperty;
- }
-
- public static void SetBindingPartName(SerializedProperty bindingProperty, string partName)
- {
- //expects beautified partName
- bindingProperty.FindPropertyRelative("m_Name").stringValue = partName;
- }
-
- public static void ChangeBinding(SerializedProperty bindingProperty, string path = null, string groups = null,
- string interactions = null, string processors = null, string action = null)
- {
- // Path.
- if (!string.IsNullOrEmpty(path))
- {
- var pathProperty = bindingProperty.FindPropertyRelative("m_Path");
- pathProperty.stringValue = path;
- }
-
- // Groups.
- if (!string.IsNullOrEmpty(groups))
- {
- var groupsProperty = bindingProperty.FindPropertyRelative("m_Groups");
- groupsProperty.stringValue = groups;
- }
-
- // Interactions.
- if (!string.IsNullOrEmpty(interactions))
- {
- var interactionsProperty = bindingProperty.FindPropertyRelative("m_Interactions");
- interactionsProperty.stringValue = interactions;
- }
-
- // Processors.
- if (!string.IsNullOrEmpty(processors))
- {
- var processorsProperty = bindingProperty.FindPropertyRelative("m_Processors");
- processorsProperty.stringValue = processors;
- }
-
- // Action.
- if (!string.IsNullOrEmpty(action))
- {
- var actionProperty = bindingProperty.FindPropertyRelative("m_Action");
- actionProperty.stringValue = action;
- }
- }
-
- public static void DeleteBinding(SerializedProperty binding, SerializedProperty actionMap)
- {
- var bindingsProperty = actionMap.FindPropertyRelative("m_Bindings");
- DeleteBinding(binding, bindingsProperty, binding.GetIndexOfArrayElement());
- }
-
- private static void DeleteBinding(SerializedProperty bindingProperty, SerializedProperty bindingArrayProperty, int bindingIndex)
- {
- var bindingFlags = (InputBinding.Flags)bindingProperty.FindPropertyRelative("m_Flags").intValue;
- var isComposite = (bindingFlags & InputBinding.Flags.Composite) != 0;
- // If it's a composite, delete all its parts first.
- if (isComposite)
- {
- for (var partIndex = bindingIndex + 1; partIndex < bindingArrayProperty.arraySize;)
- {
- var part = bindingArrayProperty.GetArrayElementAtIndex(partIndex);
- var flags = (InputBinding.Flags)part.FindPropertyRelative("m_Flags").intValue;
- if ((flags & InputBinding.Flags.PartOfComposite) == 0)
- break;
- bindingArrayProperty.DeleteArrayElementAtIndex(partIndex);
- }
- }
-
- bindingArrayProperty.DeleteArrayElementAtIndex(bindingIndex);
- }
-
- public static void DeleteBinding(SerializedProperty bindingArrayProperty, Guid id)
- {
- var bindingIndex = GetIndex(bindingArrayProperty, id);
- var bindingProperty = bindingArrayProperty.GetArrayElementAtIndex(bindingIndex);
- DeleteBinding(bindingProperty, bindingArrayProperty, bindingIndex);
- }
-
- public static void EnsureUniqueName(SerializedProperty arrayElement)
- {
- var arrayProperty = arrayElement.GetArrayPropertyFromElement();
- var arrayIndexOfElement = arrayElement.GetIndexOfArrayElement();
- var nameProperty = arrayElement.FindPropertyRelative("m_Name");
- var baseName = nameProperty.stringValue;
- nameProperty.stringValue = FindUniqueName(arrayProperty, baseName, ignoreIndex: arrayIndexOfElement);
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "False positive (possibly caused by lambda expression?).")]
- public static string FindUniqueName(SerializedProperty arrayProperty, string baseName, int ignoreIndex = -1)
- {
- return StringHelpers.MakeUniqueName(baseName,
- Enumerable.Range(0, arrayProperty.arraySize),
- index =>
- {
- if (index == ignoreIndex)
- return string.Empty;
- var elementProperty = arrayProperty.GetArrayElementAtIndex(index);
- var nameProperty = elementProperty.FindPropertyRelative("m_Name");
- if (nameProperty == null)
- throw new ArgumentException($"Cannot find m_Name property in elements of array",
- nameof(arrayProperty));
- return nameProperty.stringValue;
- });
- }
-
- public static void AssignUniqueIDs(SerializedProperty element)
- {
- AssignUniqueID(element);
- foreach (var child in element.GetChildren())
- {
- if (!child.isArray)
- continue;
-
- var fieldType = child.GetFieldType();
- if (fieldType == typeof(InputBinding[]) || fieldType == typeof(InputAction[]) ||
- fieldType == typeof(InputActionMap))
- {
- for (var i = 0; i < child.arraySize; ++i)
- using (var childElement = child.GetArrayElementAtIndex(i))
- AssignUniqueIDs(childElement);
- }
- }
- }
-
- private static void AssignUniqueID(SerializedProperty property)
- {
- var idProperty = property.FindPropertyRelative("m_Id");
- idProperty.stringValue = Guid.NewGuid().ToString();
- }
-
- public static void RenameAction(SerializedProperty actionProperty, SerializedProperty actionMapProperty, string newName)
- {
- // Make sure name is unique.
- var actionsArrayProperty = actionMapProperty.FindPropertyRelative("m_Actions");
- var uniqueName = FindUniqueName(actionsArrayProperty, newName, actionProperty.GetIndexOfArrayElement());
-
- // Update all bindings that refer to the action.
- var nameProperty = actionProperty.FindPropertyRelative("m_Name");
- var oldName = nameProperty.stringValue;
- var bindingsProperty = actionMapProperty.FindPropertyRelative("m_Bindings");
- for (var i = 0; i < bindingsProperty.arraySize; i++)
- {
- var element = bindingsProperty.GetArrayElementAtIndex(i);
- var actionNameProperty = element.FindPropertyRelative("m_Action");
- if (actionNameProperty.stringValue.Equals(oldName, StringComparison.InvariantCultureIgnoreCase))
- actionNameProperty.stringValue = uniqueName;
- }
-
- // Update name.
- nameProperty.stringValue = uniqueName;
- }
-
- public static void RenameActionMap(SerializedProperty actionMapProperty, string newName)
- {
- // Make sure name is unique in InputActionAsset.
- var assetObject = actionMapProperty.serializedObject;
- var mapsArrayProperty = assetObject.FindProperty("m_ActionMaps");
- var uniqueName = FindUniqueName(mapsArrayProperty, newName, actionMapProperty.GetIndexOfArrayElement());
-
- // Assign to map.
- var nameProperty = actionMapProperty.FindPropertyRelative("m_Name");
- nameProperty.stringValue = uniqueName;
- }
-
- public static void RenameComposite(SerializedProperty compositeGroupProperty, string newName)
- {
- var nameProperty = compositeGroupProperty.FindPropertyRelative("m_Name");
- nameProperty.stringValue = newName;
- }
-
- public static SerializedProperty AddCompositeBinding(SerializedProperty actionProperty, SerializedProperty actionMapProperty,
- string compositeName, Type compositeType = null, string groups = "", bool addPartBindings = true)
- {
- var newProperty = AddBinding(actionProperty, actionMapProperty);
- newProperty.FindPropertyRelative("m_Name").stringValue = ObjectNames.NicifyVariableName(compositeName);
- newProperty.FindPropertyRelative("m_Path").stringValue = compositeName;
- newProperty.FindPropertyRelative("m_Flags").intValue = (int)InputBinding.Flags.Composite;
-
- if (addPartBindings)
- {
- var fields = compositeType.GetFields(BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);
- foreach (var field in fields)
- {
- // Skip fields that aren't marked with [InputControl] attribute.
- if (field.GetCustomAttribute<InputControlAttribute>(false) == null)
- continue;
-
- var partProperty = AddBinding(actionProperty, actionMapProperty, groups: groups);
- partProperty.FindPropertyRelative("m_Name").stringValue = field.Name;
- partProperty.FindPropertyRelative("m_Flags").intValue = (int)InputBinding.Flags.PartOfComposite;
- }
- }
-
- return newProperty;
- }
-
- public static bool IsCompositeBinding(SerializedProperty bindingProperty)
- {
- using (var flagsProperty = bindingProperty.FindPropertyRelative("m_Flags"))
- {
- var flags = (InputBinding.Flags)flagsProperty.intValue;
- return (flags & InputBinding.Flags.Composite) != 0;
- }
- }
-
- public static SerializedProperty ChangeCompositeBindingType(SerializedProperty bindingProperty,
- NameAndParameters nameAndParameters)
- {
- var bindingsArrayProperty = bindingProperty.GetArrayPropertyFromElement();
- Debug.Assert(bindingsArrayProperty != null, "SerializedProperty is not an array of bindings");
- var bindingIndex = bindingProperty.GetIndexOfArrayElement();
-
- Debug.Assert(IsCompositeBinding(bindingProperty),
- $"Binding {bindingProperty.propertyPath} is not a composite");
-
- // If the composite still has the default name, change it to the default
- // one for the new composite type.
- var pathProperty = bindingProperty.FindPropertyRelative("m_Path");
- var nameProperty = bindingProperty.FindPropertyRelative("m_Name");
- if (nameProperty.stringValue ==
- ObjectNames.NicifyVariableName(NameAndParameters.Parse(pathProperty.stringValue).name))
- nameProperty.stringValue = ObjectNames.NicifyVariableName(nameAndParameters.name);
-
- pathProperty.stringValue = nameAndParameters.ToString();
-
- // Adjust part bindings if we have information on the registered composite. If we don't have
- // a type, we don't know about the parts. In that case, leave part bindings untouched.
- var compositeType = InputBindingComposite.s_Composites.LookupTypeRegistration(nameAndParameters.name);
- if (compositeType != null)
- {
- var actionName = bindingProperty.FindPropertyRelative("m_Action").stringValue;
-
- // Repurpose existing part bindings for the new composite or add any part bindings that
- // we're missing.
- var fields = compositeType.GetFields(BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);
- var partIndex = 0;
- var partBindingsStartIndex = bindingIndex + 1;
- foreach (var field in fields)
- {
- // Skip fields that aren't marked with [InputControl] attribute.
- if (field.GetCustomAttribute<InputControlAttribute>(false) == null)
- continue;
-
- // See if we can reuse an existing part binding.
- SerializedProperty partProperty = null;
- if (partBindingsStartIndex + partIndex < bindingsArrayProperty.arraySize)
- {
- ////REVIEW: this should probably look up part bindings by name rather than going sequentially
- var element = bindingsArrayProperty.GetArrayElementAtIndex(partBindingsStartIndex + partIndex);
- if (((InputBinding.Flags)element.FindPropertyRelative("m_Flags").intValue & InputBinding.Flags.PartOfComposite) != 0)
- partProperty = element;
- }
-
- // If not, insert a new binding.
- if (partProperty == null)
- {
- partProperty = AddBindingToBindingArray(bindingsArrayProperty, partBindingsStartIndex + partIndex,
- flags: InputBinding.Flags.PartOfComposite);
- }
-
- // Initialize.
- partProperty.FindPropertyRelative("m_Name").stringValue = ObjectNames.NicifyVariableName(field.Name);
- partProperty.FindPropertyRelative("m_Action").stringValue = actionName;
- ++partIndex;
- }
-
- ////REVIEW: when we allow adding the same part multiple times, we may want to do something smarter here
- // Delete extraneous part bindings.
- while (partBindingsStartIndex + partIndex < bindingsArrayProperty.arraySize)
- {
- var element = bindingsArrayProperty.GetArrayElementAtIndex(partBindingsStartIndex + partIndex);
- if (((InputBinding.Flags)element.FindPropertyRelative("m_Flags").intValue & InputBinding.Flags.PartOfComposite) == 0)
- break;
-
- bindingsArrayProperty.DeleteArrayElementAtIndex(partBindingsStartIndex + partIndex);
- // No incrementing of partIndex.
- }
- }
-
- return bindingProperty;
- }
-
- public static void ReplaceBindingGroup(SerializedObject asset, string oldBindingGroup, string newBindingGroup, bool deleteOrphanedBindings = false)
- {
- var mapArrayProperty = asset.FindProperty("m_ActionMaps");
- var mapCount = mapArrayProperty.arraySize;
-
- for (var k = 0; k < mapCount; ++k)
- {
- var actionMapProperty = mapArrayProperty.GetArrayElementAtIndex(k);
- var bindingsArrayProperty = actionMapProperty.FindPropertyRelative("m_Bindings");
- var bindingsCount = bindingsArrayProperty.arraySize;
-
- for (var i = 0; i < bindingsCount; ++i)
- {
- var bindingProperty = bindingsArrayProperty.GetArrayElementAtIndex(i);
- var groupsProperty = bindingProperty.FindPropertyRelative("m_Groups");
- var groups = groupsProperty.stringValue;
-
- // Ignore bindings not belonging to any control scheme.
- if (string.IsNullOrEmpty(groups))
- continue;
-
- var groupsArray = groups.Split(InputBinding.Separator);
- var numGroups = groupsArray.LengthSafe();
- var didRename = false;
- for (var n = 0; n < numGroups; ++n)
- {
- if (string.Compare(groupsArray[n], oldBindingGroup, StringComparison.InvariantCultureIgnoreCase) != 0)
- continue;
- if (string.IsNullOrEmpty(newBindingGroup))
- {
- ArrayHelpers.EraseAt(ref groupsArray, n);
- --n;
- --numGroups;
- }
- else
- groupsArray[n] = newBindingGroup;
- didRename = true;
- }
- if (!didRename)
- continue;
-
- if (groupsArray != null)
- groupsProperty.stringValue = string.Join(InputBinding.kSeparatorString, groupsArray);
- else
- {
- if (deleteOrphanedBindings)
- {
- // Binding no long belongs to any binding group. Delete it.
- bindingsArrayProperty.DeleteArrayElementAtIndex(i);
- --i;
- --bindingsCount;
- }
- else
- {
- groupsProperty.stringValue = string.Empty;
- }
- }
- }
- }
- }
-
- public static void RemoveUnusedBindingGroups(SerializedProperty binding, ReadOnlyArray<InputControlScheme> controlSchemes)
- {
- var groupsProperty = binding.FindPropertyRelative(nameof(InputBinding.m_Groups));
- groupsProperty.stringValue = string.Join(InputBinding.kSeparatorString,
- groupsProperty.stringValue
- .Split(InputBinding.Separator)
- .Where(g => controlSchemes.Any(c => c.bindingGroup.Equals(g, StringComparison.InvariantCultureIgnoreCase))));
- }
-
- #region Control Schemes
-
- public static void DeleteAllControlSchemes(SerializedObject asset)
- {
- var schemes = GetControlSchemesArray(asset);
- while (schemes.arraySize > 0)
- schemes.DeleteArrayElementAtIndex(0);
- }
-
- public static int IndexOfControlScheme(SerializedProperty controlSchemeArray, string controlSchemeName)
- {
- var serializedControlScheme = controlSchemeArray.FirstOrDefault(sp =>
- sp.FindPropertyRelative(nameof(InputControlScheme.m_Name)).stringValue == controlSchemeName);
- return serializedControlScheme?.GetIndexOfArrayElement() ?? -1;
- }
-
- public static SerializedProperty GetControlSchemesArray(SerializedObject asset)
- {
- return asset.FindProperty(nameof(InputActionAsset.m_ControlSchemes));
- }
-
- #endregion // Control Schemes
- }
- }
- #endif // UNITY_EDITOR
|