private void OnCompositeTypeChanged()
        {
            var nameAndParameters = new InputControlLayout.NameAndParameters
            {
                name       = m_CompositeTypes[m_SelectedCompositeType],
                parameters = m_CompositeParameters.GetParameters()
            };

            m_PathProperty.stringValue = nameAndParameters.ToString();
            onChange(k_CompositeTypeChanged);
        }
        public static SerializedProperty ChangeCompositeBindingType(SerializedProperty bindingProperty,
                                                                    InputControlLayout.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(InputControlLayout.ParseNameAndParameters(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);
        }