#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 navigation CSI key parsing such as \x1b[A (Cursor up)
/// and \x1b[1;5A (Cursor/Function with modifier(s))
///
public class CsiCursorPattern : AnsiKeyboardParserPattern
{
private readonly Regex _pattern = new (@"^\u001b\[(?:1;(\d+))?([A-DFHPQRS])$");
private readonly Dictionary _cursorMap = new ()
{
{ 'A', Key.CursorUp },
{ 'B', Key.CursorDown },
{ 'C', Key.CursorRight },
{ 'D', Key.CursorLeft },
{ 'H', Key.Home },
{ 'F', Key.End },
// F1–F4 as per xterm VT100-style CSI sequences
{ 'P', Key.F1 },
{ 'Q', Key.F2 },
{ 'R', Key.F3 },
{ 'S', Key.F4 }
};
///
public override bool IsMatch (string? input) { return _pattern.IsMatch (input!); }
///
/// 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 modifierGroup = match.Groups [1].Value;
char terminator = match.Groups [2].Value [0];
if (!_cursorMap.TryGetValue (terminator, out Key? key))
{
return null;
}
if (string.IsNullOrEmpty (modifierGroup))
{
return key;
}
if (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;
}
}