예제 #1
0
        ////TODO: return Substring and use path parser; should get rid of allocations

        // From the given control path, try to determine the control layout being used.
        //
        // NOTE: This function will only use information available in the path itself or
        //       in layouts referenced by the path. It will not look at actual devices
        //       in the system. This is to make the behavior predictable and not dependent
        //       on whether you currently have the right device connected or not.
        // NOTE: Allocates!
        public static string TryGetControlLayout(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            var pathLength = path.Length;

            var indexOfLastSlash = path.LastIndexOf('/');

            if (indexOfLastSlash == -1 || indexOfLastSlash == 0)
            {
                // If there's no '/' at all in the path, it surely does not mention
                // a control. Same if the '/' is the first thing in the path.
                return(null);
            }

            // Simplest case where control layout is mentioned explicitly with '<..>'.
            // Note this will only catch if the control is *only* referenced by layout and not by anything else
            // in addition (like usage or name).
            if (pathLength > indexOfLastSlash + 2 && path[indexOfLastSlash + 1] == '<' && path[pathLength - 1] == '>')
            {
                var layoutNameStart  = indexOfLastSlash + 2;
                var layoutNameLength = pathLength - layoutNameStart - 1;
                return(path.Substring(layoutNameStart, layoutNameLength));
            }

            // Have to actually look at the path in detail.
            var parser = new PathParser(path);

            if (!parser.MoveToNextComponent())
            {
                return(null);
            }

            if (parser.current.isWildcard)
            {
                throw new NotImplementedException();
            }

            if (parser.current.layout.length == 0)
            {
                return(null);
            }

            var deviceLayoutName = parser.current.layout.ToString();

            if (!parser.MoveToNextComponent())
            {
                return(null); // No control component.
            }
            if (parser.current.isWildcard)
            {
                return(Wildcard);
            }

            return(FindControlLayoutRecursive(ref parser, deviceLayoutName));
        }
예제 #2
0
        /// <summary>
        /// From the given control path, try to determine the device layout being used.
        /// </summary>
        /// <remarks>
        /// This function will only use information available in the path itself or
        /// in layouts referenced by the path. It will not look at actual devices
        /// in the system. This is to make the behavior predictable and not dependent
        /// on whether you currently have the right device connected or not.
        /// </remarks>
        /// <param name="path">A control path (like "/&lt;gamepad&gt;/leftStick")</param>
        /// <returns>The name of the device layout used by the given control path or null
        /// if the path does not specify a device layout or does so in a way that is not
        /// supported by the function.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="path"/> is null</exception>
        /// <example>
        /// <code>
        /// InputControlPath.TryGetDeviceLayout("/&lt;gamepad&gt;/leftStick"); // Returns "gamepad".
        /// InputControlPath.TryGetDeviceLayout("/*/leftStick"); // Returns "*".
        /// InputControlPath.TryGetDeviceLayout("/gamepad/leftStick"); // Returns null. "gamepad" is a device name here.
        /// </code>
        /// </example>
        public static string TryGetDeviceLayout(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var parser = new PathParser(path);

            if (!parser.MoveToNextComponent())
            {
                return(null);
            }

            if (parser.current.layout.length > 0)
            {
                return(parser.current.layout.ToString());
            }

            if (parser.current.isWildcard)
            {
                return(Wildcard);
            }

            return(null);
        }
예제 #3
0
        /// <summary>
        // From the given control path, try to determine the device template being used.
        /// </summary>
        /// <remarks>
        /// This function will only use information available in the path itself or
        /// in templates referenced by the path. It will not look at actual devices
        /// in the system. This is to make the behavior predictable and not dependent
        /// on whether you currently have the right device connected or not.
        ///
        /// Note that this function allocates and causes GC.
        /// </remarks>
        /// <param name="path">A control path (like "/<gamepad>/leftStick")</param>
        /// <returns>The name of the device template used by the given control path or null
        /// if the path does not specify a device template or does so in a way that is not
        /// supported by the function.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="path"/> is null</exception>
        /// <example>
        /// <code>
        /// InputControlPath.TryGetDeviceTemplate("/<gamepad>/leftStick"); // Returns "gamepad".
        /// InputControlPath.TryGetDeviceTemplate("/*/leftStick"); // Returns "*".
        /// InputControlPath.TryGetDeviceTemplate("/gamepad/leftStick"); // Returns null. "gamepad" is a device name here.
        /// </code>
        /// </example>
        public static string TryGetDeviceTemplate(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }

            var parser = new PathParser(path);

            if (!parser.MoveToNextComponent())
            {
                return(null);
            }

            if (parser.current.template.length > 0)
            {
                return(parser.current.template.ToString());
            }

            if (parser.current.isWildcard)
            {
                return(kWildcard);
            }

            return(null);
        }
예제 #4
0
        /// <summary>
        /// Create a human readable string from the given control path.
        /// </summary>
        /// <param name="path">A control path such as "&lt;XRController>{LeftHand}/position".</param>
        /// <returns>A string such as "leftStick/x [Gamepad]".</returns>
        public static string ToHumanReadableString(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                return(string.Empty);
            }

            var buffer = new StringBuilder();
            var parser = new PathParser(path);

            ////REVIEW: ideally, we'd use display names of controls rather than the control paths directly from the path

            // First level is taken to be device.
            if (parser.MoveToNextComponent())
            {
                var device = parser.current.ToHumanReadableString();

                // Any additional levels (if present) are taken to form a control path on the device.
                var isFirstControlLevel = true;
                while (parser.MoveToNextComponent())
                {
                    if (!isFirstControlLevel)
                    {
                        buffer.Append('/');
                    }

                    buffer.Append(parser.current.ToHumanReadableString());
                    isFirstControlLevel = false;
                }

                if (!string.IsNullOrEmpty(device))
                {
                    buffer.Append(" [");
                    buffer.Append(device);
                    buffer.Append(']');
                }
            }

            // If we didn't manage to figure out a display name, default to displaying
            // the path as is.
            if (buffer.Length == 0)
            {
                return(path);
            }

            return(buffer.ToString());
        }
예제 #5
0
        private static bool MatchesRecursive(ref PathParser parser, InputControl currentControl)
        {
            // Recurse into parent before looking at the current control. This
            // will advance the parser to where our control is in the path.
            var parent = currentControl.parent;

            if (parent != null && !MatchesRecursive(ref parser, parent))
            {
                return(false);
            }

            // Fail if there's no more path left.
            if (!parser.MoveToNextComponent())
            {
                return(false);
            }

            // Match current path component against current control.
            return(parser.current.Matches(currentControl));
        }
예제 #6
0
        public static string[] TryGetDeviceUsages(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var parser = new PathParser(path);

            if (!parser.MoveToNextComponent())
            {
                return(null);
            }

            if (parser.current.usages != null && parser.current.usages.Length > 0)
            {
                return(Array.ConvertAll <Substring, string>(parser.current.usages, i => { return i.ToString(); }));
            }

            return(null);
        }
예제 #7
0
        /// <summary>
        /// Create a human readable string from the given control path.
        /// </summary>
        /// <param name="path">A control path such as "&lt;XRController>{LeftHand}/position".</param>
        /// <returns>A string such as "Gamepad leftStick/x".</returns>
        public static string ToHumanReadableString(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                return(string.Empty);
            }

            var result = string.Empty;
            var parser = new PathParser(path);

            ////REVIEW: ideally, we'd use display names of controls rather than the control paths directly from the path

            // First level is taken to be device.
            if (parser.MoveToNextComponent())
            {
                // If all we have is a usage, create a simple string with just that.
                if (parser.current.isWildcard && parser.current.layout.isEmpty && parser.current.usage.isEmpty)
                {
                    var savedParser = parser;
                    if (parser.MoveToNextComponent() && !parser.current.usage.isEmpty && parser.current.name.isEmpty &&
                        parser.current.layout.isEmpty)
                    {
                        var usage = parser.current.usage.ToString();
                        if (!parser.MoveToNextComponent())
                        {
                            return(usage);
                        }
                    }

                    // Reset.
                    parser = savedParser;
                }

                result += parser.current.ToHumanReadableString();

                // Any additional levels (if present) are taken to form a control path on the device.
                var isFirstControlLevel = true;
                while (parser.MoveToNextComponent())
                {
                    if (!isFirstControlLevel)
                    {
                        result += '/';
                    }
                    else
                    {
                        result += ' ';
                    }
                    result += parser.current.ToHumanReadableString();
                    isFirstControlLevel = false;
                }
            }

            // If we didn't manage to figure out a display name, default to displaying
            // the path as is.
            if (string.IsNullOrEmpty(result))
            {
                return(path);
            }

            return(result);
        }