CsiKeyPattern.cs 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #nullable enable
  2. using System.Text.RegularExpressions;
  3. namespace Terminal.Gui;
  4. /// <summary>
  5. /// Detects ansi escape sequences in strings that have been read from
  6. /// the terminal (see <see cref="IAnsiResponseParser"/>). This pattern
  7. /// handles keys that begin <c>Esc[</c> e.g. <c>Esc[A</c> - cursor up
  8. /// </summary>
  9. public class CsiKeyPattern : AnsiKeyboardParserPattern
  10. {
  11. private readonly Dictionary<string, Key> _terminators = new()
  12. {
  13. { "A", Key.CursorUp },
  14. { "B", Key.CursorDown },
  15. { "C", Key.CursorRight },
  16. { "D", Key.CursorLeft },
  17. { "H", Key.Home }, // Home (older variant)
  18. { "F", Key.End }, // End (older variant)
  19. { "1~", Key.Home }, // Home (modern variant)
  20. { "4~", Key.End }, // End (modern variant)
  21. { "5~", Key.PageUp },
  22. { "6~", Key.PageDown },
  23. { "2~", Key.InsertChar },
  24. { "3~", Key.Delete },
  25. { "11~", Key.F1 },
  26. { "12~", Key.F2 },
  27. { "13~", Key.F3 },
  28. { "14~", Key.F4 },
  29. { "15~", Key.F5 },
  30. { "17~", Key.F6 },
  31. { "18~", Key.F7 },
  32. { "19~", Key.F8 },
  33. { "20~", Key.F9 },
  34. { "21~", Key.F10 },
  35. { "23~", Key.F11 },
  36. { "24~", Key.F12 }
  37. };
  38. private readonly Regex _pattern;
  39. /// <inheritdoc/>
  40. public override bool IsMatch (string? input) { return _pattern.IsMatch (input!); }
  41. /// <summary>
  42. /// Creates a new instance of the <see cref="CsiKeyPattern"/> class.
  43. /// </summary>
  44. public CsiKeyPattern ()
  45. {
  46. var terms = new string (_terminators.Select (k => k.Key [0]).Where (k => !char.IsDigit (k)).ToArray ());
  47. _pattern = new (@$"^\u001b\[(1;(\d+))?([{terms}]|\d+~)$");
  48. }
  49. /// <summary>
  50. /// Called by the base class to determine the key that matches the input.
  51. /// </summary>
  52. /// <param name="input"></param>
  53. /// <returns></returns>
  54. protected override Key? GetKeyImpl (string? input)
  55. {
  56. Match match = _pattern.Match (input!);
  57. if (!match.Success)
  58. {
  59. return null;
  60. }
  61. string terminator = match.Groups [3].Value;
  62. string modifierGroup = match.Groups [2].Value;
  63. Key? key = _terminators.GetValueOrDefault (terminator);
  64. if (key is {} && int.TryParse (modifierGroup, out int modifier))
  65. {
  66. key = modifier switch
  67. {
  68. 2 => key.WithShift,
  69. 3 => key.WithAlt,
  70. 4 => key.WithAlt.WithShift,
  71. 5 => key.WithCtrl,
  72. 6 => key.WithCtrl.WithShift,
  73. 7 => key.WithCtrl.WithAlt,
  74. 8 => key.WithCtrl.WithAlt.WithShift,
  75. _ => key
  76. };
  77. }
  78. return key;
  79. }
  80. }