#nullable enable using System.Text.RegularExpressions; namespace Terminal.Gui; /// /// Detects ansi escape sequences in strings that have been read from /// the terminal (see ). This pattern /// handles keys that begin Esc[ e.g. Esc[A - cursor up /// public class CsiKeyPattern : AnsiKeyboardParserPattern { private readonly Dictionary _terminators = new() { { "A", Key.CursorUp }, { "B", Key.CursorDown }, { "C", Key.CursorRight }, { "D", Key.CursorLeft }, { "H", Key.Home }, // Home (older variant) { "F", Key.End }, // End (older variant) { "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 } }; private readonly Regex _pattern; /// public override bool IsMatch (string? input) { return _pattern.IsMatch (input!); } /// /// Creates a new instance of the class. /// public CsiKeyPattern () { var terms = new string (_terminators.Select (k => k.Key [0]).Where (k => !char.IsDigit (k)).ToArray ()); _pattern = new (@$"^\u001b\[(1;(\d+))?([{terms}]|\d+~)$"); } /// /// Called by the base class to determine the key that matches the input. /// /// /// protected override Key? GetKeyImpl (string? input) { Match match = _pattern.Match (input!); if (!match.Success) { return null; } string terminator = match.Groups [3].Value; string modifierGroup = match.Groups [2].Value; Key? key = _terminators.GetValueOrDefault (terminator); if (key is {} && int.TryParse (modifierGroup, out int modifier)) { 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; } }