Skip to content
26 changes: 26 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Controls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1607,4 +1607,30 @@ static void CheckChildControls(Type type, HashSet<Type> checkedTypes)
Assert.That(setMethod.IsPublic, Is.True, inputControlMessage);
}
}

[Test]
[Category("Controls")]
public void Controls_MatchPathComponent_CollapsesConsecutiveWildcards()
{
var component = "leftTrigger";
var componentType = InputControlPath.PathComponentType.Name;

var patterns = new[]
{
"*Trigger",
"**Trigger",
"***Trigger"
};

foreach (var path in patterns)
{
var indexInPath = 0;
var result = InputControlPath.MatchPathComponent(component, path, ref indexInPath, componentType);

// All patterns should match
Assert.IsTrue(result, $"Pattern '{path}' should match '{component}'");
Assert.AreEqual(path.Length, indexInPath,
$"Index should advance past entire pattern for '{path}'");
}
}
}
2 changes: 1 addition & 1 deletion Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ however, it has to be formatted properly to pass verification tests.
## [1.18.0] - 2026-01-14

### Changed

- Consecutive wildcard characters ('*') used in input control-paths are now collapsed into a single wildcard when multiple consecutive wildcard characters are present.
- Updated documentation to reflect that the OnMouse MonoBehaviour events are now supported in Unity 6.4 and above.
- Updated the supported devices documentation to clarify that touchscreens are supported on Linux.
- Updated documentation to reflect PS5 controller support on Linux.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1031,15 +1031,15 @@ private static TControl MatchChildrenRecursive<TControl>(InputControl control, s
return lastMatch;
}

private enum PathComponentType
internal enum PathComponentType
{
Name,
DisplayName,
Usage,
Layout
}

private static bool MatchPathComponent(string component, string path, ref int indexInPath, PathComponentType componentType, int startIndexInComponent = 0)
internal static bool MatchPathComponent(string component, string path, ref int indexInPath, PathComponentType componentType, int startIndexInComponent = 0)
{
Debug.Assert(component != null, "Component string is null");
Debug.Assert(path != null, "Path is null");
Expand Down Expand Up @@ -1072,10 +1072,13 @@ private static bool MatchPathComponent(string component, string path, ref int in
break;
}

////TODO: allow only single '*' and recognize '**'
// If we've reached a '*' in the path, skip character in name.
if (nextCharInPath == '*')
{
// Collapse consecutive '*' so matching logic here only needs to handle a single '*'.
while (indexInPath + 1 < pathLength && path[indexInPath + 1] == '*')
++indexInPath;

// But first let's see if we have something after the wildcard that matches the rest of the component.
// This could be when, for example, we hit "T" on matching "leftTrigger" against "*Trigger". We have to stop
// gobbling up characters for the wildcard when reaching "Trigger" in the component name.
Expand Down