From d0d8ad88cdc55c6a89b2d50044c579c46ea8cf05 Mon Sep 17 00:00:00 2001 From: "roger.liu" Date: Thu, 13 Apr 2023 18:11:32 -0700 Subject: [PATCH 1/5] Checking-Pointing progress for specifying input usages in editor, as well as listing out the specific device paths that match to a binding --- .../InputSystem/Controls/InputControlPath.cs | 36 ++++++++++ .../AssetEditor/InputBindingPropertiesView.cs | 67 +++++++++++++++++++ .../ControlPicker/InputControlDropdownItem.cs | 7 +- .../InputControlPickerDropdown.cs | 25 +++++-- 4 files changed, 128 insertions(+), 7 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs b/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs index 5cbfa4a41c..45af3110b9 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs @@ -720,6 +720,42 @@ public static bool Matches(string expected, InputControl control) return MatchesRecursive(ref parser, control); } + internal static bool Matches(IEnumerable usages, string name, ref InputControlLayout.ControlItem controlItem) + { + if (usages.Count() > 0) + { + // All of usages should match to the one of usage in the control + foreach (var usage in usages) + { + if (usage.Length > 0) + { + var usageCount = controlItem.usages.Count; + var anyUsageMatches = false; + for (var i = 0; i < usageCount; ++i) + { + if (StringMatches(usage, controlItem.usages[i])) + { + anyUsageMatches = true; + break; + } + } + + if (!anyUsageMatches) + return false; + } + } + } + + // Match name. + if (name.Length > 0) + { + if (!StringMatches(name, controlItem.name)) + return false; + } + + return true; + } + /// /// Check whether the given path matches or any of its parents. /// diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs index d8de344c92..4f52e9594a 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using UnityEditor; using UnityEngine.InputSystem.Editor.Lists; using UnityEngine.InputSystem.Layouts; @@ -61,6 +62,7 @@ public void Dispose() m_ControlPathEditor?.Dispose(); } + bool showPaths = false; protected override void DrawGeneralProperties() { var currentPath = m_PathProperty.stringValue; @@ -102,11 +104,76 @@ protected override void DrawGeneralProperties() } } + showPaths = EditorGUILayout.Toggle("Show full paths", showPaths); + // Show the specific layouts that implement the control on this path + if (showPaths) + { + // Control scheme matrix. + DrawFullPathInfo(); + } // Control scheme matrix. DrawUseInControlSchemes(); } } + /// + /// Draw control scheme matrix that allows selecting which control schemes a particular + /// binding appears in. + /// + private void DrawFullPathInfo() + { + + var path = m_ControlPathEditor.pathProperty.stringValue; + var layout = InputControlPath.TryGetDeviceLayout(path); + var parsedPath = InputControlPath.Parse(path).ToArray(); + + // Try to find all relevant full paths + if(parsedPath.Length == 2) + { + var usages = parsedPath[1].usages; + var name = parsedPath[1].name; + + EditorGUILayout.BeginVertical(); + DrawPathInfoForLayout(new InternedString(layout), usages, name); + EditorGUILayout.EndVertical(); + } + // Otherwise skip + } + + private void DrawPathInfoForLayout(InternedString rootLayout, IEnumerable usages, string name) + { + var path = m_ControlPathEditor.pathProperty.stringValue; + var childLayouts = EditorInputControlLayoutCache.allLayouts + .Where(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.baseLayouts.Contains(rootLayout)).OrderBy(x => x.displayName); + + if (rootLayout == InputControlPath.Wildcard) + { + childLayouts = EditorInputControlLayoutCache.allLayouts + .Where(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.isGenericTypeOfDevice).OrderBy(x => x.displayName); + } + + if (childLayouts.Count() > 0) + { + foreach (var childLayout in childLayouts) + { + for(int i = 0; i < childLayout.m_Controls.Length;i++) + { + if (InputControlPath.Matches(usages, name, ref childLayout.m_Controls[i])) + { + EditorGUILayout.LabelField(childLayout.displayName + "/" + childLayout.m_Controls[i].displayName); + continue; + } + } + + EditorGUI.indentLevel++; + DrawPathInfoForLayout(childLayout.name, usages, name); + EditorGUI.indentLevel--; + } + } + } + + + /// /// Draw control scheme matrix that allows selecting which control schemes a particular /// binding appears in. diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs index f473cdb830..db68570cdb 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs @@ -72,12 +72,13 @@ public OptionalControlDropdownItem(EditorInputControlLayoutCache.OptionalControl internal sealed class UsageDropdownItem : InputControlDropdownItem { - public override string controlPathWithDevice => $"{m_Device}/{{{m_ControlPath}}}"; + public override string controlPathWithDevice => string.IsNullOrEmpty(m_Device) ? $"*/{{{m_ControlPath}}}" + : $"<{m_Device}>/{{{m_ControlPath}}}"; - public UsageDropdownItem(string usage) + public UsageDropdownItem(string usage, string device) : base(usage) { - m_Device = "*"; + m_Device = device; m_ControlPath = usage; id = controlPathWithDevice.GetHashCode(); m_Searchable = true; diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs index 27aeb10d5a..20a640c168 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs @@ -81,7 +81,7 @@ protected override AdvancedDropdownItem BuildRoot() // Usages. if (m_Mode != InputControlPicker.Mode.PickDevice) { - var usages = BuildTreeForUsages(); + var usages = BuildTreeForControlUsages(); if (usages.children.Any()) { root.AddChild(usages); @@ -124,14 +124,14 @@ protected override void ItemSelected(AdvancedDropdownItem item) m_OnPickCallback(path); } - private AdvancedDropdownItem BuildTreeForUsages() + private AdvancedDropdownItem BuildTreeForControlUsages(string device = "") { var usageRoot = new AdvancedDropdownItem("Usages"); foreach (var usageAndLayouts in EditorInputControlLayoutCache.allUsages) { if (usageAndLayouts.Item2.Any(LayoutMatchesExpectedControlLayoutFilter)) { - var child = new UsageDropdownItem(usageAndLayouts.Item1); + var child = new UsageDropdownItem(usageAndLayouts.Item1, device); usageRoot.AddChild(child); } } @@ -183,12 +183,29 @@ private void AddDeviceTreeItemRecursive(InputControlLayout layout, AdvancedDropd var defaultControlPickerLayout = new DefaultInputControlPickerLayout(); - // Add common usage variants. + // Add control usages for the device + var deviceControlUsages = BuildTreeForControlUsages(layout.name); + if (deviceControlUsages.children.Any()) + { + deviceItem.AddChild(deviceControlUsages); + deviceItem.AddSeparator(); + } + + // Add common device usage variants. if (layout.commonUsages.Count > 0) { foreach (var usage in layout.commonUsages) { var usageItem = new DeviceDropdownItem(layout, usage); + + // Add control usages for the device sub-variant + var deviceVariantControlUsages = BuildTreeForControlUsages(usageItem.name); + if (deviceVariantControlUsages.children.Any()) + { + usageItem.AddChild(deviceVariantControlUsages); + usageItem.AddSeparator(); + } + if (m_Mode == InputControlPicker.Mode.PickControl) AddControlTreeItemsRecursive(defaultControlPickerLayout, layout, usageItem, layout.name, usage, searchable); deviceItem.AddChild(usageItem); From afca0e1ca7b92c7e9fd19c711b2e19380b577079 Mon Sep 17 00:00:00 2001 From: "roger.liu" Date: Fri, 14 Apr 2023 12:18:56 -0700 Subject: [PATCH 2/5] Style update, optimizing performance a bit --- .../InputSystem/Controls/InputControlPath.cs | 33 +++++++-------- .../AssetEditor/InputBindingPropertiesView.cs | 42 +++++++++---------- .../ControlPicker/InputControlDropdownItem.cs | 5 +-- .../InputControlPickerDropdown.cs | 22 +++++----- 4 files changed, 48 insertions(+), 54 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs b/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs index 45af3110b9..0edc1e4b6a 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Controls/InputControlPath.cs @@ -720,36 +720,33 @@ public static bool Matches(string expected, InputControl control) return MatchesRecursive(ref parser, control); } - internal static bool Matches(IEnumerable usages, string name, ref InputControlLayout.ControlItem controlItem) + internal static bool MatchControlComponent(ref ParsedPathComponent expectedControlComponent, ref InputControlLayout.ControlItem controlItem) { - if (usages.Count() > 0) + // All of usages should match to the one of usage in the control + foreach (var usage in expectedControlComponent.m_Usages) { - // All of usages should match to the one of usage in the control - foreach (var usage in usages) + if (!usage.isEmpty) { - if (usage.Length > 0) + var usageCount = controlItem.usages.Count; + var anyUsageMatches = false; + for (var i = 0; i < usageCount; ++i) { - var usageCount = controlItem.usages.Count; - var anyUsageMatches = false; - for (var i = 0; i < usageCount; ++i) + if (StringMatches(usage, controlItem.usages[i])) { - if (StringMatches(usage, controlItem.usages[i])) - { - anyUsageMatches = true; - break; - } + anyUsageMatches = true; + break; } - - if (!anyUsageMatches) - return false; } + + if (!anyUsageMatches) + return false; } } // Match name. - if (name.Length > 0) + if (!expectedControlComponent.m_Name.isEmpty) { - if (!StringMatches(name, controlItem.name)) + if (!StringMatches(expectedControlComponent.m_Name, controlItem.name)) return false; } diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs index 4f52e9594a..ff994da0f9 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs @@ -62,7 +62,7 @@ public void Dispose() m_ControlPathEditor?.Dispose(); } - bool showPaths = false; + private static bool showPaths = false; protected override void DrawGeneralProperties() { var currentPath = m_PathProperty.stringValue; @@ -104,12 +104,12 @@ protected override void DrawGeneralProperties() } } - showPaths = EditorGUILayout.Toggle("Show full paths", showPaths); + showPaths = EditorGUILayout.Toggle("Show all matched control paths", showPaths); // Show the specific layouts that implement the control on this path if (showPaths) { // Control scheme matrix. - DrawFullPathInfo(); + DrawMatchingControlPaths(); } // Control scheme matrix. DrawUseInControlSchemes(); @@ -117,48 +117,46 @@ protected override void DrawGeneralProperties() } /// - /// Draw control scheme matrix that allows selecting which control schemes a particular - /// binding appears in. + /// Finds all registered control paths implemented by concrete classes which match the current binding path and renders it. /// - private void DrawFullPathInfo() + private void DrawMatchingControlPaths() { - var path = m_ControlPathEditor.pathProperty.stringValue; var layout = InputControlPath.TryGetDeviceLayout(path); var parsedPath = InputControlPath.Parse(path).ToArray(); - // Try to find all relevant full paths if(parsedPath.Length == 2) { - var usages = parsedPath[1].usages; - var name = parsedPath[1].name; - EditorGUILayout.BeginVertical(); - DrawPathInfoForLayout(new InternedString(layout), usages, name); + DrawMatchingControlPathsForLayout(new InternedString(layout), ref parsedPath[1]); EditorGUILayout.EndVertical(); } - // Otherwise skip } - private void DrawPathInfoForLayout(InternedString rootLayout, IEnumerable usages, string name) + /// + /// Finds all registered control paths implemented by concrete classes under a given device layout which match the current binding path and renders it. + /// + /// The device layout to draw control paths for + /// The parsed path component containing details of the Input Controls that can be matched + private void DrawMatchingControlPathsForLayout(InternedString deviceLayout, ref InputControlPath.ParsedPathComponent pathControlComponent) { var path = m_ControlPathEditor.pathProperty.stringValue; - var childLayouts = EditorInputControlLayoutCache.allLayouts - .Where(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.baseLayouts.Contains(rootLayout)).OrderBy(x => x.displayName); + var matchedChildLayouts = EditorInputControlLayoutCache.allLayouts + .Where(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.baseLayouts.Contains(deviceLayout)).OrderBy(x => x.displayName); - if (rootLayout == InputControlPath.Wildcard) + if (deviceLayout == InputControlPath.Wildcard) { - childLayouts = EditorInputControlLayoutCache.allLayouts + matchedChildLayouts = EditorInputControlLayoutCache.allLayouts .Where(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.isGenericTypeOfDevice).OrderBy(x => x.displayName); } - if (childLayouts.Count() > 0) + if (matchedChildLayouts.Count() > 0) { - foreach (var childLayout in childLayouts) + foreach (var childLayout in matchedChildLayouts) { for(int i = 0; i < childLayout.m_Controls.Length;i++) { - if (InputControlPath.Matches(usages, name, ref childLayout.m_Controls[i])) + if (InputControlPath.MatchControlComponent(ref pathControlComponent, ref childLayout.m_Controls[i])) { EditorGUILayout.LabelField(childLayout.displayName + "/" + childLayout.m_Controls[i].displayName); continue; @@ -166,7 +164,7 @@ private void DrawPathInfoForLayout(InternedString rootLayout, IEnumerable string.IsNullOrEmpty(m_Device) ? $"*/{{{m_ControlPath}}}" - : $"<{m_Device}>/{{{m_ControlPath}}}"; + public override string controlPathWithDevice => string.IsNullOrEmpty(m_Device) ? $"*/{{{m_ControlPath}}}" : $"<{m_Device}>/{{{m_ControlPath}}}"; - public UsageDropdownItem(string usage, string device) + public UsageDropdownItem(string device, string usage) : base(usage) { m_Device = device; diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs index 20a640c168..5533c3ba00 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs @@ -131,7 +131,7 @@ private AdvancedDropdownItem BuildTreeForControlUsages(string device = "") { if (usageAndLayouts.Item2.Any(LayoutMatchesExpectedControlLayoutFilter)) { - var child = new UsageDropdownItem(usageAndLayouts.Item1, device); + var child = new UsageDropdownItem(device, usageAndLayouts.Item1); usageRoot.AddChild(child); } } @@ -183,22 +183,14 @@ private void AddDeviceTreeItemRecursive(InputControlLayout layout, AdvancedDropd var defaultControlPickerLayout = new DefaultInputControlPickerLayout(); - // Add control usages for the device - var deviceControlUsages = BuildTreeForControlUsages(layout.name); - if (deviceControlUsages.children.Any()) - { - deviceItem.AddChild(deviceControlUsages); - deviceItem.AddSeparator(); - } - - // Add common device usage variants. + // Add common usage variants of the device if (layout.commonUsages.Count > 0) { foreach (var usage in layout.commonUsages) { var usageItem = new DeviceDropdownItem(layout, usage); - // Add control usages for the device sub-variant + // Add control usages to the device variants var deviceVariantControlUsages = BuildTreeForControlUsages(usageItem.name); if (deviceVariantControlUsages.children.Any()) { @@ -213,6 +205,14 @@ private void AddDeviceTreeItemRecursive(InputControlLayout layout, AdvancedDropd deviceItem.AddSeparator(); } + // Add control usages + var deviceControlUsages = BuildTreeForControlUsages(layout.name); + if (deviceControlUsages.children.Any()) + { + deviceItem.AddChild(deviceControlUsages); + deviceItem.AddSeparator(); + } + // Add controls. if (m_Mode != InputControlPicker.Mode.PickDevice) { From 83244321f176b766dbb7e30c505b7f5c9ad35297 Mon Sep 17 00:00:00 2001 From: "roger.liu" Date: Fri, 14 Apr 2023 12:19:09 -0700 Subject: [PATCH 3/5] added unit test --- Assets/Tests/InputSystem/CoreTests_Layouts.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Assets/Tests/InputSystem/CoreTests_Layouts.cs b/Assets/Tests/InputSystem/CoreTests_Layouts.cs index a3b76d5f88..fc9eaa7b75 100644 --- a/Assets/Tests/InputSystem/CoreTests_Layouts.cs +++ b/Assets/Tests/InputSystem/CoreTests_Layouts.cs @@ -2546,6 +2546,43 @@ public void Layouts_CanForceMixedVariantsThroughLayout() Assert.That(device.allControls, Has.Exactly(1).With.Property("name").EqualTo("ButtonC")); } + [Test] + [Category("Layouts")] + public void Layouts_CanMatchControlPath() + { + const string jsonBase = @" + { + ""name"" : ""BaseLayout"", + ""extend"" : ""DeviceWithLayoutVariantA"", + ""controls"" : [ + { ""name"" : ""ControlFromBase"", ""layout"" : ""Button"" }, + { ""name"" : ""OtherControlFromBase"", ""layout"" : ""Axis"" }, + { ""name"" : ""ControlWithExplicitDefaultVariant"", ""layout"" : ""Axis"", ""variants"" : ""default"" }, + { ""name"" : ""StickControl"", ""layout"" : ""Stick"" }, + { ""name"" : ""StickControl/x"", ""offset"" : 14, ""variants"" : ""A"" } + ] + } + "; + const string jsonDerived = @" + { + ""name"" : ""DerivedLayout"", + ""extend"" : ""BaseLayout"", + ""controls"" : [ + { ""name"" : ""ControlFromBase"", ""variants"" : ""A"", ""offset"" : 20 } + ] + } + "; + + InputSystem.RegisterLayout(); + InputSystem.RegisterLayout(jsonBase); + InputSystem.RegisterLayout(jsonDerived); + + var layout = InputSystem.LoadLayout("DerivedLayout"); + var parsedPath = InputControlPath.Parse("/ControlWithExplicitDefaultVariant").ToArray()[1]; + + Assert.That(layout.m_Controls.Any(x => InputControlPath.MatchControlComponent(ref parsedPath, ref x)), Is.True); + } + [Test] [Category("Layouts")] [Ignore("TODO")] From 361cf5f25ca984c71012ab48f1898217061a71cd Mon Sep 17 00:00:00 2001 From: "roger.liu" Date: Fri, 14 Apr 2023 14:08:39 -0700 Subject: [PATCH 4/5] Control usages now create the right path when combined with device usages, now shows a message when no matching registered paths exist --- .../AssetEditor/InputBindingPropertiesView.cs | 17 +++++++++---- .../ControlPicker/InputControlDropdownItem.cs | 24 +++++++++++++++---- .../InputControlPickerDropdown.cs | 6 ++--- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs index ff994da0f9..1c9729bdc3 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs @@ -104,7 +104,7 @@ protected override void DrawGeneralProperties() } } - showPaths = EditorGUILayout.Toggle("Show all matched control paths", showPaths); + showPaths = EditorGUILayout.Toggle("Show Matching Paths", showPaths); // Show the specific layouts that implement the control on this path if (showPaths) { @@ -128,17 +128,21 @@ private void DrawMatchingControlPaths() if(parsedPath.Length == 2) { EditorGUILayout.BeginVertical(); - DrawMatchingControlPathsForLayout(new InternedString(layout), ref parsedPath[1]); + if(!DrawMatchingControlPathsForLayout(new InternedString(layout), ref parsedPath[1])) + { + EditorGUILayout.LabelField("No registered control paths match this current binding"); + } EditorGUILayout.EndVertical(); } } /// /// Finds all registered control paths implemented by concrete classes under a given device layout which match the current binding path and renders it. + /// Return true if there exist matching registered control paths, false otherwise. /// /// The device layout to draw control paths for /// The parsed path component containing details of the Input Controls that can be matched - private void DrawMatchingControlPathsForLayout(InternedString deviceLayout, ref InputControlPath.ParsedPathComponent pathControlComponent) + private bool DrawMatchingControlPathsForLayout(InternedString deviceLayout, ref InputControlPath.ParsedPathComponent pathControlComponent) { var path = m_ControlPathEditor.pathProperty.stringValue; var matchedChildLayouts = EditorInputControlLayoutCache.allLayouts @@ -150,6 +154,8 @@ private void DrawMatchingControlPathsForLayout(InternedString deviceLayout, ref .Where(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.isGenericTypeOfDevice).OrderBy(x => x.displayName); } + bool matchExists = false; + if (matchedChildLayouts.Count() > 0) { foreach (var childLayout in matchedChildLayouts) @@ -159,15 +165,18 @@ private void DrawMatchingControlPathsForLayout(InternedString deviceLayout, ref if (InputControlPath.MatchControlComponent(ref pathControlComponent, ref childLayout.m_Controls[i])) { EditorGUILayout.LabelField(childLayout.displayName + "/" + childLayout.m_Controls[i].displayName); + matchExists = true; continue; } } EditorGUI.indentLevel++; - DrawMatchingControlPathsForLayout(childLayout.name, ref pathControlComponent); + matchExists |= DrawMatchingControlPathsForLayout(childLayout.name, ref pathControlComponent); EditorGUI.indentLevel--; } } + + return matchExists; } diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs index da4bd332ad..b955c9eea9 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs @@ -70,15 +70,31 @@ public OptionalControlDropdownItem(EditorInputControlLayoutCache.OptionalControl } } - internal sealed class UsageDropdownItem : InputControlDropdownItem + internal sealed class ControlUsageDropdownItem : InputControlDropdownItem { - public override string controlPathWithDevice => string.IsNullOrEmpty(m_Device) ? $"*/{{{m_ControlPath}}}" : $"<{m_Device}>/{{{m_ControlPath}}}"; + public override string controlPathWithDevice => BuildControlPath(); + private string BuildControlPath() + { + if (m_Device == "*") + { + var path = new StringBuilder(m_Device); + if (!string.IsNullOrEmpty(m_Usage)) + path.Append($"{{{m_Usage}}}"); + if (!string.IsNullOrEmpty(m_ControlPath)) + path.Append($"/{m_ControlPath}"); + return path.ToString(); + } + else + return base.controlPathWithDevice; + } - public UsageDropdownItem(string device, string usage) + public ControlUsageDropdownItem(string device, string usage, string controlUsage) : base(usage) { m_Device = device; - m_ControlPath = usage; + m_Usage = usage; + m_ControlPath = $"{{{ controlUsage }}}"; + name = controlUsage; id = controlPathWithDevice.GetHashCode(); m_Searchable = true; } diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs index 5533c3ba00..5f595a6a1d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlPickerDropdown.cs @@ -124,14 +124,14 @@ protected override void ItemSelected(AdvancedDropdownItem item) m_OnPickCallback(path); } - private AdvancedDropdownItem BuildTreeForControlUsages(string device = "") + private AdvancedDropdownItem BuildTreeForControlUsages(string device = "", string usage = "") { var usageRoot = new AdvancedDropdownItem("Usages"); foreach (var usageAndLayouts in EditorInputControlLayoutCache.allUsages) { if (usageAndLayouts.Item2.Any(LayoutMatchesExpectedControlLayoutFilter)) { - var child = new UsageDropdownItem(device, usageAndLayouts.Item1); + var child = new ControlUsageDropdownItem(device, usage, usageAndLayouts.Item1); usageRoot.AddChild(child); } } @@ -191,7 +191,7 @@ private void AddDeviceTreeItemRecursive(InputControlLayout layout, AdvancedDropd var usageItem = new DeviceDropdownItem(layout, usage); // Add control usages to the device variants - var deviceVariantControlUsages = BuildTreeForControlUsages(usageItem.name); + var deviceVariantControlUsages = BuildTreeForControlUsages(layout.name, usage); if (deviceVariantControlUsages.children.Any()) { usageItem.AddChild(deviceVariantControlUsages); From a9f0caca089b85a7822196fbb26e385888703bae Mon Sep 17 00:00:00 2001 From: "roger.liu" Date: Fri, 14 Apr 2023 14:56:53 -0700 Subject: [PATCH 5/5] updated to show relevant information when the path doesn't match any additional contexts --- .../AssetEditor/InputBindingPropertiesView.cs | 41 +++++++++++++++---- .../ControlPicker/InputControlDropdownItem.cs | 2 +- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs index 1c9729bdc3..2abb958468 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/AssetEditor/InputBindingPropertiesView.cs @@ -122,18 +122,45 @@ protected override void DrawGeneralProperties() private void DrawMatchingControlPaths() { var path = m_ControlPathEditor.pathProperty.stringValue; - var layout = InputControlPath.TryGetDeviceLayout(path); + var deviceLayout = new InternedString(InputControlPath.TryGetDeviceLayout(path)); var parsedPath = InputControlPath.Parse(path).ToArray(); - if(parsedPath.Length == 2) + bool matchExists = false; + EditorGUILayout.BeginVertical(); + if (parsedPath.Length == 2) { - EditorGUILayout.BeginVertical(); - if(!DrawMatchingControlPathsForLayout(new InternedString(layout), ref parsedPath[1])) + if (deviceLayout != InputControlPath.Wildcard) + { + var rootLayout = EditorInputControlLayoutCache.allLayouts.FirstOrDefault(x => x.isDeviceLayout && !x.isOverride && !x.hideInUI && x.name == deviceLayout); + if (rootLayout != null) + { + for (int i = 0; i < rootLayout.m_Controls.Length; i++) + { + if (InputControlPath.MatchControlComponent(ref parsedPath[1], ref rootLayout.m_Controls[i])) + { + EditorGUILayout.LabelField($"{rootLayout.displayName}/{rootLayout.m_Controls[i].displayName}"); + matchExists = true; + continue; + } + } + + EditorGUI.indentLevel++; + matchExists |= DrawMatchingControlPathsForLayout(deviceLayout, ref parsedPath[1]); + EditorGUI.indentLevel--; + } + } + else { - EditorGUILayout.LabelField("No registered control paths match this current binding"); + matchExists |= DrawMatchingControlPathsForLayout(deviceLayout, ref parsedPath[1]); } - EditorGUILayout.EndVertical(); } + + if (!matchExists) + { + EditorGUILayout.LabelField("No registered control paths match this current binding"); + } + + EditorGUILayout.EndVertical(); } /// @@ -164,7 +191,7 @@ private bool DrawMatchingControlPathsForLayout(InternedString deviceLayout, ref { if (InputControlPath.MatchControlComponent(ref pathControlComponent, ref childLayout.m_Controls[i])) { - EditorGUILayout.LabelField(childLayout.displayName + "/" + childLayout.m_Controls[i].displayName); + EditorGUILayout.LabelField($"{childLayout.displayName}/{childLayout.m_Controls[i].displayName}"); matchExists = true; continue; } diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs index b955c9eea9..a1bc18709d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ControlPicker/InputControlDropdownItem.cs @@ -91,7 +91,7 @@ private string BuildControlPath() public ControlUsageDropdownItem(string device, string usage, string controlUsage) : base(usage) { - m_Device = device; + m_Device = string.IsNullOrEmpty(device) ? "*" : device; m_Usage = usage; m_ControlPath = $"{{{ controlUsage }}}"; name = controlUsage;