NetWinVTConsole.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #nullable enable
  2. using System.Runtime.InteropServices;
  3. namespace Terminal.Gui;
  4. internal class NetWinVTConsole
  5. {
  6. private const uint DISABLE_NEWLINE_AUTO_RETURN = 8;
  7. private const uint ENABLE_ECHO_INPUT = 4;
  8. private const uint ENABLE_EXTENDED_FLAGS = 128;
  9. private const uint ENABLE_INSERT_MODE = 32;
  10. private const uint ENABLE_LINE_INPUT = 2;
  11. private const uint ENABLE_LVB_GRID_WORLDWIDE = 10;
  12. private const uint ENABLE_MOUSE_INPUT = 16;
  13. // Input modes.
  14. private const uint ENABLE_PROCESSED_INPUT = 1;
  15. // Output modes.
  16. private const uint ENABLE_PROCESSED_OUTPUT = 1;
  17. private const uint ENABLE_QUICK_EDIT_MODE = 64;
  18. private const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 512;
  19. private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;
  20. private const uint ENABLE_WINDOW_INPUT = 8;
  21. private const uint ENABLE_WRAP_AT_EOL_OUTPUT = 2;
  22. private const int STD_ERROR_HANDLE = -12;
  23. private const int STD_INPUT_HANDLE = -10;
  24. private const int STD_OUTPUT_HANDLE = -11;
  25. private readonly nint _errorHandle;
  26. private readonly nint _inputHandle;
  27. private readonly uint _originalErrorConsoleMode;
  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) < ENABLE_VIRTUAL_TERMINAL_INPUT)
  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 | DISABLE_NEWLINE_AUTO_RETURN)) < DISABLE_NEWLINE_AUTO_RETURN)
  54. {
  55. mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
  56. if (!SetConsoleMode (_outputHandle, mode))
  57. {
  58. throw new ApplicationException ($"Failed to set output console mode, error code: {GetLastError ()}.");
  59. }
  60. }
  61. _errorHandle = GetStdHandle (STD_ERROR_HANDLE);
  62. if (!GetConsoleMode (_errorHandle, out mode))
  63. {
  64. throw new ApplicationException ($"Failed to get error console mode, error code: {GetLastError ()}.");
  65. }
  66. _originalErrorConsoleMode = mode;
  67. if ((mode & DISABLE_NEWLINE_AUTO_RETURN) < DISABLE_NEWLINE_AUTO_RETURN)
  68. {
  69. mode |= DISABLE_NEWLINE_AUTO_RETURN;
  70. if (!SetConsoleMode (_errorHandle, mode))
  71. {
  72. throw new ApplicationException ($"Failed to set error console mode, error code: {GetLastError ()}.");
  73. }
  74. }
  75. }
  76. public void Cleanup ()
  77. {
  78. if (!SetConsoleMode (_inputHandle, _originalInputConsoleMode))
  79. {
  80. throw new ApplicationException ($"Failed to restore input console mode, error code: {GetLastError ()}.");
  81. }
  82. if (!SetConsoleMode (_outputHandle, _originalOutputConsoleMode))
  83. {
  84. throw new ApplicationException ($"Failed to restore output console mode, error code: {GetLastError ()}.");
  85. }
  86. if (!SetConsoleMode (_errorHandle, _originalErrorConsoleMode))
  87. {
  88. throw new ApplicationException ($"Failed to restore error console mode, error code: {GetLastError ()}.");
  89. }
  90. }
  91. [DllImport ("kernel32.dll")]
  92. private static extern bool GetConsoleMode (nint hConsoleHandle, out uint lpMode);
  93. [DllImport ("kernel32.dll")]
  94. private static extern uint GetLastError ();
  95. [DllImport ("kernel32.dll", SetLastError = true)]
  96. private static extern nint GetStdHandle (int nStdHandle);
  97. [DllImport ("kernel32.dll")]
  98. private static extern bool SetConsoleMode (nint hConsoleHandle, uint dwMode);
  99. }