private void AddControlLayouts(TreeViewItem parent, ref int id)
            {
                // Split root into three different groups:
                // 1) Control layouts
                // 2) Device layouts that don't match specific products
                // 3) Device layouts that match specific products

                var controls = AddChild(parent, "Controls", ref id);
                var devices  = AddChild(parent, "Abstract Devices", ref id);
                var products = AddChild(parent, "Specific Devices", ref id);

                foreach (var layout in EditorInputControlLayoutCache.allControlLayouts)
                {
                    AddControlLayoutItem(layout, controls, ref id);
                }
                foreach (var layout in EditorInputControlLayoutCache.allDeviceLayouts)
                {
                    AddControlLayoutItem(layout, devices, ref id);
                }
                foreach (var layout in EditorInputControlLayoutCache.allProductLayouts)
                {
                    var rootBaseLayoutName = InputControlLayout.s_Layouts.GetRootLayoutName(layout.name).ToString();
                    var groupName          = string.IsNullOrEmpty(rootBaseLayoutName) ? "Other" : rootBaseLayoutName + "s";

                    var group = products.children?.FirstOrDefault(x => x.displayName == groupName);
                    if (group == null)
                    {
                        group = AddChild(products, groupName, ref id);
                        if (!string.IsNullOrEmpty(rootBaseLayoutName))
                        {
                            group.icon = EditorInputControlLayoutCache.GetIconForLayout(rootBaseLayoutName);
                        }
                    }

                    AddControlLayoutItem(layout, group, ref id);
                }

                controls.children?.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                devices.children?.Sort((a, b) => string.Compare(a.displayName, b.displayName));

                if (products.children != null)
                {
                    products.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                    foreach (var productGroup in products.children)
                    {
                        productGroup.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                    }
                }
            }
Beispiel #2
0
 public ControlTreeViewItem(InputControlLayout.ControlItem control, string prefix, string deviceId, string usage)  : base("")
 {
     m_Device = deviceId;
     m_Usage  = usage;
     if (!string.IsNullOrEmpty(prefix))
     {
         m_ControlPath = prefix + "/";
         name          = prefix + "/";
     }
     m_ControlPath   += control.name;
     name            += control.name;
     id               = controlPathWithDevice.GetHashCode();
     m_SearchableName = InputControlPath.ToHumanReadableString(controlPathWithDevice);
     icon             = EditorInputControlLayoutCache.GetIconForLayout(control.layout);
 }
            private void AddUser(TreeViewItem parent, InputUser user, ref int id)
            {
                ////REVIEW: can we get better identification? allow associating GameObject with user?
                var userItem = AddChild(parent, "User #" + user.index, ref id);

                // Control scheme.
                var controlScheme = user.controlScheme;

                if (controlScheme != null)
                {
                    AddChild(userItem, "Control Scheme: " + controlScheme, ref id);
                }

                // Paired devices.
                var pairedDevices = user.pairedDevices;

                if (pairedDevices.Count > 0)
                {
                    var devicesItem = AddChild(userItem, "Paired Devices", ref id);
                    foreach (var device in user.pairedDevices)
                    {
                        var item = new DeviceItem
                        {
                            id          = id++,
                            depth       = devicesItem.depth + 1,
                            displayName = device.ToString(),
                            device      = device,
                            icon        = EditorInputControlLayoutCache.GetIconForLayout(device.layout),
                        };
                        devicesItem.AddChild(item);
                    }
                }

                // Actions.
                var actions = user.actions;

                if (actions != null)
                {
                    var actionsItem = AddChild(userItem, "Actions", ref id);
                    foreach (var action in actions)
                    {
                        AddActionItem(actionsItem, action, ref id);
                    }

                    parent.children?.Sort((a, b) => string.Compare(a.displayName, b.displayName, StringComparison.CurrentCultureIgnoreCase));
                }
            }
Beispiel #4
0
        // This differs from RebindingOperation.GeneratePathForControl in that it cycles through all
        // layouts in the inheritance chain and generates a path for each one that contains the given control.
        private static IEnumerable <string> GeneratePossiblePathsForControl(InputControl control)
        {
            var builder          = new StringBuilder();
            var deviceLayoutName = control.device.m_Layout;

            do
            {
                // Skip layout if it is supposed to be hidden in the UI.
                var layout = EditorInputControlLayoutCache.TryGetLayout(deviceLayoutName);
                if (layout.hideInUI)
                {
                    continue;
                }

                builder.Length = 0;
                yield return(control.BuildPath(deviceLayoutName, builder));
            }while (InputControlLayout.s_Layouts.baseLayoutTable.TryGetValue(deviceLayoutName, out deviceLayoutName));
        }
Beispiel #5
0
            private void BuildControlsRecursive(Item parent, InputControlLayout layout, string prefix, ref int id)
            {
                foreach (var control in layout.controls)
                {
                    if (control.isModifyingChildControlByPath)
                    {
                        continue;
                    }

                    // Skip variants.
                    if (!string.IsNullOrEmpty(control.variants) && control.variants.ToLower() != "default")
                    {
                        continue;
                    }

                    var controlPath = prefix + control.name;
                    var child       = new Item
                    {
                        id          = id++,
                        depth       = parent.depth + 1,
                        displayName = controlPath,
                        device      = parent.layout.name,
                        controlPath = controlPath,
                        layout      = layout
                    };

                    var childLayout = EditorInputControlLayoutCache.TryGetLayout(control.layout);
                    if (childLayout != null)
                    {
                        BuildControlsRecursive(parent, childLayout, controlPath + "/", ref id);
                    }

                    parent.AddChild(child);
                }

                if (parent.children != null)
                {
                    parent.children.Sort((a, b) =>
                                         string.Compare(a.displayName, b.displayName, StringComparison.Ordinal));
                }
            }
            private void AddDevices(TreeViewItem parent, IEnumerable <InputDevice> devices, ref int id, int participantId = InputDevice.kLocalParticipantId)
            {
                foreach (var device in devices)
                {
                    if (device.m_ParticipantId != participantId)
                    {
                        continue;
                    }

                    var item = new DeviceItem
                    {
                        id          = id++,
                        depth       = parent.depth + 1,
                        displayName = device.name,
                        device      = device,
                        icon        = EditorInputControlLayoutCache.GetIconForLayout(device.layout),
                    };
                    parent.AddChild(item);
                }

                parent.children?.Sort((a, b) => string.Compare(a.displayName, b.displayName));
            }
        /// <summary>
        /// Grab <see cref="InputSystem.settings"/> and set it up for editing.
        /// </summary>
        private void InitializeWithCurrentSettings()
        {
            // Find the set of available assets in the project.
            m_AvailableInputSettingsAssets = FindInputSettingsInProject();

            // See which is the active one.
            m_Settings = InputSystem.settings;
            var currentSettingsPath = AssetDatabase.GetAssetPath(m_Settings);

            if (string.IsNullOrEmpty(currentSettingsPath))
            {
                // The current settings aren't coming from an asset. These won't be editable
                // in the UI but we still have to show something.

                m_CurrentSelectedInputSettingsAsset = ArrayHelpers.Append(ref m_AvailableInputSettingsAssets, "<No Asset>");
                EditorBuildSettings.RemoveConfigObject(kEditorBuildSettingsConfigKey);
            }
            else
            {
                m_CurrentSelectedInputSettingsAsset = ArrayHelpers.IndexOf(m_AvailableInputSettingsAssets, currentSettingsPath);
                if (m_CurrentSelectedInputSettingsAsset == -1)
                {
                    // This is odd and shouldn't happen. Solve by just adding the path to the list.
                    m_CurrentSelectedInputSettingsAsset =
                        ArrayHelpers.Append(ref m_AvailableInputSettingsAssets, currentSettingsPath);
                }

                ////REVIEW: should we store this by platform?
                EditorBuildSettings.AddConfigObject(kEditorBuildSettingsConfigKey, m_Settings, true);
            }

            // Refresh the list of assets we display in the UI.
            m_AvailableSettingsAssetsOptions = new GUIContent[m_AvailableInputSettingsAssets.Length];
            for (var i = 0; i < m_AvailableInputSettingsAssets.Length; ++i)
            {
                var name = m_AvailableInputSettingsAssets[i];
                if (name.StartsWith("Assets/"))
                {
                    name = name.Substring("Assets/".Length);
                }
                if (name.EndsWith(".asset"))
                {
                    name = name.Substring(0, name.Length - ".asset".Length);
                }
                if (name.EndsWith(".inputsettings"))
                {
                    name = name.Substring(0, name.Length - ".inputsettings".Length);
                }
                m_AvailableSettingsAssetsOptions[i] = new GUIContent(name);
            }

            // Look up properties.
            m_SettingsObject   = new SerializedObject(m_Settings);
            m_UpdateMode       = m_SettingsObject.FindProperty("m_UpdateMode");
            m_ActionUpdateMode = m_SettingsObject.FindProperty("m_ActionUpdateMode");
            m_TimesliceEvents  = m_SettingsObject.FindProperty("m_TimesliceEvents");
            m_RunInBackground  = m_SettingsObject.FindProperty("m_RunInBackground");
            m_CompensateForScreenOrientation = m_SettingsObject.FindProperty("m_CompensateForScreenOrientation");
            m_FilterNoiseOnCurrent           = m_SettingsObject.FindProperty("m_FilterNoiseOnCurrent");
            m_DefaultDeadzoneMin             = m_SettingsObject.FindProperty("m_DefaultDeadzoneMin");
            m_DefaultDeadzoneMax             = m_SettingsObject.FindProperty("m_DefaultDeadzoneMax");
            m_DefaultButtonPressPoint        = m_SettingsObject.FindProperty("m_DefaultButtonPressPoint");
            m_DefaultTapTime     = m_SettingsObject.FindProperty("m_DefaultTapTime");
            m_DefaultSlowTapTime = m_SettingsObject.FindProperty("m_DefaultSlowTapTime");
            m_DefaultHoldTime    = m_SettingsObject.FindProperty("m_DefaultHoldTime");

            // Initialize ReorderableList for list of supported devices.
            var supportedDevicesProperty = m_SettingsObject.FindProperty("m_SupportedDevices");

            m_SupportedDevices = new ReorderableList(m_SettingsObject, supportedDevicesProperty)
            {
                drawHeaderCallback =
                    rect => { EditorGUI.LabelField(rect, m_SupportedDevicesText); },
                onChangedCallback =
                    list => { Apply(); },
                onAddDropdownCallback =
                    (rect, list) =>
                {
                    var state    = new AdvancedDropdownState();
                    var dropdown = new InputControlPickerDropdown(state,
                                                                  path =>
                    {
                        var layoutName = InputControlPath.TryGetDeviceLayout(path) ?? path;
                        var numDevices = supportedDevicesProperty.arraySize;
                        supportedDevicesProperty.InsertArrayElementAtIndex(numDevices);
                        supportedDevicesProperty.GetArrayElementAtIndex(numDevices)
                        .stringValue = layoutName;
                        Apply();
                    }, InputControlPickerDropdown.Mode.PickDevice);
                    dropdown.Show(rect);
                },
                drawElementCallback =
                    (rect, index, isActive, isFocused) =>
                {
                    var layoutName = m_Settings.supportedDevices[index];
                    var icon       = EditorInputControlLayoutCache.GetIconForLayout(layoutName);
                    if (icon != null)
                    {
                        var iconRect = rect;
                        iconRect.width = 20;
                        rect.x        += 20;
                        rect.width    -= 20;

                        GUI.Label(iconRect, icon);
                    }

                    EditorGUI.LabelField(rect, m_Settings.supportedDevices[index]);
                }
            };
        }
Beispiel #8
0
            private void AddControlItem(InputControlLayout.ControlItem control, TreeViewItem parent, ref int id)
            {
                var item = AddChild(parent, control.variants.IsEmpty() ? control.name : string.Format("{0} ({1})",
                                                                                                      control.name, control.variants), ref id);

                if (!control.layout.IsEmpty())
                {
                    item.icon = EditorInputControlLayoutCache.GetIconForLayout(control.layout);
                }

                ////TODO: fully merge TreeViewItems from isModifyingChildControlByPath control layouts into the control they modify

                ////TODO: allow clicking this field to jump to the layout
                if (!control.layout.IsEmpty())
                {
                    AddChild(item, string.Format("Layout: {0}", control.layout), ref id);
                }
                if (!control.variants.IsEmpty())
                {
                    AddChild(item, string.Format("Variant: {0}", control.variants), ref id);
                }
                if (!string.IsNullOrEmpty(control.displayName))
                {
                    AddChild(item, string.Format("Display Name: {0}", control.displayName), ref id);
                }
                if (!string.IsNullOrEmpty(control.shortDisplayName))
                {
                    AddChild(item, string.Format("Short Display Name: {0}", control.shortDisplayName), ref id);
                }
                if (control.format != 0)
                {
                    AddChild(item, string.Format("Format: {0}", control.format), ref id);
                }
                if (control.offset != InputStateBlock.kInvalidOffset)
                {
                    AddChild(item, string.Format("Offset: {0}", control.offset), ref id);
                }
                if (control.bit != InputStateBlock.kInvalidOffset)
                {
                    AddChild(item, string.Format("Bit: {0}", control.bit), ref id);
                }
                if (control.sizeInBits != 0)
                {
                    AddChild(item, string.Format("Size In Bits: {0}", control.sizeInBits), ref id);
                }
                if (control.isArray)
                {
                    AddChild(item, string.Format("Array Size: {0}", control.arraySize), ref id);
                }
                if (!string.IsNullOrEmpty(control.useStateFrom))
                {
                    AddChild(item, string.Format("Use State From: {0}", control.useStateFrom), ref id);
                }
                if (!control.defaultState.isEmpty)
                {
                    AddChild(item, string.Format("Default State: {0}", control.defaultState.ToString()), ref id);
                }
                if (!control.minValue.isEmpty)
                {
                    AddChild(item, string.Format("Min Value: {0}", control.minValue.ToString()), ref id);
                }
                if (!control.maxValue.isEmpty)
                {
                    AddChild(item, string.Format("Max Value: {0}", control.maxValue.ToString()), ref id);
                }

                if (control.usages.Count > 0)
                {
                    AddChild(item, "Usages: " + string.Join(", ", control.usages.Select(x => x.ToString()).ToArray()), ref id);
                }
                if (control.aliases.Count > 0)
                {
                    AddChild(item, "Aliases: " + string.Join(", ", control.aliases.Select(x => x.ToString()).ToArray()), ref id);
                }

                if (control.isNoisy || control.isSynthetic)
                {
                    var flags = "Flags: ";
                    if (control.isNoisy)
                    {
                        flags += "Noisy";
                    }
                    if (control.isSynthetic)
                    {
                        if (control.isNoisy)
                        {
                            flags += ", Synthetic";
                        }
                        else
                        {
                            flags += "Synthetic";
                        }
                    }
                    AddChild(item, flags, ref id);
                }

                if (control.parameters.Count > 0)
                {
                    var parameters = AddChild(item, "Parameters", ref id);
                    foreach (var parameter in control.parameters)
                    {
                        AddChild(parameters, parameter.ToString(), ref id);
                    }
                }

                if (control.processors.Count > 0)
                {
                    var processors = AddChild(item, "Processors", ref id);
                    foreach (var processor in control.processors)
                    {
                        var processorItem = AddChild(processors, processor.name, ref id);
                        foreach (var parameter in processor.parameters)
                        {
                            AddChild(processorItem, parameter.ToString(), ref id);
                        }
                    }
                }
            }
Beispiel #9
0
            protected override TreeViewItem BuildRoot()
            {
                var id = 0;

                var root = new TreeViewItem
                {
                    id    = id++,
                    depth = -1
                };

                // Actions.
                m_EnabledActions.Clear();
                InputSystem.ListEnabledActions(m_EnabledActions);
                if (m_EnabledActions.Count > 0)
                {
                    actionsItem = AddChild(root, string.Format("Actions ({0})", m_EnabledActions.Count), ref id);
                    AddEnabledActions(actionsItem, ref id);
                }

                // Users.
                ////TODO

                // Devices.
                var devices = InputSystem.devices;

                devicesItem = AddChild(root, string.Format("Devices ({0})", devices.Count), ref id);
                var          haveRemotes      = devices.Any(x => x.remote);
                TreeViewItem localDevicesNode = null;

                if (haveRemotes)
                {
                    // Split local and remote devices into groups.

                    localDevicesNode = AddChild(devicesItem, "Local", ref id);
                    AddDevices(localDevicesNode, devices, ref id);

                    var remoteDevicesNode = AddChild(devicesItem, "Remote", ref id);
                    foreach (var player in EditorConnection.instance.ConnectedPlayers)
                    {
                        var playerNode = AddChild(remoteDevicesNode, player.name, ref id);
                        AddDevices(playerNode, devices, ref id, "Remote" + player.playerId + InputControlLayout.kNamespaceQualifier);
                    }
                }
                else
                {
                    // We don't have remote devices so don't add an extra group for local devices.
                    // Put them all directly underneath the "Devices" node.
                    AddDevices(devicesItem, devices, ref id);
                }

                ////TDO: unsupported and disconnected devices should also be shown for remotes

                if (m_UnsupportedDevices == null)
                {
                    m_UnsupportedDevices = new List <InputDeviceDescription>();
                }
                m_UnsupportedDevices.Clear();
                InputSystem.GetUnsupportedDevices(m_UnsupportedDevices);
                if (m_UnsupportedDevices.Count > 0)
                {
                    var parent = haveRemotes ? localDevicesNode : devicesItem;
                    var unsupportedDevicesNode = AddChild(parent, string.Format("Unsupported ({0})", m_UnsupportedDevices.Count), ref id);
                    foreach (var device in m_UnsupportedDevices)
                    {
                        AddChild(unsupportedDevicesNode, device.ToString(), ref id);
                    }
                    unsupportedDevicesNode.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                }

                var disconnectedDevices = InputSystem.disconnectedDevices;

                if (disconnectedDevices.Count > 0)
                {
                    var parent = haveRemotes ? localDevicesNode : devicesItem;
                    var disconnectedDevicesNode = AddChild(parent, string.Format("Disconnected ({0})", disconnectedDevices.Count), ref id);
                    foreach (var device in disconnectedDevices)
                    {
                        AddChild(disconnectedDevicesNode, device.ToString(), ref id);
                    }
                    disconnectedDevicesNode.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                }

                // Layouts.
                layoutsItem = AddChild(root, "Layouts", ref id);
                AddControlLayouts(layoutsItem, ref id);

                ////FIXME: this shows local configuration only
                // Settings.
                var settings          = InputSystem.settings;
                var settingsAssetPath = AssetDatabase.GetAssetPath(settings);
                var settingsLabel     = "Settings";

                if (settingsAssetPath != null)
                {
                    settingsLabel = string.Format("Settings ({0})", Path.GetFileName(settingsAssetPath));
                }
                settingsItem = AddChild(root, settingsLabel, ref id);
                AddValueItem(settingsItem, "Update Mode", settings.updateMode, ref id);
                AddValueItem(settingsItem, "Timeslice Events", settings.timesliceEvents, ref id);
                AddValueItem(settingsItem, "Run In Background", settings.runInBackground, ref id);
                AddValueItem(settingsItem, "Compensate For Screen Orientation", settings.compensateForScreenOrientation, ref id);
                AddValueItem(settingsItem, "Filter Noise On .current", settings.filterNoiseOnCurrent, ref id);
                AddValueItem(settingsItem, "Default Button Press Point", settings.defaultButtonPressPoint, ref id);
                AddValueItem(settingsItem, "Default Deadzone Min", settings.defaultDeadzoneMin, ref id);
                AddValueItem(settingsItem, "Default Deadzone Max", settings.defaultDeadzoneMax, ref id);
                AddValueItem(settingsItem, "Default Tap Time", settings.defaultTapTime, ref id);
                AddValueItem(settingsItem, "Default Slow Tap Time", settings.defaultSlowTapTime, ref id);
                AddValueItem(settingsItem, "Default Hold Time", settings.defaultHoldTime, ref id);
                AddValueItem(settingsItem, "Default Sensitivity", settings.defaultSensitivity, ref id);
                AddValueItem(settingsItem, "Lock Input To Game View", InputEditorUserSettings.lockInputToGameView, ref id);
                if (settings.supportedDevices.Count > 0)
                {
                    var supportedDevices = AddChild(settingsItem, "Supported Devices", ref id);
                    foreach (var item in settings.supportedDevices)
                    {
                        var icon = EditorInputControlLayoutCache.GetIconForLayout(item);
                        AddChild(supportedDevices, item, ref id, icon);
                    }
                }
                settingsItem.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));

                // Metrics.
                var metrics = InputSystem.GetMetrics();

                metricsItem = AddChild(root, "Metrics", ref id);
                AddChild(metricsItem,
                         "Current State Size in Bytes: " + StringHelpers.NicifyMemorySize(metrics.currentStateSizeInBytes),
                         ref id);
                AddValueItem(metricsItem, "Current Control Count", metrics.currentControlCount, ref id);
                AddValueItem(metricsItem, "Current Layout Count", metrics.currentLayoutCount, ref id);

                return(root);
            }
        private void DrawInteractivePickButton(Rect rect)
        {
            if (s_PickButtonIcon == null)
            {
                s_PickButtonIcon = EditorInputControlLayoutCache.GetIconForLayout("Button");
            }

            var toggleRebind = GUI.Toggle(rect,
                                          m_RebindingOperation != null && m_RebindingOperation.started, s_PickButtonIcon, EditorStyles.miniButton);

            if (toggleRebind && (m_RebindingOperation == null || !m_RebindingOperation.started))
            {
                // Start rebind.

                if (m_RebindingOperation == null)
                {
                    m_RebindingOperation = new InputActionRebindingExtensions.RebindingOperation();
                }

                ////TODO: if we have multiple candidates that we can't trivially decide between, let user choose

                m_RebindingOperation
                .WithExpectedControlLayout(m_ExpectedControlLayout)
                // Require minimum actuation of 0.15f. This is after deadzoning has been applied.
                .WithMagnitudeHavingToBeGreaterThan(0.15f)
                // After 4 seconds, cancel the operation.
                .WithTimeout(4)
                ////REVIEW: the delay makes it more robust but doesn't feel good
                // Give us a buffer of 0.25 seconds to see if a better match comes along.
                .OnMatchWaitForAnother(0.25f)
                ////REVIEW: should we exclude only the system's active pointing device?
                // With the mouse operating the UI, its cursor control is too fickle a thing to
                // bind to. Ignore mouse position and delta.
                // NOTE: We go for all types of pointers here, not just mice.
                .WithControlsExcluding("<Pointer>/position")
                .WithControlsExcluding("<Pointer>/delta")
                .OnCancel(
                    operation =>
                {
                    ////REVIEW: Is there a better way to do this? All we want is for the *current* UI to repaint but Unity's
                    ////        editor API seems to have no way to retrieve the current EditorWindow from inside an OnGUI callback.
                    ////        So we'd have to pass the EditorWindow in here all the way from the EditorWindow.OnGUI() callback
                    ////        itself.
                    InternalEditorUtility.RepaintAllViews();

                    if (m_NeedToClearProgressBar)
                    {
                        EditorUtility.ClearProgressBar();
                    }
                })
                .OnComplete(
                    operation =>
                {
                    if (m_NeedToClearProgressBar)
                    {
                        EditorUtility.ClearProgressBar();
                    }
                })
                .OnApplyBinding(
                    (operation, newPath) =>
                {
                    pathProperty.stringValue = newPath;
                    pathProperty.serializedObject.ApplyModifiedProperties();
                    onModified();
                });

                // If we have control paths to match, pass them on.
                m_RebindingOperation.WithoutControlsHavingToMatchPath();
                if (m_ControlPathsToMatch.LengthSafe() > 0)
                {
                    m_ControlPathsToMatch.Select(x => m_RebindingOperation.WithControlsHavingToMatchPath(x));
                }

                m_RebindingOperation.Start();
            }
            else if (!toggleRebind && m_RebindingOperation != null && m_RebindingOperation.started)
            {
                m_RebindingOperation.Cancel();
            }
        }