private static string Benchmark(int frameCount, IBufferedAbsConsole <CHAR_INFO> screen) { var r = new Random(); var stop = new Stopwatch(); stop.Start(); for (int i = 0; i < frameCount; i++) { var x = r.Next(screen.Width); var y = r.Next(screen.Height); var a = r.Next(26); var clr = r.Next(0, 255); screen[x, y] = new CHAR_INFO(TestHelper.GetCharOffset('A', a), (ushort)clr); screen.Update(); if (i % 50 == 0) { System.Console.Title = i.ToString(); } } stop.Stop(); return($"{frameCount} frames in {stop.Elapsed} at {frameCount / stop.Elapsed.TotalSeconds} FPS"); }
protected override void Setup() { var letterA = new CHAR_INFO { AsciiChar = 'A', }; letterA.Attributes = (UInt16) (FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY); var charBufSize = new COORD { X = 1, Y = 1, }; var characterPos = new COORD { X = 0, Y = 0, }; var writeArea = new SMALL_RECT { Left = 0, Top = 0, Right = 0, Bottom = 0, }; WriteConsoleOutput( WriteHandle, new CHAR_INFO[] { letterA }, charBufSize, characterPos, ref writeArea); Console.Write("\n"); }
public static extern bool ScrollConsoleScreenBuffer( IntPtr hConsoleOutput, [In] ref SMALL_RECT lpScrollRectangle, IntPtr lpClipRectangle, COORD dwDestinationOrigin, [In] ref CHAR_INFO lpFill );
protected override void Setup() { var consoleBuffer = new CHAR_INFO[Width * Height]; for (int h = 0; h < Height; ++h) { for (int w = 0; w < Width; ++w) { consoleBuffer[w + Width * h].AsciiChar = 'A' /*(char)Random.Next(256)*/; consoleBuffer[w + Width * h].Attributes = (UInt16)Random.Next(256); } } var charBufSize = new COORD { X = Width, Y = Height, }; var characterPos = new COORD { X = 0, Y = 0, }; WriteConsoleOutput( WriteHandle, consoleBuffer, charBufSize, characterPos, ref WindowSize); }
private CHAR_INFO[] CreateCharInfoBuffer(int lines, params object[] items) { var result = new List <CHAR_INFO>(); var fg = _console.ForegroundColor; var bg = _console.BackgroundColor; foreach (var i in items) { var item = i; if (item is char) { result.Add(new CHAR_INFO((char)item, fg, bg)); continue; } if (item is InvertedToken) { fg = (ConsoleColor)((int)fg ^ 7); bg = (ConsoleColor)((int)bg ^ 7); continue; } if (item is NextLineToken) { item = new string(' ', _console.BufferWidth - (result.Count % _console.BufferWidth)); fg = _console.ForegroundColor; bg = _console.BackgroundColor; // Fallthrough to string case. } if (item is string str) { result.AddRange(str.Select(c => new CHAR_INFO(c, fg, bg))); continue; } if (item is TokenClassification) { fg = ForegroundColors[(int)(TokenClassification)item]; bg = BackgroundColors[(int)(TokenClassification)item]; continue; } if (item is Tuple <ConsoleColor, ConsoleColor> tuple) { fg = tuple.Item1; bg = tuple.Item2; continue; } throw new ArgumentException("Unexpected type"); } var extraSpacesNeeded = (lines * _console.BufferWidth) - result.Count; if (extraSpacesNeeded > 0) { var space = new CHAR_INFO(' ', _console.ForegroundColor, _console.BackgroundColor); result.AddRange(Enumerable.Repeat(space, extraSpacesNeeded)); } return(result.ToArray()); }
public void SetChar() { const ConCharAttributes attribute = (ConCharAttributes)0xCCCC; CHAR_INFO source = new CHAR_INFO(' ', attribute); var result = source.SetChar('x'); result.Char.Should().Be('x'); result.Attributes.Should().Be(attribute); }
public void Setforeground() { const ConCharAttributes attribute = (ConCharAttributes)0xCCCC; const ConCharAttributes expected = (ConCharAttributes)0xCCC0 | ConCharAttributes.ForeGroundGreen | ConCharAttributes.ForeGroundIntensity; CHAR_INFO source = new CHAR_INFO('x', attribute); var result = source.SetForeground(ConsoleColor.Green); result.Char.Should().Be('x'); result.Attributes.Should().Be(expected); }
/// <summary> /// Renderer should call this method before any control render. /// </summary> public void Clear() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { buffer[x, y] = new CHAR_INFO(); opacityMatrix[x, y] = 0; } } }
public CHAR_INFO[] ReadConsoleOutput(ConsoleOutputHandle consoleOutputHandle, Rectangle region) { SMALL_RECT rect = new SMALL_RECT(region); CHAR_INFO[] buffer = new CHAR_INFO[region.Width * region.Height]; if (!NativeMethods.ReadConsoleOutput(consoleOutputHandle, buffer, new COORD(region), default, ref rect)) { throw Exceptions.Win32(); } return(buffer); }
static CHAR_INFO ToCharInfo(char c) { var info = new CHAR_INFO(); // Give it our character to write info.Char.UnicodeChar = c; // Use our attributes info.Attributes = Attributes; // Return info for this character return(info); }
//private char[,] buffer = new char[80, 25]; private void initBuffer() { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { buffer[y, x] = new CHAR_INFO( ) { UnicodeChar = ' ' }; } } }
public void FillArea_CorrectArea_FilledCorrectly() { const char character = 'X'; Size size = new Size(4, 4); var mainBuffer = Enumerable.Repeat(cc, 16).ToArray(); CHAR_INFO c0 = new CHAR_INFO { Attributes = attributes, Char = character }; var expectedBuffer = new[] { cc, cc, cc, cc, cc, c0, c0, cc, cc, c0, c0, cc, cc, cc, cc, cc }; bool written = false, successful = false; using var stubbedApi = new StubbedNativeCalls(); stubbedApi.ReadConsoleOutputConsoleOutputHandleRectangle = (handle, rectangle) => { rectangle.Size.Should().Be(size); handle.Should().Be(stubbedApi.ScreenHandle); return(mainBuffer); }; stubbedApi.WriteConsoleOutputConsoleOutputHandleCHAR_INFOArrayRectangle = (handle, buffer, area) => { written = true; handle.Should().Be(stubbedApi.ScreenHandle); area.Size.Should().Be(size); buffer.Should().Equal(expectedBuffer); successful = true; }; var sut = new ConControls.Controls.Drawing.ConsoleGraphics(stubbedApi.ScreenHandle, stubbedApi, size, new ConControls.Controls.Drawing.FrameCharSets()); sut.FillArea( background: background, foreColor: foreground, c: character, area: new Rectangle(1, 1, 2, 2)); written.Should().BeFalse(); mainBuffer.Should().Equal(expectedBuffer); sut.Flush(); written.Should().BeTrue(); successful.Should().BeTrue(); }
internal void WriteOutputBuffer(char[] bufferChars, ConsoleColor[] bufferFg, ConsoleColor[] bufferBg, int width, int height, List <RowSpan> invalidSpans) { // This copying of the backbuffer data into a local CHAR_INFO array is a lot of // copying that might be a perf issue. If so consider storing a CHAR_INFO array // directly in the BackBuffer class. var charinfos = new CHAR_INFO[bufferChars.Length]; for (int i = 0; i < bufferChars.Length; i += 1) { charinfos[i].UnicodeChar = bufferChars[i]; charinfos[i].Attributes = CharInfoAttributeFromConsoleColors(bufferFg[i], bufferBg[i]); } COORD bufferSize; bufferSize.x = (short)width; bufferSize.y = (short)height; COORD bufferCoord; SMALL_RECT writeRegion; if (invalidSpans == null) { writeRegion.Top = 0; writeRegion.Left = 0; writeRegion.Bottom = (short)(height - 1); writeRegion.Right = (short)(width - 1); bufferCoord.x = 0; bufferCoord.y = 0; WriteConsoleOutput(_handleOut, charinfos, bufferSize, bufferCoord, ref writeRegion); } else { foreach (var span in invalidSpans) { writeRegion.Top = (short)span.Row; writeRegion.Bottom = (short)span.Row; writeRegion.Left = (short)span.Start; writeRegion.Right = (short)(span.End - 1); bufferCoord.y = writeRegion.Top; bufferCoord.x = writeRegion.Left; WriteConsoleOutput(_handleOut, charinfos, bufferSize, bufferCoord, ref writeRegion); } } }
public static IEnumerable <string> ReadFromBuffer(short x, short y, short width, short height) { IntPtr buffer = Marshal.AllocHGlobal(width * height * Marshal.SizeOf(typeof(CHAR_INFO))); if (buffer == null) { throw new OutOfMemoryException(); } try { COORD coord = new COORD(); SMALL_RECT rc = new SMALL_RECT(); rc.Left = x; rc.Top = y; rc.Right = (short)(x + width - 1); rc.Bottom = (short)(y + height - 1); COORD size = new COORD(); size.X = width; size.Y = height; const int STD_OUTPUT_HANDLE = -11; if (!ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), buffer, size, coord, ref rc)) { // 'Not enough storage is available to process this command' may be raised for buffer size > 64K (see ReadConsoleOutput doc.) throw new Win32Exception(Marshal.GetLastWin32Error()); } IntPtr ptr = buffer; for (int h = 0; h < height; h++) { StringBuilder sb = new StringBuilder(); for (int w = 0; w < width; w++) { CHAR_INFO ci = (CHAR_INFO)Marshal.PtrToStructure(ptr, typeof(CHAR_INFO)); char[] chars = Console.OutputEncoding.GetChars(ci.charData); sb.Append(chars[0]); ptr += Marshal.SizeOf(typeof(CHAR_INFO)); } yield return(sb.ToString()); } } finally { Marshal.FreeHGlobal(buffer); } }
public override void ScrollBuffer(int lines) { var handle = GetStdHandle((uint)StandardHandleId.Output); var scrollRectangle = new SMALL_RECT { Top = (short)lines, Left = 0, Bottom = (short)(Console.BufferHeight - 1), Right = (short)Console.BufferWidth }; var destinationOrigin = new COORD { X = 0, Y = 0 }; var fillChar = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor); ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar); }
public static void DrawRectangle(int left, int top, int right, int bottom) { if (!AreScreenBufferArraysEqual(left, top, right, bottom)) { int rows = bottom - top + 1; int cols = right - left + 1; CHAR_INFO[] rectBuf = new CHAR_INFO[rows * cols]; int i = 0; for (int row = top; row <= bottom; row++) { for (int col = left; col <= right; col++) { rectBuf[i++] = ScreenBuffer.screenBuf[(row * ScreenBuffer.cols) + col]; } } COORD rectBufSize = new COORD() { X = (short)cols, Y = (short)rows }; COORD rectBufCoord = new COORD() { X = 0, Y = 0 }; SMALL_RECT rectangle = new SMALL_RECT() { Left = (short)left, Top = (short)top, Right = (short)right, Bottom = (short)bottom }; // note that the screen is NOT cleared at any point as this will simply // overwrite the existing values on screen. Clearing will cause flickering again. bool b = WriteConsoleOutput( ScreenBuffer.handle, rectBuf, rectBufSize, rectBufCoord, ref rectangle); Array.Copy(ScreenBuffer.screenBuf, ScreenBuffer.screenBufCopy, ScreenBuffer.screenBuf.Length); } }
public void DrawBackground_AreaTooLarge_ClippedCorrectly() { const char expectedCharacter = default; Size size = new Size(4, 4); var mainBuffer = Enumerable.Repeat(cc, 16).ToArray(); CHAR_INFO c0 = new CHAR_INFO { Attributes = background.ToBackgroundColor() | background.ToForegroundColor(), Char = expectedCharacter }; var expectedBuffer = Enumerable.Repeat(c0, 16).ToArray(); bool written = false, successful = false; using var stubbedApi = new StubbedNativeCalls(); stubbedApi.ReadConsoleOutputConsoleOutputHandleRectangle = (handle, rectangle) => { rectangle.Size.Should().Be(size); handle.Should().Be(stubbedApi.ScreenHandle); return(mainBuffer); }; stubbedApi.WriteConsoleOutputConsoleOutputHandleCHAR_INFOArrayRectangle = (handle, buffer, area) => { written = true; handle.Should().Be(stubbedApi.ScreenHandle); area.Size.Should().Be(size); buffer.Should().Equal(expectedBuffer); successful = true; }; var sut = new ConControls.Controls.Drawing.ConsoleGraphics(stubbedApi.ScreenHandle, stubbedApi, size, new ConControls.Controls.Drawing.FrameCharSets()); sut.DrawBackground( color: background, area: new Rectangle(-1, -1, 7, 7)); written.Should().BeFalse(); mainBuffer.Should().Equal(expectedBuffer); sut.Flush(); written.Should().BeTrue(); successful.Should().BeTrue(); }
private static void Main(string[] args) { uint outChars; IntPtr consoleHandle = Process.GetCurrentProcess().MainWindowHandle; CConsole.WriteConsole(consoleHandle, "HELLO C WORLD FROM C#", 21, out outChars, new IntPtr(0)); Console.WriteLine("OutputWrite testing:"); CHAR_INFO[,] BufferData = new CHAR_INFO[8, 2]; CHAR_INFO a = new CHAR_INFO { UnicodeChar = 'C' }; SMALL_RECT writeBounds = new SMALL_RECT { Top = 3, Left = 2, Bottom = 5, Right = 10 }; CConsole.WriteConsoleOutput(consoleHandle, BufferData, new COORD { X = 8, Y = 2 }, new COORD { X = 2, Y = 4 }, ref writeBounds); }
/// <summary> /// Копирует affectedRect из буфера на экран консоли с учетом того, что буфер /// находится на экране консоли по смещению offset. /// </summary> /// <param name="canvas"></param> /// <param name="affectedRect">Измененная область относительно this.</param> /// <param name="offset">В какой точке экрана размещен контрол (см <see cref="Renderer.RootElementRect"/>).</param> public void CopyToPhysicalCanvas(PhysicalCanvas canvas, Rect affectedRect, Point offset) { Rect rectToCopy = affectedRect; Rect bufferRect = new Rect(new Point(0, 0), new Size(this.width, this.height)); Rect canvasRect = new Rect(new Point(-offset.X, -offset.Y), canvas.Size); rectToCopy.Intersect(canvasRect); rectToCopy.Intersect(bufferRect); // for (int x = 0; x < rectToCopy.width; x++) { int bufferX = x + rectToCopy.x; int canvasX = x + rectToCopy.x + offset.x; for (int y = 0; y < rectToCopy.height; y++) { int bufferY = y + rectToCopy.y; int canvasY = y + rectToCopy.y + offset.y; CHAR_INFO charInfo = buffer[bufferX, bufferY]; canvas[canvasX][canvasY].Assign(charInfo); } } }
/// <summary> /// Write a line of text with specific foreground/background colors to the console. /// </summary> /// <param name="x">The 0-based destination x coordinate.</param> /// <param name="y">The 0-based destination y coordinate.</param> /// <param name="foreground">Foreground color</param> /// <param name="background">Background color</param> /// <param name="s">The string to write.</param> /// <returns>True if the write was successful, false if there was a failure.</returns> public static bool WriteColor(int x, int y, ConsoleColor foreground, ConsoleColor background, string s) { // the attribute is the combination of the foreground color [0x00, 0x0F] and background color [0x00, 0xF0] ushort attribute = (ushort)((int)foreground | (((int)background) << 4)); // Build a CHAR_INFO array containing the characters we want to write and the attributes CHAR_INFO[] info = new CHAR_INFO[s.Length]; char[] array = s.ToCharArray(); for (int i = 0; i < s.Length; i++) { info[i].UnicodeChar = (ushort)array[i]; info[i].Attributes = attribute; } // Writing the length of the string, one character tall. COORD myBufferSize; myBufferSize.X = (short)s.Length; myBufferSize.Y = (short)1; // Starting at 0,0 in the source CHAR_INFO array COORD myBufferPosition; myBufferPosition.X = 0; myBufferPosition.Y = 0; // from x..(x+s.Length), one line for y direction. SMALL_RECT mySmallRect; mySmallRect.Left = (short)x; mySmallRect.Right = (short)(x + s.Length); mySmallRect.Top = (short)y; mySmallRect.Bottom = (short)y; // Write. return(WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), info, myBufferSize, myBufferPosition, ref mySmallRect)); }
public string readvalue(ref System.IntPtr ptr, short a) { SMALL_RECT srctReadRect = new SMALL_RECT { Top = 0, Left = 0, Bottom = 1, Right = 80 }; CHAR_INFO[,] chiBuffer = new CHAR_INFO[2, 80]; // [2][80];10 lines, with 50 characters COORD coordBufSize = new COORD { X = 80, Y = 2 }; COORD coordBufCoord = new COORD { X = 0, Y = 0 }; bool fSuccess; int i = 0; int j = 0; string chartostring = "start"; string previousstring = ""; short g = a; short h = (short)(g + 1); srctReadRect.Top = g; srctReadRect.Bottom = h; int count = 0; //System.Console.WriteLine(g + "." + h); while (count < 1)//Hunting:if it find 1 empty rows with text then it will stop reading { previousstring = chartostring; srctReadRect.Top = g; srctReadRect.Bottom = h; fSuccess = ReadConsoleOutput(ptr, chiBuffer, coordBufSize, coordBufCoord, ref srctReadRect); i = 0; j = 0; chartostring = ""; while (j < coordBufSize.Y) { while (i < coordBufSize.X) { if (chiBuffer[j, i].UnicodeChar != 0 && chiBuffer[j, i].UnicodeChar != 32) chartostring += chiBuffer[j, i].UnicodeChar; i++; } i = 0; j++; } if (chartostring.Length == 0)//The character length is zero, reverse the top of the source rect { count++; } else { count = 0; } g += 1; h += 1; } return previousstring; }
private void ReallyRender() { var text = ParseInput(); int statusLineCount = GetStatusLineCount(); int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount); var backgroundColor = _initialBackgroundColor; var foregroundColor = _initialForegroundColor; bool afterLastToken = false; int totalBytes = j; int bufferWidth = _console.BufferWidth; var tokenStack = new Stack<SavedTokenState>(); tokenStack.Push(new SavedTokenState { Tokens = _tokens, Index = 0, BackgroundColor = _initialBackgroundColor, ForegroundColor = _initialForegroundColor }); int bufferLineCount; try { _console.StartRender(); bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount; if (_consoleBuffer.Length != bufferLineCount * bufferWidth) { var newBuffer = new CHAR_INFO[bufferLineCount * bufferWidth]; Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); if (_consoleBuffer.Length > bufferLineCount * bufferWidth) { int consoleBufferOffset = ConvertOffsetToConsoleBufferOffset(text.Length, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); // Need to erase the extra lines that we won't draw again for (int i = consoleBufferOffset; i < _consoleBuffer.Length; i++) { _consoleBuffer[i] = _space; } _console.WriteBufferLines(_consoleBuffer, ref _initialY); } _consoleBuffer = newBuffer; } for (int i = 0; i < text.Length; i++) { totalBytes = totalBytes % bufferWidth; if (!afterLastToken) { // Figure out the color of the character - if it's in a token, // use the tokens color otherwise use the initial color. var state = tokenStack.Peek(); var token = state.Tokens[state.Index]; if (i == token.Extent.EndOffset) { if (token == state.Tokens[state.Tokens.Length - 1]) { tokenStack.Pop(); if (tokenStack.Count == 0) { afterLastToken = true; token = null; foregroundColor = _initialForegroundColor; backgroundColor = _initialBackgroundColor; } else { state = tokenStack.Peek(); } } if (!afterLastToken) { foregroundColor = state.ForegroundColor; backgroundColor = state.BackgroundColor; token = state.Tokens[++state.Index]; } } if (!afterLastToken && i == token.Extent.StartOffset) { GetTokenColors(token, out foregroundColor, out backgroundColor); var stringToken = token as StringExpandableToken; if (stringToken != null) { // We might have nested tokens. if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any()) { var tokens = new Token[stringToken.NestedTokens.Count + 1]; stringToken.NestedTokens.CopyTo(tokens, 0); // NestedTokens doesn't have an "EOS" token, so we use // the string literal token for that purpose. tokens[tokens.Length - 1] = stringToken; tokenStack.Push(new SavedTokenState { Tokens = tokens, Index = 0, BackgroundColor = backgroundColor, ForegroundColor = foregroundColor }); if (i == tokens[0].Extent.StartOffset) { GetTokenColors(tokens[0], out foregroundColor, out backgroundColor); } } } } } var charToRender = text[i]; if (charToRender == '\n') { while ((j % bufferWidth) != 0) { _consoleBuffer[j++] = _space; } for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++) { _consoleBuffer[j].UnicodeChar = Options.ContinuationPrompt[k]; _consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor; _consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor; } } else { int size = LengthInBufferCells(charToRender); totalBytes += size; //if there is no enough space for the character at the edge, fill in spaces at the end and //put the character to next line. int filling = totalBytes > bufferWidth ? (totalBytes - bufferWidth) % size : 0; for (int f = 0; f < filling; f++) { _consoleBuffer[j++] = _space; totalBytes++; } if (char.IsControl(charToRender)) { _consoleBuffer[j].UnicodeChar = '^'; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = (char)('@' + charToRender); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } else if (size > 1) { _consoleBuffer[j].UnicodeChar = charToRender; _consoleBuffer[j].Attributes = (ushort)(_consoleBuffer[j].Attributes | (uint)CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = charToRender; _consoleBuffer[j].Attributes = (ushort)(_consoleBuffer[j].Attributes | (uint)CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } else { _consoleBuffer[j].UnicodeChar = charToRender; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } } } } finally { _console.EndRender(); } for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++) { _consoleBuffer[j] = _space; } if (_statusLinePrompt != null) { foregroundColor = _statusIsErrorMessage ? Options.ErrorForegroundColor : _console.ForegroundColor; backgroundColor = _statusIsErrorMessage ? Options.ErrorBackgroundColor : _console.BackgroundColor; for (int i = 0; i < _statusLinePrompt.Length; i++, j++) { _consoleBuffer[j].UnicodeChar = _statusLinePrompt[i]; _consoleBuffer[j].ForegroundColor = foregroundColor; _consoleBuffer[j].BackgroundColor = backgroundColor; } for (int i = 0; i < _statusBuffer.Length; i++, j++) { _consoleBuffer[j].UnicodeChar = _statusBuffer[i]; _consoleBuffer[j].ForegroundColor = foregroundColor; _consoleBuffer[j].BackgroundColor = backgroundColor; } for (; j < _consoleBuffer.Length; j++) { _consoleBuffer[j] = _space; } } bool rendered = false; if (_parseErrors.Length > 0) { int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount); while (promptChar >= 0) { var c = (char)_consoleBuffer[promptChar].UnicodeChar; if (char.IsWhiteSpace(c)) { promptChar -= 1; continue; } ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor; _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red; _console.WriteBufferLines(_consoleBuffer, ref _initialY); rendered = true; _consoleBuffer[promptChar].ForegroundColor = prevColor; break; } } if (!rendered) { _console.WriteBufferLines(_consoleBuffer, ref _initialY); } PlaceCursor(); if ((_initialY + bufferLineCount) > (_console.WindowTop + _console.WindowHeight)) { _console.WindowTop = _initialY + bufferLineCount - _console.WindowHeight; } _lastRenderTime.Restart(); }
private void MaybeEmphasize(ref CHAR_INFO charInfo, int i, ConsoleColor foregroundColor, ConsoleColor backgroundColor) { if (i >= _emphasisStart && i < (_emphasisStart + _emphasisLength)) { backgroundColor = _options.EmphasisBackgroundColor; foregroundColor = _options.EmphasisForegroundColor; } else if (_visualSelectionCommandCount > 0 && InRegion(i)) { // We can't quite emulate real console selection because it inverts // based on actual screen colors, our pallete is limited. The choice // to invert only the lower 3 bits to change the color is somewhat // but looks best with the 2 default color schemes - starting PowerShell // from it's shortcut or from a cmd shortcut. foregroundColor = (ConsoleColor)((int)foregroundColor ^ 7); backgroundColor = (ConsoleColor)((int)backgroundColor ^ 7); } charInfo.ForegroundColor = foregroundColor; charInfo.BackgroundColor = backgroundColor; }
private static void WriteBlankLines(int count, int top) { var console = _singleton._console; var blanks = new CHAR_INFO[count * console.BufferWidth]; for (int i = 0; i < blanks.Length; i++) { blanks[i].BackgroundColor = console.BackgroundColor; blanks[i].ForegroundColor = console.ForegroundColor; blanks[i].UnicodeChar = ' '; } console.WriteBufferLines(blanks, ref top); }
public CHAR_INFO[] ReadBufferLines(int top, int count) { var toCopy = BufferWidth * count; var result = new CHAR_INFO[toCopy]; Array.Copy(buffer, top * BufferWidth, result, 0, toCopy); return result; }
public static extern bool WriteConsoleOutput( IntPtr hConsoleOutput, CHAR_INFO[] lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, ref SMALL_RECT lpWriteRegion );
private CHAR_INFO[] CreateCharInfoBuffer(int lines, params object[] items) { var result = new List<CHAR_INFO>(); var fg = _console.ForegroundColor; var bg = _console.BackgroundColor; foreach (var i in items) { var item = i; if (item is char) { result.Add(new CHAR_INFO((char)item, fg, bg)); continue; } if (item is InvertedToken) { fg = (ConsoleColor)((int)fg ^ 7); bg = (ConsoleColor)((int)bg ^ 7); continue; } if (item is NextLineToken) { item = new string(' ', _console.BufferWidth - (result.Count % _console.BufferWidth)); fg = _console.ForegroundColor; bg = _console.BackgroundColor; // Fallthrough to string case. } var str = item as string; if (str != null) { result.AddRange(str.Select(c => new CHAR_INFO(c, fg, bg))); continue; } if (item is TokenClassification) { fg = ForegroundColors[(int)(TokenClassification)item]; bg = BackgroundColors[(int)(TokenClassification)item]; continue; } var tuple = item as Tuple<ConsoleColor, ConsoleColor>; if (tuple != null) { fg = tuple.Item1; bg = tuple.Item2; continue; } throw new ArgumentException("Unexpected type"); } var extraSpacesNeeded = (lines * _console.BufferWidth) - result.Count; if (extraSpacesNeeded > 0) { var space = new CHAR_INFO(' ', _console.ForegroundColor, _console.BackgroundColor); result.AddRange(Enumerable.Repeat(space, extraSpacesNeeded)); } return result.ToArray(); }
static void Box(List <string> list) { int internalBoxWidth = Math.Min(Console.BufferWidth - 2, list.Max(e => e.Length)); int boxWidth = internalBoxWidth + 2; int internalBoxHeight = list.Count; int boxHeight = internalBoxHeight + 2; var buffer = new CHAR_INFO[boxWidth * boxHeight]; buffer[0].UnicodeChar = '+'; buffer[boxWidth - 1].UnicodeChar = '+'; for (int i = 1; i < boxWidth - 1; i++) { buffer[i].UnicodeChar = '-'; } for (int i = 0; i < list.Count; i++) { int rowStart = (i + 1) * boxWidth; buffer[rowStart++].UnicodeChar = '|'; buffer[rowStart + internalBoxWidth].UnicodeChar = '|'; string s = list[i]; int j; for (j = 0; j < s.Length; j++) { buffer[rowStart + j].UnicodeChar = s[j]; } for (; j < internalBoxWidth; j++) { buffer[rowStart + j].UnicodeChar = ' '; } } int lastRowStart = (boxHeight - 1) * boxWidth; buffer[lastRowStart].UnicodeChar = '+'; for (int i = 1; i < boxWidth - 1; i++) { buffer[i + lastRowStart].UnicodeChar = '-'; } buffer[lastRowStart + boxWidth - 1].UnicodeChar = '+'; for (int i = 0; i < buffer.Length; i++) { buffer[i].Attributes = (ushort)ConsoleColor.Blue | ((ushort)(ConsoleColor.DarkGreen) << 4); if (i % 2 != 0) { buffer[i].Attributes |= 0xfff0; } } var handle = NativeMethods.GetStdHandle((uint)StandardHandleId.Output); var bufferSize = new COORD { X = (short)boxWidth, Y = (short)boxHeight }; var bufferCoord = new COORD { X = 0, Y = 0 }; var writeRegion = new SMALL_RECT { Top = 1, Left = 1, Bottom = (short)(1 + boxHeight), Right = (short)(1 + boxWidth) }; Console.WriteLine("some random stuff"); Console.WriteLine("and more some random stuff"); Console.WriteLine("lorem ipsum blah blah"); Console.ReadKey(); var saveBuffer = new CHAR_INFO[buffer.Length]; NativeMethods.ReadConsoleOutput(handle, saveBuffer, bufferSize, bufferCoord, ref writeRegion); unsafe { fixed(CHAR_INFO *p = &buffer[0]) fixed(CHAR_INFO * sp = &saveBuffer[0]) { NativeMethods.WriteConsoleOutput(handle, buffer, bufferSize, bufferCoord, ref writeRegion); Console.ReadKey(); NativeMethods.WriteConsoleOutput(handle, saveBuffer, bufferSize, bufferCoord, ref writeRegion); } } Console.ReadKey(); }
public void WriteBufferLines(CHAR_INFO[] bufferToWrite, ref int top, bool ensureBottomLineVisible) { var startPos = top * BufferWidth; for (int i = 0; i < bufferToWrite.Length; i++) { buffer[startPos + i] = bufferToWrite[i]; } }
private static void InvertSelectedCompletion(CHAR_INFO[] buffer, int selectedItem, int menuColumnWidth, int menuRows) { var selectedX = selectedItem / menuRows; var selectedY = selectedItem - (selectedX * menuRows); var start = selectedY * Console.BufferWidth + selectedX * menuColumnWidth; for (int i = 0; i < menuColumnWidth; i++) { int j = i + start; buffer[j].ForegroundColor = (ConsoleColor)((int)buffer[j].ForegroundColor ^ 7); buffer[j].BackgroundColor = (ConsoleColor)((int)buffer[j].BackgroundColor ^ 7); } }
void ClearBuffer() { for (int i = 0; i < buffer.Length; i++) { buffer[i] = new CHAR_INFO(' ', ForegroundColor, BackgroundColor); } }
public void Assign(CHAR_INFO charInfo) { canvas.buffer[y, x] = charInfo; }
internal static unsafe extern bool ReadConsoleOutput(IntPtr hConsoleOutput, CHAR_INFO* pBuffer, COORD bufferSize, COORD bufferCoord, ref SMALL_RECT readRegion);
public void WriteBufferLines(CHAR_INFO[] bufferToWrite, ref int top) { WriteBufferLines(bufferToWrite, ref top, true); }
internal static unsafe extern bool WriteConsoleOutput(IntPtr hConsoleOutput, CHAR_INFO* buffer, COORD bufferSize, COORD bufferCoord, ref SMALL_RECT writeRegion);
/// <summary> /// Write a line of text with specific foreground/background colors to the console. /// </summary> /// <param name="x">The 0-based destination x coordinate.</param> /// <param name="y">The 0-based destination y coordinate.</param> /// <param name="foreground">Foreground color</param> /// <param name="background">Background color</param> /// <param name="s">The string to write.</param> /// <returns>True if the write was successful, false if there was a failure.</returns> public static bool WriteColor(int x, int y, ConsoleColor foreground, ConsoleColor background, string s) { // the attribute is the combination of the foreground color [0x00, 0x0F] and background color [0x00, 0xF0] ushort attribute = (ushort)((int)foreground | (((int)background)<<4)); // Build a CHAR_INFO array containing the characters we want to write and the attributes CHAR_INFO[] info = new CHAR_INFO[s.Length]; char[] array = s.ToCharArray(); for(int i = 0; i < s.Length; i++) { info[i].UnicodeChar = (ushort)array[i]; info[i].Attributes = attribute; } // Writing the length of the string, one character tall. COORD myBufferSize; myBufferSize.X = (short)s.Length; myBufferSize.Y = (short)1; // Starting at 0,0 in the source CHAR_INFO array COORD myBufferPosition; myBufferPosition.X = 0; myBufferPosition.Y = 0; // from x..(x+s.Length), one line for y direction. SMALL_RECT mySmallRect; mySmallRect.Left = (short)x; mySmallRect.Right = (short)(x + s.Length); mySmallRect.Top = (short)y; mySmallRect.Bottom = (short)y; // Write. return WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), info, myBufferSize, myBufferPosition, ref mySmallRect); }
/// <summary> /// Moves a block of data in a screen buffer. The effects of the move can be limited by specifying a clipping rectangle, so the contents of the console screen buffer outside the clipping rectangle are unchanged. /// </summary> /// <param name="hConsoleOutput">A handle to the console input buffer. The handle must have the <see cref="BUFFER_ACCESS_MODE.GENERIC_READ"/> access right.</param> /// <param name="lpScrollRectangle">A pointer to a <see cref="SMALL_RECT"/> structure whose members specify the upper-left and lower-right coordinates of the console screen buffer rectangle to be moved.</param> /// <param name="lpClipRectangle">A pointer to a <see cref="SMALL_RECT"/> structure whose members specify the upper-left and lower-right coordinates of the console screen buffer rectangle that is affected by the scrolling. This pointer can be <see langword="null"/>.</param> /// <param name="dwDestinationOrigin">A <see cref="COORD"/> structure that specifies the upper-left corner of the new location of the <paramref name="lpScrollRectangle"/> contents, in characters.</param> /// <param name="lpFill">A pointer to a <see cref="CHAR_INFO"/> structure that specifies the character and color attributes to be used in filling the cells within the intersection of <paramref name="lpScrollRectangle"/> and <paramref name="lpClipRectangle"/> that were left empty as a result of the move.</param> /// <returns>If the function succeeds, returns TRUE, otherwise, retun FALSE.</returns> [DllImport("kernel32.dll", SetLastError = true)] public static extern bool ScrollConsoleScreenBuffer([In] IntPtr hConsoleOutput, [In] ref SMALL_RECT lpScrollRectangle, [In, Optional] IntPtr lpClipRectangle, [In] COORD dwDestinationOrigin, [In] ref CHAR_INFO lpFill);
/// <summary> /// Оверлоад для оптимизированного наложения в случае, когда известно, что в дочернем /// контроле поменялась лишь часть, идентифицируемая параметром affectedRect. /// Будет обработана только эта часть дочернего контрола, и количество операций уменьшится. /// </summary> /// <param name="childBuffer"></param> /// <param name="actualOffset"></param> /// <param name="childRenderSize"></param> /// <param name="renderSlotRect"></param> /// <param name="layoutClip"></param> /// <param name="affectedRect">Прямоугольник в дочернем контроле, который был изменен.</param> public void ApplyChild(RenderingBuffer childBuffer, Vector actualOffset, Size childRenderSize, Rect renderSlotRect, Rect layoutClip, Rect?affectedRect) { // Считаем finalRect - прямоугольник относительно parent, который нужно закрасить Rect finalRect = layoutClip; if (affectedRect != null) { finalRect.Intersect(affectedRect.Value); } // Если child.RenderSlotRect больше child.RenderSize, а rendering buffer // дочернего контрола больше его RenderSize (такое бывает после уменьшения // размеров контрола - т.к. буфер может только увеличиваться, но не уменьшаться) - // то нам нужно либо передать в метод ApplyChild и child.RenderSize, либо // выполнить пересечение заранее finalRect.Intersect(new Rect(new Point(0, 0), childRenderSize)); // Because cannot call Offset() method of empty rect if (finalRect.IsEmpty) { return; } finalRect.Offset(actualOffset); finalRect.Intersect(renderSlotRect); // Нужно также учесть размеры буфера текущего контрола finalRect.Intersect(new Rect(new Point(0, 0), new Size(this.width, this.height))); for (int x = finalRect.Left; x < finalRect.Right; x++) { int parentX = x; int childX = parentX - actualOffset.x; for (int y = finalRect.Top; y < finalRect.Bottom; y++) { int parentY = y; int childY = parentY - actualOffset.y; CHAR_INFO charInfo = childBuffer.buffer[childX, childY]; int opacity = childBuffer.opacityMatrix[childX, childY]; // Для полностью прозрачных пикселей родительского буфера - присваиваем и значение // пикселя, и значение opacity, дальше дело за следующим родителем if (this.opacityMatrix[parentX, parentY] == 2 || this.opacityMatrix[parentX, parentY] == 6) { this.buffer[parentX, parentY] = charInfo; this.opacityMatrix[parentX, parentY] = opacity; } else { // В остальных случаях opacity родительского буфера остаётся, а // сам пиксель зависит от opacity дочернего элемента if (opacity == 0 || opacity == 4) { this.buffer[parentX, parentY] = charInfo; } else if (opacity == 1 || opacity == 5) { charInfo.Attributes = Colors.Blend(Color.DarkGray, Color.Black); charInfo.UnicodeChar = buffer[parentX, parentY].UnicodeChar; buffer[parentX, parentY] = charInfo; } else if (opacity == 3 || opacity == 7) { // берем фоновые атрибуты символа из родительского буфера Attr parentAttr = buffer[parentX, parentY].Attributes; if ((parentAttr & Attr.BACKGROUND_BLUE) == Attr.BACKGROUND_BLUE) { charInfo.Attributes |= Attr.BACKGROUND_BLUE; } else { charInfo.Attributes &= ~Attr.BACKGROUND_BLUE; } if ((parentAttr & Attr.BACKGROUND_GREEN) == Attr.BACKGROUND_GREEN) { charInfo.Attributes |= Attr.BACKGROUND_GREEN; } else { charInfo.Attributes &= ~Attr.BACKGROUND_GREEN; } if ((parentAttr & Attr.BACKGROUND_RED) == Attr.BACKGROUND_RED) { charInfo.Attributes |= Attr.BACKGROUND_RED; } else { charInfo.Attributes &= ~Attr.BACKGROUND_RED; } if ((parentAttr & Attr.BACKGROUND_INTENSITY) == Attr.BACKGROUND_INTENSITY) { charInfo.Attributes |= Attr.BACKGROUND_INTENSITY; } else { charInfo.Attributes &= ~Attr.BACKGROUND_INTENSITY; } buffer[parentX, parentY] = charInfo; } } } } }