NetWinVTConsole.cs 3.7 KB

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