コード例 #1
0
        public static bool Ends(this ITokenStream stream, string type, ILogger logger, out Token[] row, out string token0)
        {
            row = stream.PeekNonEmpty();
            if (row == null)
            {
                token0 = null;
                return(true);
            }

            token0 = row[0].Value.ToLower();
            if (token0 == "end")
            {
                if (row.Length > 1)
                {
                    if (!string.Equals(row[1].Value, type, StringComparison.OrdinalIgnoreCase))
                    {
                        logger?.WriteLine($"Warning: Expected 'end {type}' at {stream.Path}:{stream.Line}.");
                    }
                }

                stream.Move();
                return(true);
            }

            return(false);
        }
コード例 #2
0
        public static bool Starts(this ITokenStream stream, string type, ILogger logger, out string name)
        {
            var row = stream.PeekNonEmpty();

            if (row == null)
            {
                name = null;
                return(false);
            }

            if (string.Equals(row[0].Value, type, StringComparison.OrdinalIgnoreCase))
            {
                if (row.Length > 1)
                {
                    name = row[1].Value;
                }
                else
                {
                    name = null;
                    logger?.WriteLine($"Warning: No item name at {stream.Path}:{stream.Line}. Items without a name may get ignored.");
                }

                stream.Move();
                return(true);
            }

            name = null;
            return(false);
        }
コード例 #3
0
ファイル: Parser.cs プロジェクト: edongashi/gamepad-mapper
        public static HelpConfiguration ParseHelp(ITokenStream stream, ILogger logger, string suffix = "")
        {
            var key = "help" + suffix;

            if (!stream.Starts(key))
            {
                return(null);
            }

            string text           = null;
            var    inputHelpTexts = new List <InputHelpText>();

            while (true)
            {
                if (stream.Ends(key, logger, out var row, out var token0))
                {
                    break;
                }

                if (row.Length < 3 || row[1].Value != "=")
                {
                    logger?.WriteLine($"Error: Malformed assignment at {stream.Path}:{stream.Line}.");
                    stream.Move();
                    continue;
                }

                var rest = string.Join(" ", row.Skip(2));
                if (token0 == "text")
                {
                    text = rest;
                }
                else if (Enum.TryParse(token0, true, out HelpKey helpKey))
                {
                    inputHelpTexts.Add(new InputHelpText(helpKey, rest));
                }
                else
                {
                    logger?.WriteLine($"Warning: Invalid symbol '{token0}' at {stream.Path}:{stream.Line}.");
                }

                stream.Move();
            }

            return(new HelpConfiguration(text, inputHelpTexts));
        }
コード例 #4
0
        public static bool Starts(this ITokenStream stream, string type)
        {
            var row = stream.PeekNonEmpty();

            if (row == null)
            {
                return(false);
            }

            if (string.Equals(row[0].Value, type, StringComparison.OrdinalIgnoreCase))
            {
                stream.Move();
                return(true);
            }

            return(false);
        }
コード例 #5
0
        public static Token[] PeekNonEmpty(this ITokenStream stream)
        {
            while (true)
            {
                var tokens = stream.Peek();
                if (tokens == null)
                {
                    return(null);
                }

                if (tokens.Length > 0)
                {
                    return(tokens);
                }

                stream.Move();
            }
        }
コード例 #6
0
ファイル: Parser.cs プロジェクト: edongashi/gamepad-mapper
        public static ProfileConfiguration ParseProfile(ITokenStream stream, ILogger logger)
        {
            if (!stream.Starts("profile", logger, out var name))
            {
                return(null);
            }

            var bindings = new List <InputBinding>();

            while (true)
            {
                if (stream.Ends("profile", logger, out var row, out var token0))
                {
                    break;
                }

                if (row.Length < 4 || row[1].Value != "=")
                {
                    logger?.WriteLine($"Error: Malformed key binding at {stream.Path}:{stream.Line}.");
                    stream.Move();
                    continue;
                }

                if (token0 == "ls" || token0 == "rs")
                {
                    if (!string.Equals(row[2].Value, "map"))
                    {
                        logger?.WriteLine($"Error: Unknown analog mapping at {stream.Path}:{stream.Line}.");
                        stream.Move();
                        continue;
                    }

                    var stick = token0 == "ls" ? ThumbStick.Left : ThumbStick.Right;
                    switch (row[3].Value.ToLower())
                    {
                    case "mouse":
                        bindings.Add(new MouseMapping(stick));
                        break;

                    case "scroll":
                        bindings.Add(new ScrollMapping(stick));
                        break;

                    case "radial_menu":
                        bindings.Add(new RadialMenuMapping(stick));
                        break;

                    default:
                        logger?.WriteLine($"Error: Unknown analog mapping at {stream.Path}:{stream.Line}.");
                        break;
                    }

                    stream.Move();
                    continue;
                }

                if (!Enum.TryParse(token0, true, out InputKey inputKey))
                {
                    logger?.WriteLine($"Error: Unknown key '{token0}' at {stream.Path}:{stream.Line}.");
                }

                int end;
                switch (row[2].Value.ToLower())
                {
                case "map":
                    if (string.Equals(row[3].Value, "mod", StringComparison.OrdinalIgnoreCase))
                    {
                        bindings.Add(new ModMapping(inputKey));
                        break;
                    }

                    var keys = ParseKeyCodes(row, 3, out end);
                    if (keys == null)
                    {
                        logger?.WriteLine($"Error: Invalid key code(s) at {stream.Path}:{stream.Line}.");
                    }
                    else
                    {
                        if (end < row.Length)
                        {
                            logger?.WriteLine($"Warning: Ignored unknown symbols at {stream.Path}:{stream.Line}.");
                        }

                        bindings.Add(new KeyMapping(inputKey, keys));
                    }

                    break;

                case "press":
                    var action = ParseAction(row, 3, out end);
                    if (action == null)
                    {
                        logger?.WriteLine($"Error: Invalid action at {stream.Path}:{stream.Line}.");
                        break;
                    }

                    if (end < row.Length)
                    {
                        var nextToken = row[end];
                        if (string.Equals(nextToken.Value, "repeat", StringComparison.OrdinalIgnoreCase))
                        {
                            bindings.Add(new PressBinding(inputKey, action, true));
                        }
                        else if (string.Equals(nextToken.Value, "hold", StringComparison.OrdinalIgnoreCase))
                        {
                            end++;
                            if (end >= row.Length)
                            {
                                logger?.WriteLine($"Error: Expected action after 'hold' at {stream.Path}:{stream.Line}.");
                                break;
                            }

                            var holdAction = ParseAction(row, end, out end);
                            if (holdAction == null)
                            {
                                logger?.WriteLine($"Error: Invalid action at {stream.Path}:{stream.Line}.");
                                break;
                            }

                            if (end < row.Length)
                            {
                                logger?.WriteLine($"Warning: Ignored unknown symbols at {stream.Path}:{stream.Line}.");
                            }

                            bindings.Add(new PressHoldBinding(inputKey, action, holdAction));
                        }
                        else
                        {
                            logger?.WriteLine($"Error: Invalid symbol '{nextToken}' at {stream.Path}:{stream.Line}.");
                        }
                    }
                    else
                    {
                        bindings.Add(new PressBinding(inputKey, action, false));
                    }

                    break;

                default:
                    logger?.WriteLine($"Error: Unknown symbol '{row[2].Value}' at {stream.Path}:{stream.Line}.");
                    break;
                }

                stream.Move();
            }

            if (name == null)
            {
                return(null);
            }

            return(new ProfileConfiguration(name, bindings));
        }
コード例 #7
0
ファイル: Parser.cs プロジェクト: edongashi/gamepad-mapper
        public static RootConfiguration Parse(ITokenStream stream, ILogger logger)
        {
            var config = new RootConfiguration();

            while (true)
            {
                var tokens = stream.PeekNonEmpty();
                if (tokens == null)
                {
                    break;
                }

                var token0 = tokens[0].Value.ToLower();
                var token1 = tokens.Length > 1 ? tokens[1].Value : null;
                var token2 = tokens.Length > 2 ? tokens[2].Value : null;
                switch (token0)
                {
                case "bind":
                    var binding = ParseCommandBinding(stream, logger);
                    if (binding != null)
                    {
                        config.Bindings.Add(binding);
                    }

                    stream.Move();
                    break;

                case "profile":
                    var profile = ParseProfile(stream, logger);
                    if (profile != null)
                    {
                        config.Profiles.Add(profile);
                    }

                    break;

                case "menu":
                    var menu = ParseMenuConfiguration(stream, logger);
                    if (menu != null)
                    {
                        config.Menus.Add(menu);
                    }

                    break;

                default:
                    if (tokens.Length < 3 || token1 != "=")
                    {
                        logger?.WriteLine($"Error: Malformed line at {stream.Path}:{stream.Line}.");
                        stream.Move();
                        break;
                    }

                    if (token0 == "fps")
                    {
                        if (InvariantDouble.TryParse(token2, out var fps) && fps >= 1d && fps <= 300d)
                        {
                            config.Fps = fps;
                        }
                        else
                        {
                            logger?.WriteLine(
                                $"Warning: Invalid FPS value '{token2}' at '{token0}' at {stream.Path}:{stream.Line}.");
                        }
                    }
                    else if (config.Descriptors.TryGetValue(token0, out var descriptor))
                    {
                        if (!descriptor.isValidValue(token2))
                        {
                            logger?.WriteLine(
                                $"Warning: Value '{token2}' is invalid or out of range for key '{token0}' at {stream.Path}:{stream.Line}. Default value is assigned.");
                        }

                        descriptor.SetValue(token2);
                    }
                    else
                    {
                        logger?.WriteLine($"Error: Unknown key '{token0}' at {stream.Path}:{stream.Line}.");
                    }

                    stream.Move();
                    break;
                }
            }

            config.InitializeProfiles();
            return(config);
        }
コード例 #8
0
ファイル: Parser.cs プロジェクト: edongashi/gamepad-mapper
        public static MenuItemConfiguration ParseMenuItem(ITokenStream stream, ILogger logger)
        {
            if (!stream.Starts("item"))
            {
                return(null);
            }

            HelpConfiguration help  = null;
            HelpConfiguration help2 = null;
            var          bindings   = new List <CommandBinding>();
            string       name       = null;
            string       text       = null;
            List <Token> icon       = null;

            while (true)
            {
                if (stream.Ends("item", logger, out var row, out var token0))
                {
                    break;
                }

                if (token0 == "help")
                {
                    var h = ParseHelp(stream, logger);
                    if (h != null)
                    {
                        help = h;
                    }

                    continue;
                }

                if (token0 == "help2")
                {
                    var h2 = ParseHelp(stream, logger, "2");
                    if (h2 != null)
                    {
                        h2.Orientation = Orientation.Horizontal;
                        help2          = h2;
                    }

                    continue;
                }

                if (token0 == "bind")
                {
                    var binding = ParseCommandBinding(stream, logger);
                    if (binding != null)
                    {
                        bindings.Add(binding);
                    }

                    stream.Move();
                    continue;
                }

                if (row.Length < 3 || row[1].Value != "=")
                {
                    logger?.WriteLine($"Error: Malformed assignment at {stream.Path}:{stream.Line}.");
                    stream.Move();
                    continue;
                }

                var rest = string.Join(" ", row.Skip(2));
                switch (token0)
                {
                case "text":
                    text = rest;
                    break;

                case "icon":
                    icon = row.Skip(2).ToList();
                    break;

                case "name":
                    name = rest;
                    break;

                default:
                    logger?.UnexpectedLine(stream);
                    break;
                }

                stream.Move();
            }

            return(new MenuItemConfiguration(name, icon, text, bindings, help, help2));
        }
コード例 #9
0
ファイル: Parser.cs プロジェクト: edongashi/gamepad-mapper
        public static PageConfiguration ParsePage(ITokenStream stream, ILogger logger)
        {
            if (!stream.Starts("page"))
            {
                return(null);
            }

            HelpConfiguration help  = null;
            HelpConfiguration help2 = null;
            var bindings            = new List <CommandBinding>();
            var items = new List <MenuItemConfiguration>();

            while (true)
            {
                if (stream.Ends("page", logger, out var row, out var token0))
                {
                    break;
                }

                switch (token0)
                {
                case "help":
                    var h = ParseHelp(stream, logger);
                    if (h != null)
                    {
                        help = h;
                    }

                    continue;

                case "bind":
                    var binding = ParseCommandBinding(stream, logger);
                    if (binding != null)
                    {
                        bindings.Add(binding);
                    }

                    stream.Move();
                    continue;

                case "help2":
                    var h2 = ParseHelp(stream, logger, "2");
                    if (h2 != null)
                    {
                        h2.Orientation = Orientation.Horizontal;
                        help2          = h2;
                    }

                    continue;

                case "item":
                    var item = ParseMenuItem(stream, logger);
                    if (item != null)
                    {
                        items.Add(item);
                    }

                    continue;

                default:
                    logger?.UnexpectedLine(stream);
                    stream.Move();
                    continue;
                }
            }

            return(new PageConfiguration(help, help2, bindings, items));
        }
コード例 #10
0
ファイル: Parser.cs プロジェクト: edongashi/gamepad-mapper
        public static MenuConfiguration ParseMenuConfiguration(ITokenStream stream, ILogger logger)
        {
            if (!stream.Starts("menu", logger, out var name))
            {
                return(null);
            }

            HelpConfiguration help  = null;
            HelpConfiguration help2 = null;
            var bindings            = new List <CommandBinding>();
            var pages = new List <PageConfiguration>();

            while (true)
            {
                if (stream.Ends("menu", logger, out var row, out var token0))
                {
                    break;
                }

                switch (token0)
                {
                case "bind":
                    var binding = ParseCommandBinding(stream, logger);
                    if (binding != null)
                    {
                        bindings.Add(binding);
                    }

                    stream.Move();
                    continue;

                case "help":
                    var h = ParseHelp(stream, logger);
                    if (h != null)
                    {
                        help = h;
                    }

                    continue;

                case "help2":
                    var h2 = ParseHelp(stream, logger, "2");
                    if (h2 != null)
                    {
                        h2.Orientation = Orientation.Horizontal;
                        help2          = h2;
                    }

                    continue;

                case "page":
                    var page = ParsePage(stream, logger);
                    if (page != null)
                    {
                        pages.Add(page);
                    }

                    continue;

                default:
                    logger?.UnexpectedLine(stream);
                    stream.Move();
                    continue;
                }
            }

            return(name != null ? new MenuConfiguration(name, help, help2, bindings, pages) : null);
        }