internal static string ReadConsole(SafeFileHandle handle, string initialContent, int charsToRead, int?controlCharacter)
        {
            dotCmd.Native.ConsoleHostNativeMethods.CONSOLE_READCONSOLE_CONTROL readControl = new dotCmd.Native.ConsoleHostNativeMethods.CONSOLE_READCONSOLE_CONTROL();

            readControl.length = (uint)Marshal.SizeOf(readControl);

            if (initialContent != null)
            {
                readControl.initialChars = (uint)initialContent.Length;
            }

            readControl.controlKeyState = 0;

            //Magic VOODO starts here.
            //I've found almost no documentation how to set this mask to a given key
            //from what I know it only supports control characters \n \b \t etc.
            if (controlCharacter.HasValue)
            {
                readControl.ctrlWakeupMask = (uint)(1 << controlCharacter.Value);
            }

            StringBuilder buffer    = new StringBuilder(initialContent, charsToRead);
            uint          charsRead = 0;

            bool result = ConsoleHostNativeMethods.ReadConsole(handle.DangerousGetHandle(), buffer, (uint)charsToRead, out charsRead, ref readControl);

            if (result == false)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot read from the input buffer", err);
            }

            return(buffer.ToString(0, (int)charsRead));
        }
        internal static void SetConsoleCursorPosition(SafeFileHandle handle, dotCmd.Native.ConsoleHostNativeMethods.COORD cursorPosition)
        {
            bool result = ConsoleHostNativeMethods.SetConsoleCursorPosition(handle.DangerousGetHandle(), cursorPosition);

            if (result == false)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot set the curor position", err);
            }
        }
        internal static dotCmd.Native.ConsoleHostNativeMethods.INPUT_RECORD[] ReadConsoleKeys(SafeFileHandle handle, int charsToRead, out uint recordsRead)
        {
            dotCmd.Native.ConsoleHostNativeMethods.INPUT_RECORD[] inputRecords = new dotCmd.Native.ConsoleHostNativeMethods.INPUT_RECORD[charsToRead];

            bool result = ConsoleHostNativeMethods.ReadConsoleInput(handle.DangerousGetHandle(), inputRecords, (uint)inputRecords.Length, out recordsRead);

            if (result == false)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot read key(s) from the input buffer", err);
            }

            return(inputRecords);
        }
        internal static dotCmd.Native.ConsoleHostNativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX SetConsoleScreenBufferInfoExtended(
            SafeFileHandle handle,
            ConsoleHostNativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX info)
        {
            bool result = ConsoleHostNativeMethods.SetConsoleScreenBufferInfoEx(handle.DangerousGetHandle(), ref info);

            if (result == false)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot set output buffer info", err);
            }

            return(info);
        }
        internal static dotCmd.Native.ConsoleHostNativeMethods.CONSOLE_SCREEN_BUFFER_INFO GetConsoleScreenBufferInfo(
            SafeFileHandle handle)
        {
            ConsoleHostNativeMethods.CONSOLE_SCREEN_BUFFER_INFO info = new ConsoleHostNativeMethods.CONSOLE_SCREEN_BUFFER_INFO();
            bool result = ConsoleHostNativeMethods.GetConsoleScreenBufferInfo(handle.DangerousGetHandle(), out info);

            if (result == false)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot get output buffer info", err);
            }

            return(info);
        }
        internal static dotCmd.Native.ConsoleHostNativeMethods.CHAR_INFO[] ReadConsoleOutput(
            SafeFileHandle handle,
            dotCmd.Native.ConsoleHostNativeMethods.CHAR_INFO[] buffer,
            dotCmd.Native.ConsoleHostNativeMethods.COORD bufferSize,
            dotCmd.Native.ConsoleHostNativeMethods.COORD bufferCoord,
            ref dotCmd.Native.ConsoleHostNativeMethods.SMALL_RECT readRegion)
        {
            bool result = ConsoleHostNativeMethods.ReadConsoleOutput(handle.DangerousGetHandle(), buffer, bufferSize, bufferCoord, ref readRegion);

            if (result == false)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot read from the output buffer", err);
            }

            return(buffer);
        }
        internal static SafeFileHandle CreateInputBuffer()
        {
            //We dont use GetStdHandle since it might return a redirected handle, so use the bare bones function.

            var handle = ConsoleHostNativeMethods.CreateFile(
                "CONIN$",
                (UInt32)(ConsoleHostNativeMethods.DesiredAccess.GenericRead | ConsoleHostNativeMethods.DesiredAccess.GenericWrite),
                (UInt32)ConsoleHostNativeMethods.ShareMode.ShareWrite,
                (IntPtr)0,
                (UInt32)ConsoleHostNativeMethods.CreationDisposition.OpenExisting,
                0,
                (IntPtr)0);

            if (handle.IsInvalid)
            {
                int err = Marshal.GetLastWin32Error();
                throw CreateException("Cannot get the input buffer", err);
            }

            return(handle);
        }