/* * Move from one rectangle to another. We must be careful about the order that * this is done, to avoid overwriting parts of the source before they are moved. */ static VOID ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer, PSMALL_RECT SrcRegion, PSMALL_RECT DstRegion, PSMALL_RECT ClipRegion, CHAR_INFO FillChar) { int Width = ConioRectWidth(SrcRegion); int Height = ConioRectHeight(SrcRegion); int SX, SY; int DX, DY; int XDelta, YDelta; int i, j; SY = SrcRegion->Top; DY = DstRegion->Top; YDelta = 1; if (SY < DY) { /* Moving down: work from bottom up */ SY = SrcRegion->Bottom; DY = DstRegion->Bottom; YDelta = -1; } for (i = 0; i < Height; i++) { PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY); PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY); SX = SrcRegion->Left; DX = DstRegion->Left; XDelta = 1; if (SX < DX) { /* Moving right: work from right to left */ SX = SrcRegion->Right; DX = DstRegion->Right; XDelta = -1; } for (j = 0; j < Width; j++) { CHAR_INFO Cell = SRow[SX]; if (SX >= ClipRegion->Left && SX <= ClipRegion->Right && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom) { SRow[SX] = FillChar; } if (DX >= ClipRegion->Left && DX <= ClipRegion->Right && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom) { DRow[DX] = Cell; } SX += XDelta; DX += XDelta; } SY += YDelta; DY += YDelta; } }
/* * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput... */ NTSTATUS NTAPI ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN PCHAR_CELL CharInfo/*Buffer*/, IN COORD CharInfoSize, IN OUT PSMALL_RECT WriteRegion, IN BOOLEAN DrawRegion) { SHORT X, Y; SMALL_RECT ScreenBuffer; PCHAR_CELL CurCharInfo; SMALL_RECT CapturedWriteRegion; PCHAR_INFO Ptr; if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedWriteRegion = *WriteRegion; /* Make sure WriteRegion is inside the screen buffer */ ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion)) { /* * It is okay to have a WriteRegion completely outside * the screen buffer. No data is written then. */ return STATUS_SUCCESS; } // CurCharInfo = CharInfo; for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y) { /**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/ Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y); for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X) { ConsoleOutputAnsiToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char); Ptr->Attributes = CurCharInfo->Attributes; ++Ptr; ++CurCharInfo; } } if (DrawRegion) TermDrawRegion(Console, &CapturedWriteRegion); *WriteRegion = CapturedWriteRegion; return STATUS_SUCCESS; }
/*static*/ VOID ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff) { PCHAR_INFO Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y); SHORT Pos; for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++, Ptr++) { /* Fill the cell */ Ptr->Char.UnicodeChar = L' '; Ptr->Attributes = Buff->ScreenDefaultAttrib; } }
static VOID FASTCALL TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region) { UINT SrcDelta, DestDelta; LONG i; PCHAR_INFO Src, SrcEnd; Src = ConioCoordToPointer(Buff, Region->Left, Region->Top); SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */; for (i = Region->Top; i <= Region->Bottom; i++) { ConsoleUnicodeCharToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar); *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes; Src += SrcDelta; if (SrcEnd <= Src) { Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); } Dest += DestDelta; } }
NTSTATUS NTAPI ConDrvReadConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, OUT PCHAR_INFO CharInfo/*Buffer*/, IN OUT PSMALL_RECT ReadRegion) { SHORT X, Y; SMALL_RECT ScreenBuffer; PCHAR_INFO CurCharInfo; SMALL_RECT CapturedReadRegion; PCHAR_INFO Ptr; if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedReadRegion = *ReadRegion; /* Make sure ReadRegion is inside the screen buffer */ ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion)) { /* * It is okay to have a ReadRegion completely outside * the screen buffer. No data is read then. */ return STATUS_SUCCESS; } CurCharInfo = CharInfo; for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y) { Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y); for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X) { if (Unicode) { CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar; } else { // ConsoleOutputUnicodeToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar); WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1, &CurCharInfo->Char.AsciiChar, 1, NULL, NULL); } CurCharInfo->Attributes = Ptr->Attributes; ++Ptr; ++CurCharInfo; } } *ReadRegion = CapturedReadRegion; return STATUS_SUCCESS; }
NTSTATUS ConioResizeBuffer(PCONSOLE Console, PTEXTMODE_SCREEN_BUFFER ScreenBuffer, COORD Size) { PCHAR_INFO Buffer; DWORD Offset = 0; PCHAR_INFO ptr; WORD CurrentAttribute; USHORT CurrentY; PCHAR_INFO OldBuffer; DWORD i; DWORD diff; /* Buffer size is not allowed to be smaller than the view size */ if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y) return STATUS_INVALID_PARAMETER; if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y) { // FIXME: Trigger a buffer resize event ?? return STATUS_SUCCESS; } if (Console->FixedSize) { /* * The console is in fixed-size mode, so we cannot resize anything * at the moment. However, keep those settings somewhere so that * we can try to set them up when we will be allowed to do so. */ ScreenBuffer->OldScreenBufferSize = Size; return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS } Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO)); if (!Buffer) return STATUS_NO_MEMORY; DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y); OldBuffer = ScreenBuffer->Buffer; for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++) { ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY); if (Size.X <= ScreenBuffer->ScreenBufferSize.X) { /* Reduce size */ RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO)); Offset += Size.X; } else { /* Enlarge size */ RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO)); Offset += ScreenBuffer->ScreenBufferSize.X; /* The attribute to be used is the one of the last cell of the current line */ CurrentAttribute = ConioCoordToPointer(ScreenBuffer, ScreenBuffer->ScreenBufferSize.X - 1, CurrentY)->Attributes; diff = Size.X - ScreenBuffer->ScreenBufferSize.X; /* Zero-out the new part of the buffer */ for (i = 0; i < diff; i++) { ptr = Buffer + Offset; ptr->Char.UnicodeChar = L' '; ptr->Attributes = CurrentAttribute; ++Offset; } } } if (Size.Y > ScreenBuffer->ScreenBufferSize.Y) { diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y); /* Zero-out the new part of the buffer */ for (i = 0; i < diff; i++) { ptr = Buffer + Offset; ptr->Char.UnicodeChar = L' '; ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib; ++Offset; } } (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer); ConsoleFreeHeap(OldBuffer); ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size; ScreenBuffer->VirtualY = 0; /* Ensure cursor and window are within buffer */ if (ScreenBuffer->CursorPosition.X >= Size.X) ScreenBuffer->CursorPosition.X = Size.X - 1; if (ScreenBuffer->CursorPosition.Y >= Size.Y) ScreenBuffer->CursorPosition.Y = Size.Y - 1; if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X) ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X; if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y) ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y; /* * Trigger a buffer resize event */ if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT) { ULONG NumEventsWritten; INPUT_RECORD er; er.EventType = WINDOW_BUFFER_SIZE_EVENT; er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize; // ConioProcessInputEvent(Console, &er); ConDrvWriteConsoleInput(Console, &Console->InputBuffer, TRUE, &er, 1, &NumEventsWritten); } return STATUS_SUCCESS; }
static NTSTATUS ConioWriteConsole(PFRONTEND FrontEnd, PTEXTMODE_SCREEN_BUFFER Buff, PWCHAR Buffer, DWORD Length, BOOL Attrib) { PCONSRV_CONSOLE Console = FrontEnd->Console; UINT i; PCHAR_INFO Ptr; SMALL_RECT UpdateRect; SHORT CursorStartX, CursorStartY; UINT ScrolledLines; CursorStartX = Buff->CursorPosition.X; CursorStartY = Buff->CursorPosition.Y; UpdateRect.Left = Buff->ScreenBufferSize.X; UpdateRect.Top = Buff->CursorPosition.Y; UpdateRect.Right = -1; UpdateRect.Bottom = Buff->CursorPosition.Y; ScrolledLines = 0; for (i = 0; i < Length; i++) { /* * If we are in processed mode, interpret special characters and * display them correctly. Otherwise, just put them into the buffer. */ if (Buff->Mode & ENABLE_PROCESSED_OUTPUT) { /* --- CR --- */ if (Buffer[i] == L'\r') { Buff->CursorPosition.X = 0; UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); continue; } /* --- LF --- */ else if (Buffer[i] == L'\n') { Buff->CursorPosition.X = 0; ConioNextLine(Buff, &UpdateRect, &ScrolledLines); continue; } /* --- BS --- */ else if (Buffer[i] == L'\b') { /* Only handle BS if we're not on the first pos of the first line */ if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y) { if (0 == Buff->CursorPosition.X) { /* slide virtual position up */ Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1; Buff->CursorPosition.Y--; UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y); } else { Buff->CursorPosition.X--; } Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); Ptr->Char.UnicodeChar = L' '; Ptr->Attributes = Buff->ScreenDefaultAttrib; UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); } continue; } /* --- TAB --- */ else if (Buffer[i] == L'\t') { UINT EndX; UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1); EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X); Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); while (Buff->CursorPosition.X < EndX) { Ptr->Char.UnicodeChar = L' '; Ptr->Attributes = Buff->ScreenDefaultAttrib; ++Ptr; Buff->CursorPosition.X++; } UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1); if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) { if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) { Buff->CursorPosition.X = 0; ConioNextLine(Buff, &UpdateRect, &ScrolledLines); } else { Buff->CursorPosition.X--; } } continue; } /* --- BEL ---*/ else if (Buffer[i] == L'\a') { FrontEnd->Vtbl->RingBell(FrontEnd); continue; } } UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); Ptr->Char.UnicodeChar = Buffer[i]; if (Attrib) Ptr->Attributes = Buff->ScreenDefaultAttrib; Buff->CursorPosition.X++; if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) { if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) { Buff->CursorPosition.X = 0; ConioNextLine(Buff, &UpdateRect, &ScrolledLines); } else { Buff->CursorPosition.X = CursorStartX; } } } if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer) { // TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, // ScrolledLines, Buffer, Length); FrontEnd->Vtbl->WriteStream(FrontEnd, &UpdateRect, CursorStartX, CursorStartY, ScrolledLines, Buffer, Length); } return STATUS_SUCCESS; }
static VOID CopyBlock(PTEXTMODE_SCREEN_BUFFER Buffer, PSMALL_RECT Selection) { /* * Pressing the Shift key while copying text, allows us to copy * text without newline characters (inline-text copy mode). */ BOOL InlineCopyMode = !!(GetKeyState(VK_SHIFT) & KEY_PRESSED); HANDLE hData; PCHAR_INFO ptr; LPWSTR data, dstPos; ULONG selWidth, selHeight; ULONG xPos, yPos; ULONG size; DPRINT("CopyBlock(%u, %u, %u, %u)\n", Selection->Left, Selection->Top, Selection->Right, Selection->Bottom); /* Prevent against empty blocks */ if (Selection == NULL) return; if (Selection->Left > Selection->Right || Selection->Top > Selection->Bottom) return; selWidth = Selection->Right - Selection->Left + 1; selHeight = Selection->Bottom - Selection->Top + 1; /* Basic size for one line... */ size = selWidth; /* ... and for the other lines, add newline characters if needed. */ if (selHeight > 0) { /* * If we are not in inline-text copy mode, each selected line must * finish with \r\n . Otherwise, the lines will be just concatenated. */ size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1); } else { DPRINT1("This case must never happen, because selHeight is at least == 1\n"); } size++; /* Null-termination */ size *= sizeof(WCHAR); /* Allocate some memory area to be given to the clipboard, so it will not be freed here */ hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size); if (hData == NULL) return; data = GlobalLock(hData); if (data == NULL) { GlobalFree(hData); return; } DPRINT("Copying %dx%d selection\n", selWidth, selHeight); dstPos = data; for (yPos = 0; yPos < selHeight; yPos++) { ULONG length = selWidth; ptr = ConioCoordToPointer(Buffer, Selection->Left, Selection->Top + yPos); /* Trim whitespace from the right */ while (length > 0) { if (IS_WHITESPACE(ptr[length-1].Char.UnicodeChar)) --length; else break; } /* Copy only the characters, leave attributes alone */ for (xPos = 0; xPos < length; xPos++) { /* * Sometimes, applications can put NULL chars into the screen-buffer * (this behaviour is allowed). Detect this and replace by a space. */ *dstPos++ = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' '); } /* Add newline characters if we are not in inline-text copy mode */ if (!InlineCopyMode) { if (yPos != (selHeight - 1)) { wcscat(dstPos, L"\r\n"); dstPos += 2; } } } DPRINT("Setting data <%S> to clipboard\n", data); GlobalUnlock(hData); EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hData); }
VOID GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, PGUI_CONSOLE_DATA GuiData, PRECT rcView, PRECT rcFramebuffer) { PCONSRV_CONSOLE Console = Buffer->Header.Console; // ASSERT(Console == GuiData->Console); ULONG TopLine, BottomLine, LeftChar, RightChar; ULONG Line, Char, Start; PCHAR_INFO From; PWCHAR To; WORD LastAttribute, Attribute; ULONG CursorX, CursorY, CursorHeight; HBRUSH CursorBrush, OldBrush; HFONT OldFont, NewFont; BOOLEAN IsUnderline; if (Buffer->Buffer == NULL) return; if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; rcFramebuffer->left = Buffer->ViewOrigin.X * GuiData->CharWidth + rcView->left; rcFramebuffer->top = Buffer->ViewOrigin.Y * GuiData->CharHeight + rcView->top; rcFramebuffer->right = Buffer->ViewOrigin.X * GuiData->CharWidth + rcView->right; rcFramebuffer->bottom = Buffer->ViewOrigin.Y * GuiData->CharHeight + rcView->bottom; LeftChar = rcFramebuffer->left / GuiData->CharWidth; TopLine = rcFramebuffer->top / GuiData->CharHeight; RightChar = rcFramebuffer->right / GuiData->CharWidth; BottomLine = rcFramebuffer->bottom / GuiData->CharHeight; if (RightChar >= (ULONG)Buffer->ScreenBufferSize.X) RightChar = Buffer->ScreenBufferSize.X - 1; if (BottomLine >= (ULONG)Buffer->ScreenBufferSize.Y) BottomLine = Buffer->ScreenBufferSize.Y - 1; LastAttribute = ConioCoordToPointer(Buffer, LeftChar, TopLine)->Attributes; SetTextColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute))); SetBkColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute))); /* We use the underscore flag as a underline flag */ IsUnderline = !!(LastAttribute & COMMON_LVB_UNDERSCORE); /* Select the new font */ NewFont = GuiData->Font[IsUnderline ? FONT_BOLD : FONT_NORMAL]; OldFont = SelectObject(GuiData->hMemDC, NewFont); for (Line = TopLine; Line <= BottomLine; Line++) { WCHAR LineBuffer[80]; // Buffer containing a part or all the line to be displayed From = ConioCoordToPointer(Buffer, LeftChar, Line); // Get the first code of the line Start = LeftChar; To = LineBuffer; for (Char = LeftChar; Char <= RightChar; Char++) { /* * We flush the buffer if the new attribute is different * from the current one, or if the buffer is full. */ if (From->Attributes != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR))) { TextOutW(GuiData->hMemDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight, LineBuffer, Char - Start); Start = Char; To = LineBuffer; Attribute = From->Attributes; if (Attribute != LastAttribute) { LastAttribute = Attribute; SetTextColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute))); SetBkColor(GuiData->hMemDC, PaletteRGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute))); /* Change underline state if needed */ if (!!(LastAttribute & COMMON_LVB_UNDERSCORE) != IsUnderline) { IsUnderline = !!(LastAttribute & COMMON_LVB_UNDERSCORE); /* Select the new font */ NewFont = GuiData->Font[IsUnderline ? FONT_BOLD : FONT_NORMAL]; /* OldFont = */ SelectObject(GuiData->hMemDC, NewFont); } } } *(To++) = (From++)->Char.UnicodeChar; } TextOutW(GuiData->hMemDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight, LineBuffer, RightChar - Start + 1); } /* Restore the old font */ SelectObject(GuiData->hMemDC, OldFont); /* * Draw the caret */ if (Buffer->CursorInfo.bVisible && Buffer->CursorBlinkOn && !Buffer->ForceCursorOff) { CursorX = Buffer->CursorPosition.X; CursorY = Buffer->CursorPosition.Y; if (LeftChar <= CursorX && CursorX <= RightChar && TopLine <= CursorY && CursorY <= BottomLine) { CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight); Attribute = ConioCoordToPointer(Buffer, Buffer->CursorPosition.X, Buffer->CursorPosition.Y)->Attributes; if (Attribute == DEFAULT_SCREEN_ATTRIB) Attribute = Buffer->ScreenDefaultAttrib; CursorBrush = CreateSolidBrush(PaletteRGBFromAttrib(Console, TextAttribFromAttrib(Attribute))); OldBrush = SelectObject(GuiData->hMemDC, CursorBrush); PatBlt(GuiData->hMemDC, CursorX * GuiData->CharWidth, CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight), GuiData->CharWidth, CursorHeight, PATCOPY); SelectObject(GuiData->hMemDC, OldBrush); DeleteObject(CursorBrush); } } LeaveCriticalSection(&Console->Lock); }
static VOID CopyLines(PTEXTMODE_SCREEN_BUFFER Buffer, PCOORD Begin, PCOORD End) { HANDLE hData; PCHAR_INFO ptr; LPWSTR data, dstPos; ULONG NumChars, size; ULONG xPos, yPos, xBeg, xEnd; DPRINT("CopyLines((%u, %u) ; (%u, %u))\n", Begin->X, Begin->Y, End->X, End->Y); /* Prevent against empty blocks... */ if (Begin == NULL || End == NULL) return; /* ... or malformed blocks */ if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X)) return; /* Compute the number of characters to copy */ if (End->Y == Begin->Y) // top == bottom { NumChars = End->X - Begin->X + 1; } else // if (End->Y > Begin->Y) { NumChars = Buffer->ScreenBufferSize.X - Begin->X; if (End->Y >= Begin->Y + 2) { NumChars += (End->Y - Begin->Y - 1) * Buffer->ScreenBufferSize.X; } NumChars += End->X + 1; } size = (NumChars + 1) * sizeof(WCHAR); /* Null-terminated */ /* Allocate some memory area to be given to the clipboard, so it will not be freed here */ hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size); if (hData == NULL) return; data = GlobalLock(hData); if (data == NULL) { GlobalFree(hData); return; } DPRINT("Copying %d characters\n", NumChars); dstPos = data; /* * We need to walk per-lines, and not just looping in the big screen-buffer * array, because of the way things are stored inside it. The downside is * that it makes the code more complicated. */ for (yPos = Begin->Y; (yPos <= (ULONG)End->Y) && (NumChars > 0); yPos++) { xBeg = (yPos == Begin->Y ? Begin->X : 0); xEnd = (yPos == End->Y ? End->X : Buffer->ScreenBufferSize.X - 1); ptr = ConioCoordToPointer(Buffer, 0, yPos); /* Copy only the characters, leave attributes alone */ for (xPos = xBeg; (xPos <= xEnd) && (NumChars-- > 0); xPos++) { /* * Sometimes, applications can put NULL chars into the screen-buffer * (this behaviour is allowed). Detect this and replace by a space. */ *dstPos++ = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' '); } } DPRINT("Setting data <%S> to clipboard\n", data); GlobalUnlock(hData); EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hData); }
NTSTATUS NTAPI ConDrvWriteConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, IN PCHAR_INFO CharInfo/*Buffer*/, IN PCOORD BufferSize, IN PCOORD BufferCoord, IN OUT PSMALL_RECT WriteRegion) { SHORT i, X, Y, SizeX, SizeY; SMALL_RECT ScreenBuffer; PCHAR_INFO CurCharInfo; SMALL_RECT CapturedWriteRegion; PCHAR_INFO Ptr; if (Console == NULL || Buffer == NULL || CharInfo == NULL || BufferSize == NULL || BufferCoord == NULL || WriteRegion == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedWriteRegion = *WriteRegion; SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedWriteRegion)); SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedWriteRegion)); CapturedWriteRegion.Right = CapturedWriteRegion.Left + SizeX - 1; CapturedWriteRegion.Bottom = CapturedWriteRegion.Top + SizeY - 1; /* Make sure WriteRegion is inside the screen buffer */ ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion)) { /* * It is okay to have a WriteRegion completely outside * the screen buffer. No data is written then. */ return STATUS_SUCCESS; } for (i = 0, Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; i++, Y++) { CurCharInfo = CharInfo + (i + BufferCoord->Y) * BufferSize->X + BufferCoord->X; Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y); for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; X++) { if (Unicode) { Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar; } else { ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar); } Ptr->Attributes = CurCharInfo->Attributes; ++Ptr; ++CurCharInfo; } } ConioDrawRegion(Console, &CapturedWriteRegion); WriteRegion->Left = CapturedWriteRegion.Left; WriteRegion->Top = CapturedWriteRegion.Top ; WriteRegion->Right = CapturedWriteRegion.Left + SizeX - 1; WriteRegion->Bottom = CapturedWriteRegion.Top + SizeY - 1; return STATUS_SUCCESS; }
NTSTATUS NTAPI ConDrvReadConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, OUT PCHAR_INFO CharInfo/*Buffer*/, IN PCOORD BufferSize, IN PCOORD BufferCoord, IN OUT PSMALL_RECT ReadRegion) { PCHAR_INFO CurCharInfo; SHORT SizeX, SizeY; SMALL_RECT CapturedReadRegion; SMALL_RECT ScreenRect; DWORD i; PCHAR_INFO Ptr; LONG X, Y; UINT CodePage; if (Console == NULL || Buffer == NULL || CharInfo == NULL || BufferSize == NULL || BufferCoord == NULL || ReadRegion == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity check */ ASSERT(Console == Buffer->Header.Console); CapturedReadRegion = *ReadRegion; /* FIXME: Is this correct? */ CodePage = Console->OutputCodePage; SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedReadRegion)); SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedReadRegion)); CapturedReadRegion.Right = CapturedReadRegion.Left + SizeX; CapturedReadRegion.Bottom = CapturedReadRegion.Top + SizeY; ConioInitRect(&ScreenRect, 0, 0, Buffer->ScreenBufferSize.Y, Buffer->ScreenBufferSize.X); if (!ConioGetIntersection(&CapturedReadRegion, &ScreenRect, &CapturedReadRegion)) { return STATUS_SUCCESS; } for (i = 0, Y = CapturedReadRegion.Top; Y < CapturedReadRegion.Bottom; ++i, ++Y) { CurCharInfo = CharInfo + (i * BufferSize->X); Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y); for (X = CapturedReadRegion.Left; X < CapturedReadRegion.Right; ++X) { if (Unicode) { CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar; } else { // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar); WideCharToMultiByte(CodePage, 0, &Ptr->Char.UnicodeChar, 1, &CurCharInfo->Char.AsciiChar, 1, NULL, NULL); } CurCharInfo->Attributes = Ptr->Attributes; ++Ptr; ++CurCharInfo; } } ReadRegion->Left = CapturedReadRegion.Left; ReadRegion->Top = CapturedReadRegion.Top ; ReadRegion->Right = CapturedReadRegion.Left + SizeX - 1; ReadRegion->Bottom = CapturedReadRegion.Top + SizeY - 1; return STATUS_SUCCESS; }
VOID GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer) { /* * This function supposes that the system clipboard was opened. */ PCONSOLE Console = Buffer->Header.Console; /* * Pressing the Shift key while copying text, allows us to copy * text without newline characters (inline-text copy mode). */ BOOL InlineCopyMode = (GetKeyState(VK_SHIFT) & 0x8000); HANDLE hData; PCHAR_INFO ptr; LPWSTR data, dstPos; ULONG selWidth, selHeight; ULONG xPos, yPos, size; selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1; selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1; DPRINT("Selection is (%d|%d) to (%d|%d)\n", Console->Selection.srSelection.Left, Console->Selection.srSelection.Top, Console->Selection.srSelection.Right, Console->Selection.srSelection.Bottom); /* Basic size for one line... */ size = selWidth; /* ... and for the other lines, add newline characters if needed. */ if (selHeight > 0) { /* * If we are not in inline-text copy mode, each selected line must * finish with \r\n . Otherwise, the lines will be just concatenated. */ size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1); } size += 1; /* Null-termination */ size *= sizeof(WCHAR); /* Allocate memory, it will be passed to the system and may not be freed here */ hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size); if (hData == NULL) return; data = GlobalLock(hData); if (data == NULL) return; DPRINT("Copying %dx%d selection\n", selWidth, selHeight); dstPos = data; for (yPos = 0; yPos < selHeight; yPos++) { ptr = ConioCoordToPointer(Buffer, Console->Selection.srSelection.Left, yPos + Console->Selection.srSelection.Top); /* Copy only the characters, leave attributes alone */ for (xPos = 0; xPos < selWidth; xPos++) { /* * Sometimes, applications can put NULL chars into the screen-buffer * (this behaviour is allowed). Detect this and replace by a space. * FIXME - HACK: Improve the way we're doing that (i.e., put spaces * instead of NULLs (or even, nothing) only if it exists a non-null * char *after* those NULLs, before the end-of-line of the selection. * Do the same concerning spaces -- i.e. trailing spaces --). */ dstPos[xPos] = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' '); } dstPos += selWidth; /* Add newline characters if we are not in inline-text copy mode */ if (!InlineCopyMode) { if (yPos != (selHeight - 1)) { wcscat(data, L"\r\n"); dstPos += 2; } } } DPRINT("Setting data <%S> to clipboard\n", data); GlobalUnlock(hData); EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hData); }
VOID GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, PGUI_CONSOLE_DATA GuiData, HDC hDC, PRECT rc) { PCONSOLE Console = Buffer->Header.Console; // ASSERT(Console == GuiData->Console); ULONG TopLine, BottomLine, LeftChar, RightChar; ULONG Line, Char, Start; PCHAR_INFO From; PWCHAR To; WORD LastAttribute, Attribute; ULONG CursorX, CursorY, CursorHeight; HBRUSH CursorBrush, OldBrush; HFONT OldFont; if (Buffer->Buffer == NULL) return; TopLine = rc->top / GuiData->CharHeight + Buffer->ViewOrigin.Y; BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buffer->ViewOrigin.Y; LeftChar = rc->left / GuiData->CharWidth + Buffer->ViewOrigin.X; RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1 + Buffer->ViewOrigin.X; LastAttribute = ConioCoordToPointer(Buffer, LeftChar, TopLine)->Attributes; SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute))); SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute))); if (BottomLine >= Buffer->ScreenBufferSize.Y) BottomLine = Buffer->ScreenBufferSize.Y - 1; if (RightChar >= Buffer->ScreenBufferSize.X) RightChar = Buffer->ScreenBufferSize.X - 1; OldFont = SelectObject(hDC, GuiData->Font); for (Line = TopLine; Line <= BottomLine; Line++) { WCHAR LineBuffer[80]; // Buffer containing a part or all the line to be displayed From = ConioCoordToPointer(Buffer, LeftChar, Line); // Get the first code of the line Start = LeftChar; To = LineBuffer; for (Char = LeftChar; Char <= RightChar; Char++) { /* * We flush the buffer if the new attribute is different * from the current one, or if the buffer is full. */ if (From->Attributes != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR))) { TextOutW(hDC, (Start - Buffer->ViewOrigin.X) * GuiData->CharWidth , (Line - Buffer->ViewOrigin.Y) * GuiData->CharHeight, LineBuffer, Char - Start); Start = Char; To = LineBuffer; Attribute = From->Attributes; if (Attribute != LastAttribute) { SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(Attribute))); SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(Attribute))); LastAttribute = Attribute; } } *(To++) = (From++)->Char.UnicodeChar; } TextOutW(hDC, (Start - Buffer->ViewOrigin.X) * GuiData->CharWidth , (Line - Buffer->ViewOrigin.Y) * GuiData->CharHeight, LineBuffer, RightChar - Start + 1); } /* * Draw the caret */ if (Buffer->CursorInfo.bVisible && Buffer->CursorBlinkOn && !Buffer->ForceCursorOff) { CursorX = Buffer->CursorPosition.X; CursorY = Buffer->CursorPosition.Y; if (LeftChar <= CursorX && CursorX <= RightChar && TopLine <= CursorY && CursorY <= BottomLine) { CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight); Attribute = ConioCoordToPointer(Buffer, Buffer->CursorPosition.X, Buffer->CursorPosition.Y)->Attributes; if (Attribute != DEFAULT_SCREEN_ATTRIB) { CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Attribute)); } else { CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Buffer->ScreenDefaultAttrib)); } OldBrush = SelectObject(hDC, CursorBrush); PatBlt(hDC, (CursorX - Buffer->ViewOrigin.X) * GuiData->CharWidth, (CursorY - Buffer->ViewOrigin.Y) * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight), GuiData->CharWidth, CursorHeight, PATCOPY); SelectObject(hDC, OldBrush); DeleteObject(CursorBrush); } } SelectObject(hDC, OldFont); }