#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_UI_TK_ASSET_EDITOR using System; using System.Collections.Generic; using System.Linq; using UnityEngine.InputSystem.Utilities; namespace UnityEngine.InputSystem.Editor { internal static class ControlSchemeCommands { private const string kAllControlSchemesName = "All Control Schemes"; private const string kNewControlSchemeName = "New Control Scheme"; public static Command AddNewControlScheme() { return (in InputActionsEditorState state) => state.With(selectedControlScheme: new InputControlScheme( MakeUniqueControlSchemeName(state, kNewControlSchemeName))); } public static Command AddDeviceRequirement(InputControlScheme.DeviceRequirement requirement) { return (in InputActionsEditorState state) => state.With(selectedControlScheme: new InputControlScheme(state.selectedControlScheme.name, state.selectedControlScheme.deviceRequirements.Append(requirement))); } public static Command RemoveDeviceRequirement(int selectedDeviceIndex) { return (in InputActionsEditorState state) => { return state.With(selectedControlScheme: new InputControlScheme(state.selectedControlScheme.name, state.selectedControlScheme.deviceRequirements.Where((r, i) => i != selectedDeviceIndex))); }; } public static Command SaveControlScheme(string newName = "", bool updateExisting = false) { return (in InputActionsEditorState state) => { var controlSchemeName = state.selectedControlScheme.name; var controlSchemesArray = state.serializedObject.FindProperty(nameof(InputActionAsset.m_ControlSchemes)); var controlScheme = controlSchemesArray .FirstOrDefault(sp => sp.FindPropertyRelative(nameof(InputControlScheme.m_Name)).stringValue == controlSchemeName); // if the control scheme is null, we're saving a new control scheme, otherwise editing an existing one if (controlScheme == null && updateExisting) throw new InvalidOperationException("Tried to update a non-existent control scheme."); if (updateExisting == false) { controlSchemeName = MakeUniqueControlSchemeName(state, controlSchemeName); controlSchemesArray.InsertArrayElementAtIndex(controlSchemesArray.arraySize); controlScheme = controlSchemesArray.GetArrayElementAtIndex(controlSchemesArray.arraySize - 1); } controlScheme.FindPropertyRelative(nameof(InputControlScheme.m_Name)).stringValue = string.IsNullOrEmpty(newName) ? controlSchemeName : newName; var serializedDeviceRequirements = controlScheme.FindPropertyRelative(nameof(InputControlScheme.m_DeviceRequirements)); serializedDeviceRequirements.ClearArray(); for (var i = 0; i < state.selectedControlScheme.deviceRequirements.Count; i++) { var deviceRequirement = state.selectedControlScheme.deviceRequirements[i]; serializedDeviceRequirements.InsertArrayElementAtIndex(i); var serializedRequirement = serializedDeviceRequirements.GetArrayElementAtIndex(i); serializedRequirement .FindPropertyRelative(nameof(InputControlScheme.DeviceRequirement.m_ControlPath)) .stringValue = deviceRequirement.controlPath; serializedRequirement.FindPropertyRelative(nameof(InputControlScheme.DeviceRequirement.m_Flags)) .enumValueFlag = (int)deviceRequirement.m_Flags; } state.serializedObject.ApplyModifiedProperties(); return state.With(selectedControlScheme: new InputControlScheme(controlScheme)); }; } public static Command SelectControlScheme(int controlSchemeIndex) { return (in InputActionsEditorState state) => { if (controlSchemeIndex == -1) return state.With(selectedControlSchemeIndex: controlSchemeIndex); var controlSchemeSerializedProperty = state.serializedObject .FindProperty(nameof(InputActionAsset.m_ControlSchemes)) .GetArrayElementAtIndex(controlSchemeIndex); return state.With( selectedControlSchemeIndex: controlSchemeIndex, selectedControlScheme: new InputControlScheme(controlSchemeSerializedProperty)); }; } /// /// Duplicate creates a new instance of the selected control scheme and places it in the selected /// control scheme property of the state but doesn't persist anything. /// public static Command DuplicateSelectedControlScheme() { return (in InputActionsEditorState state) => state.With(selectedControlScheme: new InputControlScheme( MakeUniqueControlSchemeName(state, state.selectedControlScheme.name), state.selectedControlScheme.deviceRequirements)); } public static Command DeleteSelectedControlScheme() { return (in InputActionsEditorState state) => { var selectedControlSchemeName = state.selectedControlScheme.name; var serializedArray = state.serializedObject.FindProperty(nameof(InputActionAsset.m_ControlSchemes)); var serializedControlScheme = serializedArray .FirstOrDefault(sp => sp.FindPropertyRelative(nameof(InputControlScheme.m_Name)).stringValue == selectedControlSchemeName); if (serializedControlScheme == null) throw new InvalidOperationException("Control scheme doesn't exist in collection."); var indexOfArrayElement = serializedControlScheme.GetIndexOfArrayElement(); serializedArray.DeleteArrayElementAtIndex(indexOfArrayElement); state.serializedObject.ApplyModifiedProperties(); if (serializedArray.arraySize == 0) return state.With( selectedControlSchemeIndex: -1, selectedControlScheme: new InputControlScheme()); if (indexOfArrayElement > serializedArray.arraySize - 1) return state.With( selectedControlSchemeIndex: serializedArray.arraySize - 1, selectedControlScheme: new InputControlScheme(serializedArray.GetArrayElementAtIndex(serializedArray.arraySize - 1))); return state.With( selectedControlSchemeIndex: indexOfArrayElement, selectedControlScheme: new InputControlScheme(serializedArray.GetArrayElementAtIndex(indexOfArrayElement))); }; } internal static string MakeUniqueControlSchemeName(InputActionsEditorState state, string name) { var controlSchemes = state.serializedObject.FindProperty(nameof(InputActionAsset.m_ControlSchemes)); IEnumerable controlSchemeNames = Array.Empty(); if (controlSchemes != null) controlSchemeNames = controlSchemes.Select(sp => sp.FindPropertyRelative(nameof(InputControlScheme.m_Name)).stringValue); return StringHelpers.MakeUniqueName(name, controlSchemeNames.Append(kAllControlSchemesName), x => x); } public static Command ChangeDeviceRequirement(int deviceRequirementIndex, bool isRequired) { return (in InputActionsEditorState state) => { var deviceRequirements = state.selectedControlScheme.deviceRequirements.ToList(); var requirement = deviceRequirements[deviceRequirementIndex]; requirement.isOptional = !isRequired; deviceRequirements[deviceRequirementIndex] = requirement; return state.With(selectedControlScheme: new InputControlScheme( state.selectedControlScheme.name, deviceRequirements, state.selectedControlScheme.bindingGroup)); }; } public static Command ReorderDeviceRequirements(int oldPosition, int newPosition) { return (in InputActionsEditorState state) => { var deviceRequirements = state.selectedControlScheme.deviceRequirements.ToList(); var requirement = deviceRequirements[oldPosition]; deviceRequirements.RemoveAt(oldPosition); deviceRequirements.Insert(newPosition, requirement); return state.With(selectedControlScheme: new InputControlScheme( state.selectedControlScheme.name, deviceRequirements, state.selectedControlScheme.bindingGroup)); }; } public static Command ChangeSelectedBindingsControlSchemes(string controlScheme, bool add) { return (in InputActionsEditorState state) => { var actionMapSO = state.serializedObject ?.FindProperty(nameof(InputActionAsset.m_ActionMaps)) ?.GetArrayElementAtIndex(state.selectedActionMapIndex); var serializedProperty = actionMapSO?.FindPropertyRelative(nameof(InputActionMap.m_Bindings)) ?.GetArrayElementAtIndex(state.selectedBindingIndex); var groupsProperty = serializedProperty.FindPropertyRelative(nameof(InputBinding.m_Groups)); var groups = groupsProperty.stringValue; if (add) groupsProperty.stringValue = groups .Split(InputBinding.kSeparatorString) .Append(controlScheme) .Distinct() .Join(InputBinding.kSeparatorString); else groupsProperty.stringValue = groups .Split(InputBinding.kSeparatorString) .Where(s => s != controlScheme) .Join(InputBinding.kSeparatorString); state.serializedObject.ApplyModifiedProperties(); return state; }; } } } #endif