Maze / Library /PackageCache /com.unity.inputsystem@1.6.1 /InputSystem /Devices /InputDeviceMatcher.cs
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text.RegularExpressions; | |
| using UnityEngine.InputSystem.Utilities; | |
| namespace UnityEngine.InputSystem.Layouts | |
| { | |
| /// <summary> | |
| /// Specification that can be matched against an <see cref="InputDeviceDescription"/>. This is | |
| /// used to find which <see cref="InputControlLayout"/> to create for a device when it is discovered. | |
| /// </summary> | |
| /// <remarks> | |
| /// Each matcher is basically a set of key/value pairs where each value may either be | |
| /// a regular expression or a plain value object. The central method for testing a given matcher | |
| /// against an <see cref="InputDeviceDescription"/> is <see cref="MatchPercentage"/>. | |
| /// | |
| /// Various helper methods such as <see cref="WithInterface"/> or <see cref="WithCapability{TValue}"/> | |
| /// assist with creating matchers. | |
| /// | |
| /// <example> | |
| /// <code> | |
| /// // A matcher that matches a PS4 controller by name. | |
| /// new InputDeviceMatcher() | |
| /// .WithInterface("HID") | |
| /// .WithManufacturer("Sony.+Entertainment") // Regular expression | |
| /// .WithProduct("Wireless Controller")); | |
| /// | |
| /// // A matcher that matches the same controller by PID and VID. | |
| /// new InputDeviceMatcher() | |
| /// .WithInterface("HID") | |
| /// .WithCapability("vendorId", 0x54C) // Sony Entertainment. | |
| /// .WithCapability("productId", 0x9CC)); // Wireless controller. | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// For each registered <see cref="InputControlLayout"/> in the system that represents | |
| /// a device, arbitrary many matchers can be added. A matcher can be supplied either | |
| /// at registration time or at any point after using <see cref="InputSystem.RegisterLayoutMatcher"/>. | |
| /// | |
| /// <example> | |
| /// <code> | |
| /// // Supply a matcher at registration time. | |
| /// InputSystem.RegisterLayout<DualShock4GamepadHID>( | |
| /// matches: new InputDeviceMatcher() | |
| /// .WithInterface("HID") | |
| /// .WithCapability("vendorId", 0x54C) // Sony Entertainment. | |
| /// .WithCapability("productId", 0x9CC)); // Wireless controller. | |
| /// | |
| /// // Supply a matcher for an already registered layout. | |
| /// // This can be called repeatedly and will add another matcher | |
| /// // each time. | |
| /// InputSystem.RegisterLayoutMatcher<DualShock4GamepadHID>( | |
| /// matches: new InputDeviceMatcher() | |
| /// .WithInterface("HID") | |
| /// .WithManufacturer("Sony.+Entertainment") | |
| /// .WithProduct("Wireless Controller")); | |
| /// </code> | |
| /// </example> | |
| /// </remarks> | |
| /// <seealso cref="InputDeviceDescription"/> | |
| /// <seealso cref="InputDevice.description"/> | |
| /// <seealso cref="InputSystem.RegisterLayoutMatcher"/> | |
| public struct InputDeviceMatcher : IEquatable<InputDeviceMatcher> | |
| { | |
| private KeyValuePair<InternedString, object>[] m_Patterns; | |
| /// <summary> | |
| /// If true, the matcher has been default-initialized and contains no | |
| /// matching <see cref="patterns"/>. | |
| /// </summary> | |
| /// <value>Whether the matcher contains any matching patterns.</value> | |
| /// <seealso cref="patterns"/> | |
| public bool empty => m_Patterns == null; | |
| /// <summary> | |
| /// The list of patterns to match. | |
| /// </summary> | |
| /// <value>List of matching patterns.</value> | |
| /// <remarks> | |
| /// Each pattern is comprised of a key and a value. The key determines which part | |
| /// of an <see cref="InputDeviceDescription"/> to match. | |
| /// | |
| /// The value represents the expected value. This can be either a plain string | |
| /// (matched case-insensitive) or a regular expression. | |
| /// </remarks> | |
| /// <seealso cref="WithInterface"/> | |
| /// <seealso cref="WithCapability{TValue}"/> | |
| /// <seealso cref="WithProduct"/> | |
| /// <seealso cref="WithManufacturer"/> | |
| /// <seealso cref="WithVersion"/> | |
| /// <seealso cref="WithDeviceClass"/> | |
| public IEnumerable<KeyValuePair<string, object>> patterns | |
| { | |
| get | |
| { | |
| if (m_Patterns == null) | |
| yield break; | |
| var count = m_Patterns.Length; | |
| for (var i = 0; i < count; ++i) | |
| yield return new KeyValuePair<string, object>(m_Patterns[i].Key.ToString(), m_Patterns[i].Value); | |
| } | |
| } | |
| /// <summary> | |
| /// Add a pattern to <see cref="patterns"/> to match an <see cref="InputDeviceDescription.interfaceName"/>. | |
| /// </summary> | |
| /// <param name="pattern">String to match.</param> | |
| /// <param name="supportRegex">If true (default), <paramref name="pattern"/> can be | |
| /// a regular expression.</param> | |
| /// <returns>The modified device matcher with the added pattern.</returns> | |
| /// <seealso cref="InputDeviceDescription.interfaceName"/> | |
| public InputDeviceMatcher WithInterface(string pattern, bool supportRegex = true) | |
| { | |
| return With(kInterfaceKey, pattern, supportRegex); | |
| } | |
| /// <summary> | |
| /// Add a pattern to <see cref="patterns"/> to match a <see cref="InputDeviceDescription.deviceClass"/>. | |
| /// </summary> | |
| /// <param name="pattern">String to match.</param> | |
| /// <param name="supportRegex">If true (default), <paramref name="pattern"/> can be | |
| /// a regular expression.</param> | |
| /// <returns>The modified device matcher with the added pattern.</returns> | |
| /// <seealso cref="InputDeviceDescription.deviceClass"/> | |
| public InputDeviceMatcher WithDeviceClass(string pattern, bool supportRegex = true) | |
| { | |
| return With(kDeviceClassKey, pattern, supportRegex); | |
| } | |
| /// <summary> | |
| /// Add a pattern to <see cref="patterns"/> to match a <see cref="InputDeviceDescription.manufacturer"/>. | |
| /// </summary> | |
| /// <param name="pattern">String to match.</param> | |
| /// <param name="supportRegex">If true (default), <paramref name="pattern"/> can be | |
| /// a regular expression.</param> | |
| /// <returns>The modified device matcher with the added pattern.</returns> | |
| /// <seealso cref="InputDeviceDescription.manufacturer"/> | |
| public InputDeviceMatcher WithManufacturer(string pattern, bool supportRegex = true) | |
| { | |
| return With(kManufacturerKey, pattern, supportRegex); | |
| } | |
| /// <summary> | |
| /// Add a pattern to <see cref="patterns"/> to match a <see cref="InputDeviceDescription.product"/>. | |
| /// </summary> | |
| /// <param name="pattern">String to match.</param> | |
| /// <param name="supportRegex">If true (default), <paramref name="pattern"/> can be | |
| /// a regular expression.</param> | |
| /// <returns>The modified device matcher with the added pattern.</returns> | |
| /// <seealso cref="InputDeviceDescription.product"/> | |
| public InputDeviceMatcher WithProduct(string pattern, bool supportRegex = true) | |
| { | |
| return With(kProductKey, pattern, supportRegex); | |
| } | |
| /// <summary> | |
| /// Add a pattern to <see cref="patterns"/> to match a <see cref="InputDeviceDescription.version"/>. | |
| /// </summary> | |
| /// <param name="pattern">String to match.</param> | |
| /// <param name="supportRegex">If true (default), <paramref name="pattern"/> can be | |
| /// a regular expression.</param> | |
| /// <returns>The modified device matcher with the added pattern.</returns> | |
| /// <seealso cref="InputDeviceDescription.version"/> | |
| public InputDeviceMatcher WithVersion(string pattern, bool supportRegex = true) | |
| { | |
| return With(kVersionKey, pattern, supportRegex); | |
| } | |
| /// <summary> | |
| /// Add a pattern to <see cref="patterns"/> to match an individual capability in <see cref="InputDeviceDescription.capabilities"/>. | |
| /// </summary> | |
| /// <param name="path">Path to the JSON property using '/' as a separator, | |
| /// e.g. <c>"elements/count"</c>.</param> | |
| /// <param name="value">Value to match. This can be a string, a regular expression, | |
| /// a boolean, an integer, or a float. Floating-point numbers are matched with respect | |
| /// for <c>Mathf.Epsilon</c>. Values are converted between types automatically as | |
| /// needed (meaning that a bool can be compared to a string, for example).</param> | |
| /// <typeparam name="TValue">Type of value to match.</typeparam> | |
| /// <returns>The modified device matcher with the added pattern.</returns> | |
| /// <remarks> | |
| /// Capabilities are stored as JSON strings in <see cref="InputDeviceDescription.capabilities"/>. | |
| /// A matcher has the ability to match specific properties from the JSON object | |
| /// contained in the capabilities string. | |
| /// | |
| /// <example> | |
| /// <code> | |
| /// // The description for a HID will usually have a HIDDeviceDescriptor in | |
| /// // JSON format found on its InputDeviceDescription.capabilities. So, a | |
| /// // real-world device description could look the equivalent of this: | |
| /// var description = new InputDeviceDescription | |
| /// { | |
| /// interfaceName = "HID", | |
| /// capabilities = new HID.HIDDeviceDescriptor | |
| /// { | |
| /// vendorId = 0x54C, | |
| /// productId = 0x9CC | |
| /// }.ToJson() | |
| /// }; | |
| /// | |
| /// // We can create a device matcher that looks for those to properties | |
| /// // directly in the JSON object. | |
| /// new InputDeviceMatcher() | |
| /// .WithCapability("vendorId", 0x54C) | |
| /// .WithCapability("productId", 0x9CC); | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// Properties in nested objects can be referenced by separating properties | |
| /// with <c>/</c> and properties in arrays can be indexed with <c>[..]</c>. | |
| /// </remarks> | |
| /// <seealso cref="InputDeviceDescription.capabilities"/> | |
| public InputDeviceMatcher WithCapability<TValue>(string path, TValue value) | |
| { | |
| return With(new InternedString(path), value); | |
| } | |
| private InputDeviceMatcher With(InternedString key, object value, bool supportRegex = true) | |
| { | |
| // If it's a string, check whether it's a regex. | |
| if (supportRegex && value is string str) | |
| { | |
| var mayBeRegex = !str.All(ch => char.IsLetterOrDigit(ch) || char.IsWhiteSpace(ch)) && | |
| !double.TryParse(str, out var _); // Avoid '.' in floats forcing the value to be a regex. | |
| if (mayBeRegex) | |
| value = new Regex(str, RegexOptions.IgnoreCase); | |
| } | |
| // Add to list. | |
| var result = this; | |
| ArrayHelpers.Append(ref result.m_Patterns, new KeyValuePair<InternedString, object>(key, value)); | |
| return result; | |
| } | |
| /// <summary> | |
| /// Return the level of matching to the given <paramref name="deviceDescription"/>. | |
| /// </summary> | |
| /// <param name="deviceDescription">A device description.</param> | |
| /// <returns>A score usually in the range between 0 and 1.</returns> | |
| /// <remarks> | |
| /// The algorithm computes a score of how well the matcher matches the given description. | |
| /// Essentially, a matcher that matches every single property that is present (as in | |
| /// not <c>null</c> and not an empty string) in <paramref name="deviceDescription"/> receives | |
| /// a score of 1, a matcher that matches none a score of 0. Matches that match only a subset | |
| /// receive a score in-between. | |
| /// | |
| /// An exception to this are capabilities. Every single match of a capability is counted | |
| /// as one property match and added to the score. This means that matchers that match | |
| /// on multiple capabilities may actually achieve a score >1. | |
| /// | |
| /// <example> | |
| /// <code> | |
| /// var description = new InputDeviceDescription | |
| /// { | |
| /// interfaceName = "HID", | |
| /// product = "MadeUpDevice", | |
| /// capabilities = new HID.HIDDeviceDescriptor | |
| /// { | |
| /// vendorId = 0xABC, | |
| /// productId = 0xDEF | |
| /// }.ToJson() | |
| /// }; | |
| /// | |
| /// // This matcher will achieve a score of 0.666 (2/3) as it | |
| /// // matches two out of three available properties. | |
| /// new InputDeviceMatcher() | |
| /// .WithInterface("HID") | |
| /// .WithProduct("MadeUpDevice"); | |
| /// | |
| /// // This matcher will achieve a score of 1 despite not matching | |
| /// // 'product'. The reason is that it matches two keys in | |
| /// // 'capabilities'. | |
| /// new InputDeviceMatcher() | |
| /// .WithInterface("HID") | |
| /// .WithCapability("vendorId", 0xABC) | |
| /// .WithCapability("productId", 0xDEF); | |
| /// </code> | |
| /// </example> | |
| /// </remarks> | |
| public float MatchPercentage(InputDeviceDescription deviceDescription) | |
| { | |
| if (empty) | |
| return 0; | |
| // Go through all patterns. Score is 0 if any of the patterns | |
| // doesn't match. | |
| var numPatterns = m_Patterns.Length; | |
| for (var i = 0; i < numPatterns; ++i) | |
| { | |
| var key = m_Patterns[i].Key; | |
| var pattern = m_Patterns[i].Value; | |
| if (key == kInterfaceKey) | |
| { | |
| if (string.IsNullOrEmpty(deviceDescription.interfaceName) | |
| || !MatchSingleProperty(pattern, deviceDescription.interfaceName)) | |
| return 0; | |
| } | |
| else if (key == kDeviceClassKey) | |
| { | |
| if (string.IsNullOrEmpty(deviceDescription.deviceClass) | |
| || !MatchSingleProperty(pattern, deviceDescription.deviceClass)) | |
| return 0; | |
| } | |
| else if (key == kManufacturerKey) | |
| { | |
| if (string.IsNullOrEmpty(deviceDescription.manufacturer) | |
| || !MatchSingleProperty(pattern, deviceDescription.manufacturer)) | |
| return 0; | |
| } | |
| else if (key == kProductKey) | |
| { | |
| if (string.IsNullOrEmpty(deviceDescription.product) | |
| || !MatchSingleProperty(pattern, deviceDescription.product)) | |
| return 0; | |
| } | |
| else if (key == kVersionKey) | |
| { | |
| if (string.IsNullOrEmpty(deviceDescription.version) | |
| || !MatchSingleProperty(pattern, deviceDescription.version)) | |
| return 0; | |
| } | |
| else | |
| { | |
| // Capabilities match. Take the key as a path into the JSON | |
| // object and match the value found at the given path. | |
| if (string.IsNullOrEmpty(deviceDescription.capabilities)) | |
| return 0; | |
| var graph = new JsonParser(deviceDescription.capabilities); | |
| if (!graph.NavigateToProperty(key.ToString()) || | |
| !graph.CurrentPropertyHasValueEqualTo(new JsonParser.JsonValue { type = JsonParser.JsonValueType.Any, anyValue = pattern})) | |
| return 0; | |
| } | |
| } | |
| // All patterns matched. Our score is determined by the number of properties | |
| // we matched against. | |
| var propertyCountInDescription = GetNumPropertiesIn(deviceDescription); | |
| var scorePerProperty = 1.0f / propertyCountInDescription; | |
| return numPatterns * scorePerProperty; | |
| } | |
| private static bool MatchSingleProperty(object pattern, string value) | |
| { | |
| // String match. | |
| if (pattern is string str) | |
| return string.Compare(str, value, StringComparison.OrdinalIgnoreCase) == 0; | |
| // Regex match. | |
| if (pattern is Regex regex) | |
| return regex.IsMatch(value); | |
| return false; | |
| } | |
| private static int GetNumPropertiesIn(InputDeviceDescription description) | |
| { | |
| var count = 0; | |
| if (!string.IsNullOrEmpty(description.interfaceName)) | |
| count += 1; | |
| if (!string.IsNullOrEmpty(description.deviceClass)) | |
| count += 1; | |
| if (!string.IsNullOrEmpty(description.manufacturer)) | |
| count += 1; | |
| if (!string.IsNullOrEmpty(description.product)) | |
| count += 1; | |
| if (!string.IsNullOrEmpty(description.version)) | |
| count += 1; | |
| if (!string.IsNullOrEmpty(description.capabilities)) | |
| count += 1; | |
| return count; | |
| } | |
| /// <summary> | |
| /// Produce a matcher that matches the given device description verbatim. | |
| /// </summary> | |
| /// <param name="deviceDescription">A device description.</param> | |
| /// <returns>A matcher that matches <paramref name="deviceDescription"/> exactly.</returns> | |
| /// <remarks> | |
| /// This method can be used to produce a matcher for an existing device description, | |
| /// e.g. when writing a layout <see cref="InputControlLayout.Builder"/> that produces | |
| /// layouts for devices on the fly. | |
| /// </remarks> | |
| public static InputDeviceMatcher FromDeviceDescription(InputDeviceDescription deviceDescription) | |
| { | |
| var matcher = new InputDeviceMatcher(); | |
| if (!string.IsNullOrEmpty(deviceDescription.interfaceName)) | |
| matcher = matcher.WithInterface(deviceDescription.interfaceName, false); | |
| if (!string.IsNullOrEmpty(deviceDescription.deviceClass)) | |
| matcher = matcher.WithDeviceClass(deviceDescription.deviceClass, false); | |
| if (!string.IsNullOrEmpty(deviceDescription.manufacturer)) | |
| matcher = matcher.WithManufacturer(deviceDescription.manufacturer, false); | |
| if (!string.IsNullOrEmpty(deviceDescription.product)) | |
| matcher = matcher.WithProduct(deviceDescription.product, false); | |
| if (!string.IsNullOrEmpty(deviceDescription.version)) | |
| matcher = matcher.WithVersion(deviceDescription.version, false); | |
| // We don't include capabilities in this conversion. | |
| return matcher; | |
| } | |
| /// <summary> | |
| /// Return a string representation useful for debugging. Lists the | |
| /// <see cref="patterns"/> contained in the matcher. | |
| /// </summary> | |
| /// <returns>A string representation of the matcher.</returns> | |
| public override string ToString() | |
| { | |
| if (empty) | |
| return "<empty>"; | |
| var result = string.Empty; | |
| foreach (var pattern in m_Patterns) | |
| { | |
| if (result.Length > 0) | |
| result += $",{pattern.Key}={pattern.Value}"; | |
| else | |
| result += $"{pattern.Key}={pattern.Value}"; | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Test whether this matcher is equivalent to the <paramref name="other"/> matcher. | |
| /// </summary> | |
| /// <param name="other">Another device matcher.</param> | |
| /// <returns>True if the two matchers are equivalent.</returns> | |
| /// <remarks> | |
| /// Two matchers are equivalent if they contain the same number of patterns and the | |
| /// same pattern occurs in each of the matchers. Order of the patterns does not | |
| /// matter. | |
| /// </remarks> | |
| [] | |
| public bool Equals(InputDeviceMatcher other) | |
| { | |
| if (m_Patterns == other.m_Patterns) | |
| return true; | |
| if (m_Patterns == null || other.m_Patterns == null) | |
| return false; | |
| if (m_Patterns.Length != other.m_Patterns.Length) | |
| return false; | |
| // Pattern count matches. Compare pattern by pattern. Order of patterns doesn't matter. | |
| for (var i = 0; i < m_Patterns.Length; ++i) | |
| { | |
| var thisPattern = m_Patterns[i]; | |
| var foundPattern = false; | |
| for (var n = 0; n < m_Patterns.Length; ++n) | |
| { | |
| var otherPattern = other.m_Patterns[n]; | |
| if (thisPattern.Key != otherPattern.Key) | |
| continue; | |
| if (!thisPattern.Value.Equals(otherPattern.Value)) | |
| return false; | |
| foundPattern = true; | |
| break; | |
| } | |
| if (!foundPattern) | |
| return false; | |
| } | |
| return true; | |
| } | |
| /// <summary> | |
| /// Compare this matcher to another. | |
| /// </summary> | |
| /// <param name="obj">A matcher object or <c>null</c>.</param> | |
| /// <returns>True if the matcher is equivalent.</returns> | |
| /// <seealso cref="Equals(InputDeviceMatcher)"/> | |
| public override bool Equals(object obj) | |
| { | |
| if (ReferenceEquals(null, obj)) | |
| return false; | |
| return obj is InputDeviceMatcher matcher && Equals(matcher); | |
| } | |
| /// <summary> | |
| /// Compare two matchers for equivalence. | |
| /// </summary> | |
| /// <param name="left">First device matcher.</param> | |
| /// <param name="right">Second device matcher.</param> | |
| /// <returns>True if the two matchers are equivalent.</returns> | |
| /// <seealso cref="Equals(InputDeviceMatcher)"/> | |
| public static bool operator==(InputDeviceMatcher left, InputDeviceMatcher right) | |
| { | |
| return left.Equals(right); | |
| } | |
| /// <summary> | |
| /// Compare two matchers for non-equivalence. | |
| /// </summary> | |
| /// <param name="left">First device matcher.</param> | |
| /// <param name="right">Second device matcher.</param> | |
| /// <returns>True if the two matchers are not equivalent.</returns> | |
| /// <seealso cref="Equals(InputDeviceMatcher)"/> | |
| public static bool operator!=(InputDeviceMatcher left, InputDeviceMatcher right) | |
| { | |
| return !(left == right); | |
| } | |
| /// <summary> | |
| /// Compute a hash code for the device matcher. | |
| /// </summary> | |
| /// <returns>A hash code for the matcher.</returns> | |
| public override int GetHashCode() | |
| { | |
| return m_Patterns != null ? m_Patterns.GetHashCode() : 0; | |
| } | |
| private static readonly InternedString kInterfaceKey = new InternedString("interface"); | |
| private static readonly InternedString kDeviceClassKey = new InternedString("deviceClass"); | |
| private static readonly InternedString kManufacturerKey = new InternedString("manufacturer"); | |
| private static readonly InternedString kProductKey = new InternedString("product"); | |
| private static readonly InternedString kVersionKey = new InternedString("version"); | |
| [] | |
| internal struct MatcherJson | |
| { | |
| public string @interface; | |
| public string[] interfaces; | |
| public string deviceClass; | |
| public string[] deviceClasses; | |
| public string manufacturer; | |
| public string[] manufacturers; | |
| public string product; | |
| public string[] products; | |
| public string version; | |
| public string[] versions; | |
| public Capability[] capabilities; | |
| public struct Capability | |
| { | |
| public string path; | |
| public string value; | |
| } | |
| public static MatcherJson FromMatcher(InputDeviceMatcher matcher) | |
| { | |
| if (matcher.empty) | |
| return new MatcherJson(); | |
| var json = new MatcherJson(); | |
| foreach (var pattern in matcher.m_Patterns) | |
| { | |
| var key = pattern.Key; | |
| var value = pattern.Value.ToString(); | |
| if (key == kInterfaceKey) | |
| { | |
| if (json.@interface == null) | |
| json.@interface = value; | |
| else | |
| ArrayHelpers.Append(ref json.interfaces, value); | |
| } | |
| else if (key == kDeviceClassKey) | |
| { | |
| if (json.deviceClass == null) | |
| json.deviceClass = value; | |
| else | |
| ArrayHelpers.Append(ref json.deviceClasses, value); | |
| } | |
| else if (key == kManufacturerKey) | |
| { | |
| if (json.manufacturer == null) | |
| json.manufacturer = value; | |
| else | |
| ArrayHelpers.Append(ref json.manufacturers, value); | |
| } | |
| else if (key == kProductKey) | |
| { | |
| if (json.product == null) | |
| json.product = value; | |
| else | |
| ArrayHelpers.Append(ref json.products, value); | |
| } | |
| else if (key == kVersionKey) | |
| { | |
| if (json.version == null) | |
| json.version = value; | |
| else | |
| ArrayHelpers.Append(ref json.versions, value); | |
| } | |
| else | |
| { | |
| ArrayHelpers.Append(ref json.capabilities, new Capability {path = key, value = value}); | |
| } | |
| } | |
| return json; | |
| } | |
| public InputDeviceMatcher ToMatcher() | |
| { | |
| var matcher = new InputDeviceMatcher(); | |
| ////TODO: get rid of the piecemeal array allocation and do it in one step | |
| // Interfaces. | |
| if (!string.IsNullOrEmpty(@interface)) | |
| matcher = matcher.WithInterface(@interface); | |
| if (interfaces != null) | |
| foreach (var value in interfaces) | |
| matcher = matcher.WithInterface(value); | |
| // Device classes. | |
| if (!string.IsNullOrEmpty(deviceClass)) | |
| matcher = matcher.WithDeviceClass(deviceClass); | |
| if (deviceClasses != null) | |
| foreach (var value in deviceClasses) | |
| matcher = matcher.WithDeviceClass(value); | |
| // Manufacturer. | |
| if (!string.IsNullOrEmpty(manufacturer)) | |
| matcher = matcher.WithManufacturer(manufacturer); | |
| if (manufacturers != null) | |
| foreach (var value in manufacturers) | |
| matcher = matcher.WithManufacturer(value); | |
| // Product. | |
| if (!string.IsNullOrEmpty(product)) | |
| matcher = matcher.WithProduct(product); | |
| if (products != null) | |
| foreach (var value in products) | |
| matcher = matcher.WithProduct(value); | |
| // Version. | |
| if (!string.IsNullOrEmpty(version)) | |
| matcher = matcher.WithVersion(version); | |
| if (versions != null) | |
| foreach (var value in versions) | |
| matcher = matcher.WithVersion(value); | |
| // Capabilities. | |
| if (capabilities != null) | |
| foreach (var value in capabilities) | |
| ////FIXME: we're turning all values into strings here | |
| matcher = matcher.WithCapability(value.path, value.value); | |
| return matcher; | |
| } | |
| } | |
| } | |
| } | |