{"record":{"id":"deace22d604c440c","repo":"mgth/LittleBigMouse","slug":"a-delay-must-follow-a-key-command","errorCode":null,"errorMessage":"A delay must follow a KEY_ command.","messagePattern":"A delay must follow a KEY_ command\\.","errorType":"validation","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/RemoteMacro.cs","lineNumber":19,"sourceCode":"#nullable enable\n\nnamespace LittleBigMouse.Plugin.Vcp.Avalonia;\n\n/// <summary>Shared parser for Samsung and VIDAA remote-key macros.</summary>\npublic static class RemoteMacro\n{\n    public static IReadOnlyList<(string Key, TimeSpan DelayAfter)> Parse(string sequence)\n    {\n        var result = new List<(string Key, TimeSpan DelayAfter)>();\n        var tokens = sequence.Split(\n            [',', ';', '+', '\\n', '\\r'],\n            StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);\n\n        foreach (var token in tokens)\n        {\n            if (int.TryParse(token, out var milliseconds))\n            {\n                if (result.Count == 0) throw new FormatException(\"A delay must follow a KEY_ command.\");\n                if (milliseconds is < 0 or > 10000)\n                    throw new FormatException(\"Macro delays must be between 0 and 10000 ms.\");\n                result[^1] = (result[^1].Key, TimeSpan.FromMilliseconds(milliseconds));\n                continue;\n            }\n\n            var key = token.ToUpperInvariant();\n            if (!key.StartsWith(\"KEY_\", StringComparison.Ordinal) || key.Any(char.IsWhiteSpace))\n                throw new FormatException($\"Invalid remote key: {token}\");\n            result.Add((key, TimeSpan.FromMilliseconds(150)));\n        }\n\n        if (result.Count == 0) throw new FormatException(\"Enter at least one KEY_ command.\");\n        return result;\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/RemoteMacro.cs#L1-L36","documentation":"RemoteMacro.Parse tokenizes a macro string: KEY_ commands and integer delay tokens must alternate, with a delay always following a KEY_ command. A leading integer (or one after another delay) has no command to attach the duration to, so FormatException is thrown. Delays are also range-checked to 0–10000 ms.","triggerScenarios":"Calling RemoteMacro.Parse with a string whose first token is a bare number (e.g. \"500 KEY_OK\"), two consecutive delay numbers (\"KEY_OK 500 300\"), or whitespace-only/number-only input producing an empty command list before the number.","commonSituations":"Hand-edited macro strings with a stray leading delay; UI macro builder emitting a trailing/leading duration; copy-paste errors; user typing a delay where a KEY_ token was expected; localization stripping the KEY_ prefix.","solutions":["Ensure every macro starts with a KEY_ command and each numeric token immediately follows one (e.g. \"KEY_OK 500 KEY_DOWN\")","Remove stray leading or duplicated numeric tokens from the macro string","Validate the macro string in the UI before saving/calling Parse","If you need an initial delay, encode it as a command followed by the delay rather than a leading number"],"exampleFix":"// before\nvar macro = RemoteMacro.Parse(\"500 KEY_OK\", ...); // FormatException\n// after\nvar macro = RemoteMacro.Parse(\"KEY_OK 500\", ...);","handlingStrategy":"try-catch","validationCode":"static bool IsValidMacro(string s) =>\n    !string.IsNullOrWhiteSpace(s) &&\n    !int.TryParse(s.Trim().Split(' ', ',')[0], out _); // first token must be a KEY_ command","typeGuard":"bool StartsWithKeyCommand(string macro) =>\n    macro?.TrimStart().StartsWith(\"KEY_\", StringComparison.Ordinal) == true;","tryCatchPattern":"try\n{\n    var macro = RemoteMacro.Parse(input, keyFactory);\n}\ncatch (FormatException ex)\n{\n    ShowMacroSyntaxError(ex.Message); // \"A delay must follow a KEY_ command\" / range errors\n}","preventionTips":["Validate macro strings in the UI editor before persisting","Enforce KEY_ command + optional delay alternation at input time","Clamp delay tokens to 0–10000 ms in the editor","Trim and normalize whitespace/commas before calling Parse"],"tags":["csharp","parsing","format-exception","remote-macro"],"backgroundTag":"invalid-argument-format","analyzedSha":"7a42f01d47d99d223b8ee33ba4019af82adf1c48","analyzedAt":"2026-09-16T00:35:00.514Z","contentChangedAt":"2026-09-16T00:35:00.514Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}