NetWinVTConsole.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #nullable enable
  2. using System.Runtime.InteropServices;
  3. namespace Terminal.Gui.Drivers;
  4. internal class NetWinVTConsole
  5. {
  6. // Input modes.
  7. private const uint ENABLE_PROCESSED_INPUT = 1;
  8. private const uint ENABLE_LINE_INPUT = 2;
  9. private const uint ENABLE_ECHO_INPUT = 4;
  10. private const uint ENABLE_WINDOW_INPUT = 8;
  11. private const uint ENABLE_MOUSE_INPUT = 16;
  12. private const uint ENABLE_INSERT_MODE = 32;
  13. private const uint ENABLE_QUICK_EDIT_MODE = 64;
  14. private const uint ENABLE_EXTENDED_FLAGS = 128;
  15. private const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 512;
  16. // Output modes.
  17. private const uint ENABLE_PROCESSED_OUTPUT = 1;
  18. private const uint ENABLE_WRAP_AT_EOL_OUTPUT = 2;
  19. private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;
  20. private const uint DISABLE_NEWLINE_AUTO_RETURN = 8;
  21. private const uint ENABLE_LVB_GRID_WORLDWIDE = 10;
  22. // Standard handles.
  23. private const int STD_ERROR_HANDLE = -12;
  24. private const int STD_INPUT_HANDLE = -10;
  25. private const int STD_OUTPUT_HANDLE = -11;
  26. // Handles and original console modes.
  27. private readonly nint _inputHandle;
  28. private readonly uint _originalInputConsoleMode;
  29. private readonly uint _originalOutputConsoleMode;
  30. private readonly nint _outputHandle;
  31. public NetWinVTConsole ()
  32. {
  33. _inputHandle = GetStdHandle (STD_INPUT_HANDLE);
  34. if (!GetConsoleMode (_inputHandle, out uint mode))
  35. {
  36. throw new ApplicationException ($"Failed to get input console mode, error code: {GetLastError ()}.");
  37. }
  38. _originalInputConsoleMode = mode;
  39. if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) == 0)
  40. {
  41. mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
  42. if (!SetConsoleMode (_inputHandle, mode))
  43. {
  44. throw new ApplicationException ($"Failed to set input console mode, error code: {GetLastError ()}.");
  45. }
  46. }
  47. _outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
  48. if (!GetConsoleMode (_outputHandle, out mode))
  49. {
  50. throw new ApplicationException ($"Failed to get output console mode, error code: {GetLastError ()}.");
  51. }
  52. _originalOutputConsoleMode = mode;
  53. if ((mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
  54. {
  55. mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
  56. if (!SetConsoleMode (_outputHandle, mode))
  57. {
  58. throw new ApplicationException ($"Failed to set output console mode, error code: {GetLastError ()}.");
  59. }
  60. }
  61. }
  62. public void Cleanup ()
  63. {
  64. if (!FlushConsoleInputBuffer (_inputHandle))
  65. {
  66. throw new ApplicationException ($"Failed to flush input buffer, error code: {GetLastError ()}.");
  67. }
  68. if (!SetConsoleMode (_inputHandle, _originalInputConsoleMode))
  69. {
  70. throw new ApplicationException ($"Failed to restore input console mode, error code: {GetLastError ()}.");
  71. }
  72. if (!SetConsoleMode (_outputHandle, _originalOutputConsoleMode))
  73. {
  74. throw new ApplicationException ($"Failed to restore output console mode, error code: {GetLastError ()}.");
  75. }
  76. }
  77. [DllImport ("kernel32.dll")]
  78. private static extern bool GetConsoleMode (nint hConsoleHandle, out uint lpMode);
  79. [DllImport ("kernel32.dll")]
  80. private static extern uint GetLastError ();
  81. [DllImport ("kernel32.dll", SetLastError = true)]
  82. private static extern nint GetStdHandle (int nStdHandle);
  83. [DllImport ("kernel32.dll")]
  84. private static extern bool SetConsoleMode (nint hConsoleHandle, uint dwMode);
  85. [DllImport ("kernel32.dll", SetLastError = true)]
  86. private static extern bool FlushConsoleInputBuffer (nint hConsoleInput);
  87. }