public static void WriteCharacterAt(int x, int y, char character, ConsoleColor foregroundColor, ConsoleColor backgroundColor = ConsoleColor.Black) { IntPtr consoleHandle = GetStdHandle(-11); if (consoleHandle == IntPtr.Zero) { return; } NativeMethods.COORD position = new NativeMethods.COORD((short)x, (short)y); uint length = 0; WriteConsoleOutputAttribute(consoleHandle, new ushort[] { NativeMethods.GetConsoleColor(foregroundColor, backgroundColor) }, 1, position, out length); WriteConsoleOutputCharacter(consoleHandle, character.ToString(), 1, position, out length); }
private static extern bool WriteConsoleOutputAttribute(IntPtr hConsoleOutput, ushort[] lpAttribute, uint nLength, NativeMethods.COORD dwWriteCoord, out uint lpNumberOfAttrsWritten);
/// <summary> /// Moves the cursor to the given coordinates within the virtual screen. /// </summary> /// <remarks> /// The upper-left corner of the virtual screen corresponds to (1, 1). /// /// GotoXY is window-relative. /// </remarks> /// <param name="column">The 1-based column to move to</param> /// <param name="row">The 1-based row to move to</param> public static void GotoXY(int column, int row) { lock (_Lock) { if ((column > 0) && (row > 0)) { int X = column - 1 + WindMinX; int Y = row - 1 + WindMinY; if ((X <= WindMaxX) && (Y <= WindMaxY)) { if (OSUtils.IsWindows) { NativeMethods.COORD CursorPosition = new NativeMethods.COORD(); CursorPosition.X = (short)X; CursorPosition.Y = (short)Y; NativeMethods.SetConsoleCursorPosition(_StdOutputHandle, CursorPosition); } else { try { Console.SetCursorPosition(X, Y); } catch (NotImplementedException) { // Can't do that } } } } } }
private static extern bool WriteConsoleOutputCharacter( IntPtr hConsoleOutput, string lpCharacter, uint nLength, NativeMethods.COORD dwWriteCoord, out uint lpNumberOfCharsWritten);
/// <summary> /// Retrieves the text attribute at the given X/Y coordinate. /// /// GetAttrAt is not window-relative. /// </summary> /// <param name="column">The 1-based column to look at</param> /// <param name="row">The 1-based row to look at</param> /// <returns>The text attribute at the given X/Y coordinate</returns> public static int GetAttrAt(int column, int row) { lock (_Lock) { if ((column <= _ScreenSize.X) && (row <= _ScreenSize.Y)) { if (OSUtils.IsWindows) { NativeMethods.COORD ReadCoord = new NativeMethods.COORD(); ReadCoord.X = (short)(column - 1); ReadCoord.Y = (short)(row - 1); ushort[] Attribute = new ushort[1]; uint NumberOfAttrsRead = 0; NativeMethods.ReadConsoleOutputAttribute(_StdOutputHandle, Attribute, 1, ReadCoord, out NumberOfAttrsRead); return Attribute[0]; } else { return LightGray; } } else { return LightGray; } } }
/// <summary> /// Retrieves the character at the given X/Y coordinate. /// /// GetCharAt is not window-relative. /// </summary> /// <param name="column">The 1-based column to look at</param> /// <param name="row">The 1-based row to look at</param> /// <returns>The character at the given X/Y coordinate</returns> public static char GetCharAt(int column, int row) { lock (_Lock) { if ((column <= _ScreenSize.X) && (row <= _ScreenSize.Y)) { if (OSUtils.IsWindows) { NativeMethods.COORD ReadCoord = new NativeMethods.COORD(); ReadCoord.X = (short)(column - 1); ReadCoord.Y = (short)(row - 1); StringBuilder Character = new StringBuilder(); uint NumberOfCharsRead = 0; NativeMethods.ReadConsoleOutputCharacter(_StdOutputHandle, Character, 1, ReadCoord, out NumberOfCharsRead); return Character[0]; } else { return ' '; } } else { return ' '; } } }
/// <summary> /// Writes a string of text at the desired X/Y coordinate with the given text attribute. /// /// FastWrite is not window-relative, and it does not wrap text that goes beyond the right edge of the screen. /// </summary> /// <param name="text">The text to write</param> /// <param name="column">The 1-based column to start the text</param> /// <param name="row">The 1-based row to start the text</param> /// <param name="attribute">The text attribute to colour the text</param> public static void FastWrite(string text, int column, int row, int attribute) { lock (_Lock) { if ((column <= _ScreenSize.X) && (row <= _ScreenSize.Y)) { if (OSUtils.IsWindows) { NativeMethods.CHAR_INFO[] Buffer = new NativeMethods.CHAR_INFO[text.Length]; for (int i = 0; i < text.Length; i++) { Buffer[i].Attributes = (ushort)attribute; Buffer[i].AsciiChar = text[i]; } NativeMethods.COORD BufferCoord = new NativeMethods.COORD(); BufferCoord.X = 0; BufferCoord.Y = 0; NativeMethods.COORD BufferSize = new NativeMethods.COORD(); BufferSize.X = (short)text.Length; BufferSize.Y = 1; NativeMethods.SMALL_RECT WriteRegion = new NativeMethods.SMALL_RECT(); WriteRegion.Bottom = (short)(row - 1); WriteRegion.Left = (short)(column - 1); WriteRegion.Right = (short)((column - 1) + text.Length); WriteRegion.Top = (short)(row - 1); NativeMethods.WriteConsoleOutput(_StdOutputHandle, Buffer, BufferSize, BufferCoord, ref WriteRegion); } else { try { int OldX = Console.CursorLeft; int OldY = Console.CursorTop; ConsoleColor OldFore = Console.ForegroundColor; ConsoleColor OldBack = Console.BackgroundColor; Console.SetCursorPosition(column - 1, row - 1); //Console.ForegroundColor = GetConsoleColour(attribute % 16); //Console.BackgroundColor = GetConsoleColour(attribute / 16); Console.Write(text); // TODO Keep text in buffer for SaveScreen() and RestoreScreen() Console.SetCursorPosition(OldX, OldY); Console.ForegroundColor = OldFore; Console.BackgroundColor = OldBack; } catch (NotImplementedException) { // Can't do that } } } } }
/// <summary> /// Scrolls the given window up the given number of lines (leaving blank lines at the bottom), filling the void with the given character with the given text attribute /// </summary> /// <param name="AX1">The 0-based left column of the window</param> /// <param name="AY1">The 0-based top row of the window</param> /// <param name="AX2">The 0-based right column of the window</param> /// <param name="AY2">The 0-based bottom row of the window</param> /// <param name="ALines">The number of lines to scroll</param> /// <param name="ACh">The character to fill the void with</param> /// <param name="AAttr">The text attribute to fill the void with</param> private static void ScrollUpCustom(int AX1, int AY1, int AX2, int AY2, int ALines, char ACh, int AAttr) { lock (_Lock) { if (OSUtils.IsWindows) { NativeMethods.SMALL_RECT ClipRectangle = new NativeMethods.SMALL_RECT(); ClipRectangle.Bottom = (short)AY2; ClipRectangle.Left = (short)AX1; ClipRectangle.Right = (short)AX2; ClipRectangle.Top = (short)AY1; NativeMethods.CHAR_INFO Fill = new NativeMethods.CHAR_INFO(); Fill.AsciiChar = ACh; Fill.Attributes = (ushort)AAttr; NativeMethods.SMALL_RECT ScrollRectangle = ClipRectangle; NativeMethods.COORD DestinationOrigin = new NativeMethods.COORD(); DestinationOrigin.X = (short)AX1; DestinationOrigin.Y = (short)(AY1 - ALines); NativeMethods.ScrollConsoleScreenBuffer(_StdOutputHandle, ref ScrollRectangle, ref ClipRectangle, DestinationOrigin, ref Fill); } else { try { Console.MoveBufferArea(AX1, AY1, AX2, AY2, AX1, AY1 - ALines, ' ', GetConsoleColour(_TextAttr % 16), GetConsoleColour(_TextAttr / 16)); } catch (NotImplementedException) { try { int OldX = Console.CursorLeft; int OldY = Console.CursorTop; Console.SetCursorPosition(0, _ScreenSize.Y - 1); for (int i = 0; i < ALines; i++) Console.WriteLine(); Console.SetCursorPosition(OldX, OldY); } catch (NotImplementedException) { // Can't do that } } } } }
/// <summary> /// Scrolls the given window down the given number of lines (leaving blank lines at the top), filling the void with the given character with the given text attribute /// </summary> /// <param name="AX1">The 0-based left column of the window</param> /// <param name="AY1">The 0-based top row of the window</param> /// <param name="AX2">The 0-based right column of the window</param> /// <param name="AY2">The 0-based bottom row of the window</param> /// <param name="ALines">The number of lines to scroll</param> /// <param name="ACh">The character to fill the void with</param> /// <param name="AAttr">The text attribute to fill the void with</param> private static void ScrollDownCustom(int AX1, int AY1, int AX2, int AY2, int ALines, char ACh, int AAttr) { lock (_Lock) { if (OSUtils.IsWindows) { NativeMethods.COORD DestinationOrigin = new NativeMethods.COORD(); DestinationOrigin.X = (short)AX1; DestinationOrigin.Y = (short)(AY1 + ALines); NativeMethods.CHAR_INFO Fill = new NativeMethods.CHAR_INFO(); Fill.AsciiChar = ACh; Fill.Attributes = (ushort)AAttr; NativeMethods.SMALL_RECT ScrollRectangle = new NativeMethods.SMALL_RECT(); ScrollRectangle.Bottom = (short)(AY2 - ALines); ScrollRectangle.Left = (short)AX1; ScrollRectangle.Right = (short)AX2; ScrollRectangle.Top = (short)AY1; NativeMethods.ScrollConsoleScreenBuffer(_StdOutputHandle, ref ScrollRectangle, IntPtr.Zero, DestinationOrigin, ref Fill); } else { try { Console.MoveBufferArea(AX1, AY1, AX2, AY2 - ALines, AX1, AY1 + ALines, ' ', GetConsoleColour(_TextAttr % 16), GetConsoleColour(_TextAttr / 16)); } catch (NotImplementedException) { // Can't do that } } } }
public static NativeMethods.CHAR_INFO[] SaveScreen(int left, int top, int right, int bottom) { lock (_Lock) { if (OSUtils.IsWindows) { NativeMethods.COORD BufferSize = new NativeMethods.COORD(); BufferSize.X = (short)(right - left + 1); BufferSize.Y = (short)(bottom - top + 1); NativeMethods.CHAR_INFO[] Buffer = new NativeMethods.CHAR_INFO[BufferSize.X * BufferSize.Y]; NativeMethods.COORD BufferCoord = new NativeMethods.COORD(); BufferCoord.X = 0; BufferCoord.Y = 0; NativeMethods.SMALL_RECT ReadRegion = new NativeMethods.SMALL_RECT(); ReadRegion.Left = (short)(left - 1); ReadRegion.Top = (short)(top - 1); ReadRegion.Right = (short)(right - 1); ReadRegion.Bottom = (short)(bottom - 1); NativeMethods.ReadConsoleOutput(_StdOutputHandle, Buffer, BufferSize, BufferCoord, ref ReadRegion); return Buffer; } else { // TODO Save from buffer return null; } } }
public static void RestoreScreen(NativeMethods.CHAR_INFO[] buffer, int left, int top, int right, int bottom) { lock (_Lock) { if (OSUtils.IsWindows) { NativeMethods.COORD BufferCoord = new NativeMethods.COORD(); BufferCoord.X = 0; BufferCoord.Y = 0; NativeMethods.COORD BufferSize = new NativeMethods.COORD(); BufferSize.X = (short)(right - left + 1); BufferSize.Y = (short)(bottom - top + 1); NativeMethods.SMALL_RECT WriteRegion = new NativeMethods.SMALL_RECT(); WriteRegion.Left = (short)(left - 1); WriteRegion.Top = (short)(top - 1); WriteRegion.Right = (short)(right - 1); WriteRegion.Bottom = (short)(bottom - 1); NativeMethods.WriteConsoleOutput(_StdOutputHandle, buffer, BufferSize, BufferCoord, ref WriteRegion); } else { if (buffer != null) { // TODO Restore from buffer } } } }