#nullable enable using System.Text.RegularExpressions; namespace Terminal.Gui.Drivers; /// /// Detects ansi escape sequences in strings that have been read from /// the terminal (see ). /// Handles CSI key parsing such as \x1b[3;5~ (Delete with Ctrl) /// public class CsiKeyPattern : AnsiKeyboardParserPattern { private readonly Regex _pattern = new (@"^\u001b\[(\d+)(?:;(\d+))?~$"); private readonly Dictionary _keyCodeMap = new () { { 1, Key.Home }, // Home (modern variant) { 4, Key.End }, // End (modern variant) { 5, Key.PageUp }, { 6, Key.PageDown }, { 2, Key.InsertChar }, { 3, Key.Delete }, { 11, Key.F1 }, { 12, Key.F2 }, { 13, Key.F3 }, { 14, Key.F4 }, { 15, Key.F5 }, { 17, Key.F6 }, { 18, Key.F7 }, { 19, Key.F8 }, { 20, Key.F9 }, { 21, Key.F10 }, { 23, Key.F11 }, { 24, Key.F12 } }; /// public override bool IsMatch (string? input) { return _pattern.IsMatch (input!); } /// protected override Key? GetKeyImpl (string? input) { Match match = _pattern.Match (input!); if (!match.Success) { return null; } // Group 1: Key code (e.g. 3, 17, etc.) // Group 2: Optional modifier code (e.g. 2 = Shift, 5 = Ctrl) if (!int.TryParse (match.Groups [1].Value, out int keyCode)) { return null; } if (!_keyCodeMap.TryGetValue (keyCode, out Key? key)) { return null; } // If there's no modifier, just return the key. if (!int.TryParse (match.Groups [2].Value, out int modifier)) { return key; } key = modifier switch { 2 => key.WithShift, 3 => key.WithAlt, 4 => key.WithAlt.WithShift, 5 => key.WithCtrl, 6 => key.WithCtrl.WithShift, 7 => key.WithCtrl.WithAlt, 8 => key.WithCtrl.WithAlt.WithShift, _ => key }; return key; } }