/*++ Copyright (c) 1985 - 1999, Microsoft Corporation Module Name: clipbrd.c Abstract: This file implements the clipboard functions. Author: Therese Stowell (thereses) Jan-24-1992 --*/ #include "precomp.h" #pragma hdrstop /*++ Here's the pseudocode for various clipboard operations init keyboard select (mark) --------------------------- if (already selecting) cancel selection init flags hidecursor createcursor init select rect set win text convert to mouse select (select) -------------------------------- set flags destroy cursor showcursor invert old select rect init select rect invert select rect set win text re-init mouse select -------------------- invert old select rect init select rect invert select rect cancel mouse select ------------------- set flags reset win text invert old select rect cancel key select ----------------- set flags reset win text destroy cursor showcursor invert old select rect --*/ BOOL MyInvert( IN PCONSOLE_INFORMATION Console, IN PSMALL_RECT SmallRect ) /*++ invert a rect --*/ { RECT Rect; PSCREEN_INFORMATION ScreenInfo; #ifdef FE_SB SMALL_RECT SmallRect2; COORD TargetPoint; SHORT StringLength; #endif // FE_SB ScreenInfo = Console->CurrentScreenBuffer; #ifdef FE_SB if (CONSOLE_IS_DBCS_OUTPUTCP(Console) && ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { for (SmallRect2.Top=SmallRect->Top; SmallRect2.Top <= SmallRect->Bottom;SmallRect2.Top++) { SmallRect2.Bottom = SmallRect2.Top; SmallRect2.Left = SmallRect->Left; SmallRect2.Right = SmallRect->Right; TargetPoint.X = SmallRect2.Left; TargetPoint.Y = SmallRect2.Top; StringLength = SmallRect2.Right - SmallRect2.Left + 1; BisectClipbrd(StringLength,TargetPoint,ScreenInfo,&SmallRect2); if (SmallRect2.Left <= SmallRect2.Right) { Rect.left = SmallRect2.Left-ScreenInfo->Window.Left; Rect.top = SmallRect2.Top-ScreenInfo->Window.Top; Rect.right = SmallRect2.Right+1-ScreenInfo->Window.Left; Rect.bottom = SmallRect2.Bottom+1-ScreenInfo->Window.Top; Rect.left *= SCR_FONTSIZE(ScreenInfo).X; Rect.top *= SCR_FONTSIZE(ScreenInfo).Y; Rect.right *= SCR_FONTSIZE(ScreenInfo).X; Rect.bottom *= SCR_FONTSIZE(ScreenInfo).Y; PatBlt(Console->hDC, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, DSTINVERT ); } } } else #endif // FE_SB { Rect.left = SmallRect->Left-ScreenInfo->Window.Left; Rect.top = SmallRect->Top-ScreenInfo->Window.Top; Rect.right = SmallRect->Right+1-ScreenInfo->Window.Left; Rect.bottom = SmallRect->Bottom+1-ScreenInfo->Window.Top; #ifdef FE_SB if (!CONSOLE_IS_DBCS_OUTPUTCP(Console) && ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) #else if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) #endif { Rect.left *= SCR_FONTSIZE(ScreenInfo).X; Rect.top *= SCR_FONTSIZE(ScreenInfo).Y; Rect.right *= SCR_FONTSIZE(ScreenInfo).X; Rect.bottom *= SCR_FONTSIZE(ScreenInfo).Y; } PatBlt(Console->hDC, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, DSTINVERT ); } return(TRUE); } VOID InvertSelection( IN PCONSOLE_INFORMATION Console, BOOL Inverting ) { BOOL Inverted; if (Console->Flags & CONSOLE_SELECTING && Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY) { Inverted = (Console->SelectionFlags & CONSOLE_SELECTION_INVERTED) ? TRUE : FALSE; if (Inverting == Inverted) { return; } if (Inverting) { Console->SelectionFlags |= CONSOLE_SELECTION_INVERTED; } else { Console->SelectionFlags &= ~CONSOLE_SELECTION_INVERTED; } MyInvert(Console,&Console->SelectionRect); } } VOID InitializeMouseSelection( IN PCONSOLE_INFORMATION Console, IN COORD CursorPosition ) /*++ This routine initializes a selection region. --*/ { Console->SelectionAnchor = CursorPosition; Console->SelectionRect.Left = Console->SelectionRect.Right = CursorPosition.X; Console->SelectionRect.Top = Console->SelectionRect.Bottom = CursorPosition.Y; // // Fire off an event to let accessibility apps know the selection has changed. // ConsoleNotifyWinEvent(Console, EVENT_CONSOLE_CARET, CONSOLE_CARET_SELECTION, PACKCOORD(CursorPosition)); } VOID ExtendSelection( IN PCONSOLE_INFORMATION Console, IN COORD CursorPosition ) /*++ This routine extends a selection region. --*/ { SMALL_RECT OldSelectionRect; HRGN OldRegion,NewRegion,CombineRegion; COORD FontSize; PSCREEN_INFORMATION ScreenInfo = Console->CurrentScreenBuffer; if (CursorPosition.X < 0) { CursorPosition.X = 0; } else if (CursorPosition.X >= ScreenInfo->ScreenBufferSize.X) { CursorPosition.X = ScreenInfo->ScreenBufferSize.X-1; } if (CursorPosition.Y < 0) { CursorPosition.Y = 0; } else if (CursorPosition.Y >= ScreenInfo->ScreenBufferSize.Y) { CursorPosition.Y = ScreenInfo->ScreenBufferSize.Y-1; } if (!(Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY)) { if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { // scroll if necessary to make cursor visible. MakeCursorVisible(ScreenInfo, CursorPosition); ASSERT(!(Console->SelectionFlags & CONSOLE_MOUSE_SELECTION)); // // if the selection rect hasn't actually been started, // the selection cursor is still blinking. turn it off. // ConsoleHideCursor(ScreenInfo); } Console->SelectionFlags |= CONSOLE_SELECTION_NOT_EMPTY; Console->SelectionRect.Left =Console->SelectionRect.Right = Console->SelectionAnchor.X; Console->SelectionRect.Top = Console->SelectionRect.Bottom = Console->SelectionAnchor.Y; // invert the cursor corner #ifdef FE_SB if (!CONSOLE_IS_DBCS_OUTPUTCP(Console) && ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) #else if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) #endif { MyInvert(Console,&Console->SelectionRect); } } else { if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { // scroll if necessary to make cursor visible. MakeCursorVisible(ScreenInfo,CursorPosition); } #ifdef FE_SB // // uninvert old selection // if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) { MyInvert(Console, &Console->SelectionRect); } #endif // FE_SB } // // update selection rect // OldSelectionRect = Console->SelectionRect; if (CursorPosition.X <= Console->SelectionAnchor.X) { Console->SelectionRect.Left = CursorPosition.X; Console->SelectionRect.Right = Console->SelectionAnchor.X; } else if (CursorPosition.X > Console->SelectionAnchor.X) { Console->SelectionRect.Right = CursorPosition.X; Console->SelectionRect.Left = Console->SelectionAnchor.X; } if (CursorPosition.Y <= Console->SelectionAnchor.Y) { Console->SelectionRect.Top = CursorPosition.Y; Console->SelectionRect.Bottom = Console->SelectionAnchor.Y; } else if (CursorPosition.Y > Console->SelectionAnchor.Y) { Console->SelectionRect.Bottom = CursorPosition.Y; Console->SelectionRect.Top = Console->SelectionAnchor.Y; } // // change inverted selection // #ifdef FE_SB if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) { MyInvert(Console, &Console->SelectionRect); } else #endif { if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { FontSize = CON_FONTSIZE(Console); } else { FontSize.X = 1; FontSize.Y = 1; } CombineRegion = CreateRectRgn(0,0,0,0); OldRegion = CreateRectRgn((OldSelectionRect.Left-ScreenInfo->Window.Left)*FontSize.X, (OldSelectionRect.Top-ScreenInfo->Window.Top)*FontSize.Y, (OldSelectionRect.Right-ScreenInfo->Window.Left+1)*FontSize.X, (OldSelectionRect.Bottom-ScreenInfo->Window.Top+1)*FontSize.Y ); NewRegion = CreateRectRgn((Console->SelectionRect.Left-ScreenInfo->Window.Left)*FontSize.X, (Console->SelectionRect.Top-ScreenInfo->Window.Top)*FontSize.Y, (Console->SelectionRect.Right-ScreenInfo->Window.Left+1)*FontSize.X, (Console->SelectionRect.Bottom-ScreenInfo->Window.Top+1)*FontSize.Y ); CombineRgn(CombineRegion,OldRegion,NewRegion,RGN_XOR); InvertRgn(Console->hDC,CombineRegion); DeleteObject(OldRegion); DeleteObject(NewRegion); DeleteObject(CombineRegion); } // // Fire off an event to let accessibility apps know the selection has changed. // ConsoleNotifyWinEvent(Console, EVENT_CONSOLE_CARET, CONSOLE_CARET_SELECTION, PACKCOORD(CursorPosition)); } VOID CancelMouseSelection( IN PCONSOLE_INFORMATION Console ) /*++ This routine terminates a mouse selection. --*/ { PSCREEN_INFORMATION ScreenInfo = Console->CurrentScreenBuffer; // // turn off selection flag // Console->Flags &= ~CONSOLE_SELECTING; SetWinText(Console,msgSelectMode,FALSE); // // invert old select rect. if we're selecting by mouse, we // always have a selection rect. // MyInvert(Console,&Console->SelectionRect); ReleaseCapture(); // // Mark the cursor position as changed so we'll fire off a win event. // if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { ScreenInfo->BufferInfo.TextInfo.CursorMoved = TRUE; } } VOID CancelKeySelection( IN PCONSOLE_INFORMATION Console, IN BOOL JustCursor ) /*++ This routine terminates a key selection. --*/ { PSCREEN_INFORMATION ScreenInfo; if (!JustCursor) { // // turn off selection flag // Console->Flags &= ~CONSOLE_SELECTING; SetWinText(Console,msgMarkMode,FALSE); } // // invert old select rect, if we have one. // ScreenInfo = Console->CurrentScreenBuffer; if (Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY) { MyInvert(Console,&Console->SelectionRect); } else { ConsoleHideCursor(ScreenInfo); } // restore text cursor if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { SetCursorInformation(ScreenInfo, Console->TextCursorSize, Console->TextCursorVisible ); SetCursorPosition(ScreenInfo, Console->TextCursorPosition, TRUE ); } ConsoleShowCursor(ScreenInfo); } VOID ConvertToMouseSelect( IN PCONSOLE_INFORMATION Console, IN COORD MousePosition ) /*++ This routine converts to a mouse selection from a key selection. --*/ { Console->SelectionFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN; // // undo key selection // CancelKeySelection(Console,TRUE); Console->SelectionFlags |= CONSOLE_SELECTION_NOT_EMPTY; // // invert new selection // InitializeMouseSelection(Console, MousePosition); MyInvert(Console,&Console->SelectionRect); // // update title bar // SetWinText(Console,msgMarkMode,FALSE); SetWinText(Console,msgSelectMode,TRUE); // // capture mouse movement // SetCapture(Console->hWnd); } VOID ClearSelection( IN PCONSOLE_INFORMATION Console ) { if (Console->Flags & CONSOLE_SELECTING) { if (Console->SelectionFlags & CONSOLE_MOUSE_SELECTION) { CancelMouseSelection(Console); } else { CancelKeySelection(Console,FALSE); } UnblockWriteConsole(Console, CONSOLE_SELECTING); } } VOID StoreSelection( IN PCONSOLE_INFORMATION Console ) /*++ StoreSelection - Store selection (if present) into the Clipboard --*/ { PCHAR_INFO Selection,CurCharInfo; COORD SourcePoint; COORD TargetSize; SMALL_RECT TargetRect; PWCHAR CurChar,CharBuf; HANDLE ClipboardDataHandle; SHORT i,j; BOOL Success; PSCREEN_INFORMATION ScreenInfo; BOOL bFalseUnicode; BOOL bMungeData; #if defined(FE_SB) COORD TargetSize2; PWCHAR TmpClipboardData; SMALL_RECT SmallRect2; COORD TargetPoint; SHORT StringLength; WCHAR wchCARRIAGERETURN; WCHAR wchLINEFEED; int iExtra = 0; int iFeReserve = 1; #endif // // See if there is a selection to get // if (!(Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY)) { return; } // // read selection rectangle. clip it first. // ScreenInfo = Console->CurrentScreenBuffer; if (Console->SelectionRect.Left < 0) { Console->SelectionRect.Left = 0; } if (Console->SelectionRect.Top < 0) { Console->SelectionRect.Top = 0; } if (Console->SelectionRect.Right >= ScreenInfo->ScreenBufferSize.X) { Console->SelectionRect.Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1); } if (Console->SelectionRect.Bottom >= ScreenInfo->ScreenBufferSize.Y) { Console->SelectionRect.Bottom = (SHORT)(ScreenInfo->ScreenBufferSize.Y-1); } TargetSize.X = WINDOW_SIZE_X(&Console->SelectionRect); TargetSize.Y = WINDOW_SIZE_Y(&Console->SelectionRect); if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { #if defined(FE_SB) if (CONSOLE_IS_DBCS_CP(Console)) { iExtra = 4 ; // 4 is for DBCS lead or tail extra iFeReserve = 2 ; // FE does this for safety TmpClipboardData = ConsoleHeapAlloc(TMP_DBCS_TAG, (sizeof(WCHAR) * TargetSize.Y * (TargetSize.X + iExtra) + sizeof(WCHAR))); if (TmpClipboardData == NULL) { return; } } else { TmpClipboardData = NULL; } Selection = ConsoleHeapAlloc(TMP_TAG, sizeof(CHAR_INFO) * (TargetSize.X + iExtra) * TargetSize.Y * iFeReserve); if (Selection == NULL) { if (TmpClipboardData) ConsoleHeapFree(TmpClipboardData); return; } #else Selection = ConsoleHeapAlloc(TMP_TAG, sizeof(CHAR_INFO) * TargetSize.X * TargetSize.Y); if (Selection == NULL) return; #endif #if defined(FE_SB) if (!CONSOLE_IS_DBCS_CP(Console)) { #endif #ifdef i386 if ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) && (Console->Flags & CONSOLE_VDM_REGISTERED)) { ReadRegionFromScreenHW(ScreenInfo, &Console->SelectionRect, Selection); CurCharInfo = Selection; for (i=0; iChar.UnicodeChar = SB_CharToWcharGlyph(Console->OutputCP, CurCharInfo->Char.AsciiChar); } } } else { #endif SourcePoint.X = Console->SelectionRect.Left; SourcePoint.Y = Console->SelectionRect.Top; TargetRect.Left = TargetRect.Top = 0; TargetRect.Right = (SHORT)(TargetSize.X-1); TargetRect.Bottom = (SHORT)(TargetSize.Y-1); ReadRectFromScreenBuffer(ScreenInfo, SourcePoint, Selection, TargetSize, &TargetRect); #ifdef i386 } #endif // extra 2 per line is for CRLF, extra 1 is for null ClipboardDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (TargetSize.Y * (TargetSize.X + 2) + 1) * sizeof(WCHAR)); if (ClipboardDataHandle == NULL) { ConsoleHeapFree(Selection); return; } #if defined(FE_SB) } #endif // // convert to clipboard form // #if defined(FE_SB) if (CONSOLE_IS_DBCS_CP(Console)) { if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) && !(Console->FullScreenFlags & CONSOLE_FULLSCREEN)) { /* * False Unicode is obtained, so we will have to convert it to * Real Unicode, in which case we can't put CR or LF in now, since * they will be converted into 0x266A and 0x25d9. Temporarily * mark the CR/LF positions with 0x0000 instead. */ wchCARRIAGERETURN = 0x0000; wchLINEFEED = 0x0000; } else { wchCARRIAGERETURN = UNICODE_CARRIAGERETURN; wchLINEFEED = UNICODE_LINEFEED; } CurChar = TmpClipboardData; bMungeData = (GetKeyState(VK_SHIFT) & KEY_PRESSED) == 0; for (i=0;iSelectionRect.Left; SourcePoint.Y = Console->SelectionRect.Top + i; TargetSize2.X = TargetSize.X; TargetSize2.Y = 1; SmallRect2.Left = SourcePoint.X; SmallRect2.Top = SourcePoint.Y; SmallRect2.Right = SourcePoint.X + TargetSize2.X - 1; SmallRect2.Bottom = SourcePoint.Y; TargetPoint = SourcePoint; StringLength = TargetSize2.X; BisectClipbrd(StringLength,TargetPoint,ScreenInfo,&SmallRect2); SourcePoint.X = SmallRect2.Left; SourcePoint.Y = SmallRect2.Top; TargetSize2.X = SmallRect2.Right - SmallRect2.Left + 1; TargetSize2.Y = 1; TargetRect.Left = TargetRect.Top = TargetRect.Bottom = 0; TargetRect.Right = (SHORT)(TargetSize2.X-1); ReadRectFromScreenBuffer(ScreenInfo, SourcePoint, Selection, TargetSize2, &TargetRect); CurCharInfo = Selection; for (j=0;jAttributes & COMMON_LVB_TRAILING_BYTE)) *CurChar++ = CurCharInfo->Char.UnicodeChar; } // trim trailing spaces if (bMungeData) { CurChar--; while ((CurChar >= pwchLineStart) && (*CurChar == UNICODE_SPACE)) CurChar--; CurChar++; *CurChar++ = wchCARRIAGERETURN; *CurChar++ = wchLINEFEED; } } } else { #endif CurCharInfo = Selection; CurChar = CharBuf = GlobalLock(ClipboardDataHandle); bFalseUnicode = ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) && !(Console->FullScreenFlags & CONSOLE_FULLSCREEN)); bMungeData = (GetKeyState(VK_SHIFT) & KEY_PRESSED) == 0; for (i=0;iChar.UnicodeChar; if (*CurChar == 0) { *CurChar = UNICODE_SPACE; } } // trim trailing spaces if (bMungeData) { CurChar--; while ((CurChar >= pwchLineStart) && (*CurChar == UNICODE_SPACE)) CurChar--; CurChar++; } if (bFalseUnicode) { FalseUnicodeToRealUnicode(pwchLineStart, (ULONG)(CurChar - pwchLineStart), Console->OutputCP); } if (bMungeData) { *CurChar++ = UNICODE_CARRIAGERETURN; *CurChar++ = UNICODE_LINEFEED; } } #if defined(FE_SB) } #endif if (bMungeData) { if (TargetSize.Y) CurChar -= 2; // don't put CRLF on last line } *CurChar = '\0'; // null terminate #if defined(FE_SB) if (CONSOLE_IS_DBCS_CP(Console)) { // extra 4 is for CRLF and DBCS Reserved, extra 1 is for null ClipboardDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (sizeof(WCHAR) * TargetSize.Y * (TargetSize.X+(4*sizeof(WCHAR)))) + (1*sizeof(WCHAR))); if (ClipboardDataHandle == NULL) { ConsoleHeapFree(Selection); ConsoleHeapFree(TmpClipboardData); return; } CharBuf = GlobalLock(ClipboardDataHandle); RtlCopyMemory(CharBuf,TmpClipboardData,ConsoleHeapSize(TmpClipboardData)); CurChar = CharBuf + (CurChar - TmpClipboardData); if (wchCARRIAGERETURN == 0x0000) { /* * We have False Unicode, so we temporarily represented CRLFs with * 0x0000s to avoid undesirable conversions (above). * Convert to Real Unicode and restore real CRLFs. */ PWCHAR pwch; FalseUnicodeToRealUnicode(CharBuf, (ULONG)(CurChar - CharBuf), Console->OutputCP ); for (pwch = CharBuf; pwch < CurChar; pwch++) { if ((*pwch == 0x0000) && (pwch[1] == 0x0000)) { *pwch++ = UNICODE_CARRIAGERETURN; *pwch = UNICODE_LINEFEED; } } } } #endif GlobalUnlock(ClipboardDataHandle); #if defined(FE_SB) if (TmpClipboardData) ConsoleHeapFree(TmpClipboardData); #endif ConsoleHeapFree(Selection); Success = OpenClipboard(Console->hWnd); if (!Success) { GlobalFree(ClipboardDataHandle); return; } Success = EmptyClipboard(); if (!Success) { GlobalFree(ClipboardDataHandle); return; } SetClipboardData(CF_UNICODETEXT,ClipboardDataHandle); CloseClipboard(); // Close clipboard } else { HBITMAP hBitmapTarget, hBitmapOld; HDC hDCMem; HPALETTE hPaletteOld; int Height; NtWaitForSingleObject(ScreenInfo->BufferInfo.GraphicsInfo.hMutex, FALSE, NULL); hDCMem = CreateCompatibleDC(Console->hDC); hBitmapTarget = CreateCompatibleBitmap(Console->hDC, TargetSize.X, TargetSize.Y); if (hBitmapTarget) { hBitmapOld = SelectObject(hDCMem, hBitmapTarget); if (ScreenInfo->hPalette) { hPaletteOld = SelectPalette(hDCMem, ScreenInfo->hPalette, FALSE); } MyInvert(Console,&Console->SelectionRect); // if (DIB is a top-down) // ySrc = abs(height) - rect.bottom - 1; // else // ySrc = rect.Bottom. // Height = ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo->bmiHeader.biHeight; StretchDIBits(hDCMem, 0, 0, TargetSize.X, TargetSize.Y, Console->SelectionRect.Left + ScreenInfo->Window.Left, (Height < 0) ? -Height - (Console->SelectionRect.Bottom + ScreenInfo->Window.Top) - 1 : Console->SelectionRect.Bottom + ScreenInfo->Window.Top, TargetSize.X, TargetSize.Y, ScreenInfo->BufferInfo.GraphicsInfo.BitMap, ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo, ScreenInfo->BufferInfo.GraphicsInfo.dwUsage, SRCCOPY); MyInvert(Console,&Console->SelectionRect); if (ScreenInfo->hPalette) { SelectPalette(hDCMem, hPaletteOld, FALSE); } SelectObject(hDCMem, hBitmapOld); OpenClipboard(Console->hWnd); EmptyClipboard(); SetClipboardData(CF_BITMAP,hBitmapTarget); CloseClipboard(); } DeleteDC(hDCMem); NtReleaseMutant(ScreenInfo->BufferInfo.GraphicsInfo.hMutex, NULL); } } VOID DoCopy( IN PCONSOLE_INFORMATION Console ) { StoreSelection(Console); // store selection in clipboard ClearSelection(Console); // clear selection in console } VOID ColorSelection( IN PCONSOLE_INFORMATION Console, IN PSMALL_RECT Rect, IN ULONG Attr ) { PSCREEN_INFORMATION ScreenInfo; COORD TargetSize, Target; DWORD Written; ASSERT( Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER); ASSERT( Attr <= 0xff); // // See if there is a selection to get // if (!(Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY)) { return; } // // read selection rectangle, assumed already clipped to buffer. // ScreenInfo = Console->CurrentScreenBuffer; TargetSize.X = WINDOW_SIZE_X(&Console->SelectionRect); TargetSize.Y = WINDOW_SIZE_Y(&Console->SelectionRect); // // Now color the selection a line at a time, since this seems to be // the only way to do it? // Target.X = Rect->Left; Target.Y = Rect->Top; for ( ; (Target.Y < Rect->Top + TargetSize.Y); ++Target.Y) { Written = TargetSize.X; (VOID)FillOutput( Console->CurrentScreenBuffer, (USHORT)Attr, Target, CONSOLE_ATTRIBUTE, &Written); } } /*++ Routine Description: This routine pastes given Unicode string into the console window. Arguments: Console - Pointer to CONSOLE_INFORMATION structure pwStr - Unicode string that is pasted to the console window DataSize - Size of the Unicode String in characters Return Value: None --*/ VOID DoStringPaste( IN PCONSOLE_INFORMATION Console, IN PWCHAR pwStr, IN UINT DataSize ) { PINPUT_RECORD StringData,CurRecord; PWCHAR CurChar; WCHAR Char; DWORD i; DWORD ChunkSize,j; ULONG EventsWritten; if(!pwStr) { return; } if (DataSize > DATA_CHUNK_SIZE) { ChunkSize = DATA_CHUNK_SIZE; } else { ChunkSize = DataSize; } // // allocate space to copy data. // StringData = ConsoleHeapAlloc(TMP_TAG, ChunkSize * sizeof(INPUT_RECORD) * 8); // 8 is maximum number of events per char if (StringData == NULL) { return; } // // transfer data to the input buffer in chunks // CurChar = pwStr; // LATER remove this for (j = 0; j < DataSize; j += ChunkSize) { if (ChunkSize > DataSize - j) { ChunkSize = DataSize - j; } CurRecord = StringData; for (i = 0, EventsWritten = 0; i < ChunkSize; i++) { // filter out LF if not first char and preceded by CR Char = *CurChar; if (Char != UNICODE_LINEFEED || (i==0 && j==0) || (*(CurChar-1)) != UNICODE_CARRIAGERETURN) { SHORT KeyState; BYTE KeyFlags; BOOL AltGr=FALSE; BOOL Shift=FALSE; if (Char == 0) { j = DataSize; break; } KeyState = VkKeyScan(Char); #if defined(FE_SB) if (CONSOLE_IS_DBCS_ENABLED() && (KeyState == -1)) { WORD CharType; // // Determine DBCS character because these character doesn't know by VkKeyScan. // GetStringTypeW(CT_CTYPE3) & C3_ALPHA can determine all linguistic characters. // However, this is not include symbolic character for DBCS. // IsConsoleFullWidth can help for DBCS symbolic character. // GetStringTypeW(CT_CTYPE3,&Char,1,&CharType); if ((CharType & C3_ALPHA) || IsConsoleFullWidth(Console->hDC,Console->OutputCP,Char)) { KeyState = 0; } } #endif // if VkKeyScanW fails (char is not in kbd layout), we must // emulate the key being input through the numpad if (KeyState == -1) { CHAR CharString[4]; UCHAR OemChar; PCHAR pCharString; ConvertToOem(Console->OutputCP, &Char, 1, &OemChar, 1 ); _itoa(OemChar, CharString, 10); EventsWritten++; LoadKeyEvent(CurRecord,TRUE,0,VK_MENU,0x38,LEFT_ALT_PRESSED); CurRecord++; for (pCharString=CharString;*pCharString;pCharString++) { WORD wVirtualKey, wScancode; EventsWritten++; wVirtualKey = *pCharString-'0'+VK_NUMPAD0; wScancode = (WORD)MapVirtualKey(wVirtualKey, 0); LoadKeyEvent(CurRecord,TRUE,0,wVirtualKey,wScancode,LEFT_ALT_PRESSED); CurRecord++; EventsWritten++; LoadKeyEvent(CurRecord,FALSE,0,wVirtualKey,wScancode,LEFT_ALT_PRESSED); CurRecord++; } EventsWritten++; LoadKeyEvent(CurRecord,FALSE,Char,VK_MENU,0x38,0); CurRecord++; } else { KeyFlags = HIBYTE(KeyState); // handle yucky alt-gr keys if ((KeyFlags & 6) == 6) { AltGr=TRUE; EventsWritten++; LoadKeyEvent(CurRecord,TRUE,0,VK_MENU,0x38,ENHANCED_KEY | LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED); CurRecord++; } else if (KeyFlags & 1) { Shift=TRUE; EventsWritten++; LoadKeyEvent(CurRecord,TRUE,0,VK_SHIFT,0x2a,SHIFT_PRESSED); CurRecord++; } EventsWritten++; LoadKeyEvent(CurRecord, TRUE, Char, LOBYTE(KeyState), (WORD)MapVirtualKey(CurRecord->Event.KeyEvent.wVirtualKeyCode,0), 0); if (KeyFlags & 1) CurRecord->Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; if (KeyFlags & 2) CurRecord->Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; if (KeyFlags & 4) CurRecord->Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED; CurRecord++; EventsWritten++; *CurRecord = *(CurRecord-1); CurRecord->Event.KeyEvent.bKeyDown = FALSE; CurRecord++; // handle yucky alt-gr keys if (AltGr) { EventsWritten++; LoadKeyEvent(CurRecord,FALSE,0,VK_MENU,0x38,ENHANCED_KEY); CurRecord++; } else if (Shift) { EventsWritten++; LoadKeyEvent(CurRecord,FALSE,0,VK_SHIFT,0x2a,0); CurRecord++; } } } CurChar++; } EventsWritten = WriteInputBuffer(Console, &Console->InputBuffer, StringData, EventsWritten ); } ConsoleHeapFree(StringData); return; } VOID DoPaste( IN PCONSOLE_INFORMATION Console ) /*++ Perform paste request into old app by pulling out clipboard contents and writing them to the console's input buffer --*/ { BOOL Success; HANDLE ClipboardDataHandle; if (Console->Flags & CONSOLE_SCROLLING) { return; } // // Get paste data from clipboard // Success = OpenClipboard(Console->hWnd); if (!Success) return; if (Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) { PWCHAR pwstr; ClipboardDataHandle = GetClipboardData(CF_UNICODETEXT); if (ClipboardDataHandle == NULL) { CloseClipboard(); // Close clipboard return; } pwstr = GlobalLock(ClipboardDataHandle); DoStringPaste(Console,pwstr,(ULONG)GlobalSize(ClipboardDataHandle)/sizeof(WCHAR)); GlobalUnlock(ClipboardDataHandle); } else { HBITMAP hBitmapSource,hBitmapTarget; HDC hDCMemSource,hDCMemTarget; BITMAP bm; PSCREEN_INFORMATION ScreenInfo; hBitmapSource = GetClipboardData(CF_BITMAP); if (hBitmapSource) { ScreenInfo = Console->CurrentScreenBuffer; NtWaitForSingleObject(ScreenInfo->BufferInfo.GraphicsInfo.hMutex, FALSE, NULL); hBitmapTarget = CreateDIBitmap(Console->hDC, &ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo->bmiHeader, CBM_INIT, ScreenInfo->BufferInfo.GraphicsInfo.BitMap, ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo, ScreenInfo->BufferInfo.GraphicsInfo.dwUsage ); if (hBitmapTarget) { hDCMemTarget = CreateCompatibleDC ( Console->hDC ); if (hDCMemTarget != NULL) { hDCMemSource = CreateCompatibleDC ( Console->hDC ); if (hDCMemSource != NULL) { SelectObject( hDCMemTarget, hBitmapTarget ); SelectObject( hDCMemSource, hBitmapSource ); GetObjectW(hBitmapSource, sizeof (BITMAP), (LPSTR) &bm); BitBlt ( hDCMemTarget, 0, 0, bm.bmWidth, bm.bmHeight, hDCMemSource, 0, 0, SRCCOPY); GetObjectW(hBitmapTarget, sizeof (BITMAP), (LPSTR) &bm); // copy the bits from the DC to memory GetDIBits(hDCMemTarget, hBitmapTarget, 0, bm.bmHeight, ScreenInfo->BufferInfo.GraphicsInfo.BitMap, ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo, ScreenInfo->BufferInfo.GraphicsInfo.dwUsage); DeleteDC(hDCMemSource); } DeleteDC(hDCMemTarget); } DeleteObject(hBitmapTarget); InvalidateRect(Console->hWnd,NULL,FALSE); // force repaint } NtReleaseMutant(ScreenInfo->BufferInfo.GraphicsInfo.hMutex, NULL); } } CloseClipboard(); return; } VOID InitSelection( IN PCONSOLE_INFORMATION Console ) /*++ This routine initializes the selection process. It is called when the user selects the Mark option from the system menu. --*/ { COORD Position; PSCREEN_INFORMATION ScreenInfo; // // if already selecting, cancel selection. // if (Console->Flags & CONSOLE_SELECTING) { if (Console->SelectionFlags & CONSOLE_MOUSE_SELECTION) { CancelMouseSelection(Console); } else { CancelKeySelection(Console,FALSE); } } // // set flags // Console->Flags |= CONSOLE_SELECTING; Console->SelectionFlags = 0; // // save old cursor position and // make console cursor into selection cursor. // ScreenInfo = Console->CurrentScreenBuffer; Console->TextCursorPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition; Console->TextCursorVisible = (BOOLEAN)ScreenInfo->BufferInfo.TextInfo.CursorVisible; Console->TextCursorSize = ScreenInfo->BufferInfo.TextInfo.CursorSize; ConsoleHideCursor(ScreenInfo); SetCursorInformation(ScreenInfo, 100, TRUE ); Position.X = ScreenInfo->Window.Left; Position.Y = ScreenInfo->Window.Top; SetCursorPosition(ScreenInfo, Position, TRUE ); ConsoleShowCursor(ScreenInfo); // // init select rect // Console->SelectionAnchor = Position; // // set win text // SetWinText(Console,msgMarkMode,TRUE); } VOID DoMark( IN PCONSOLE_INFORMATION Console ) { InitSelection(Console); // initialize selection } VOID DoSelectAll( IN PCONSOLE_INFORMATION Console ) { COORD Position; COORD WindowOrigin; PSCREEN_INFORMATION ScreenInfo; // clear any old selections if (Console->Flags & CONSOLE_SELECTING) { ClearSelection(Console); } // save the old window position ScreenInfo = Console->CurrentScreenBuffer; WindowOrigin.X = ScreenInfo->Window.Left; WindowOrigin.Y = ScreenInfo->Window.Top; // initialize selection Console->Flags |= CONSOLE_SELECTING; Console->SelectionFlags = CONSOLE_MOUSE_SELECTION | CONSOLE_SELECTION_NOT_EMPTY; Position.X = Position.Y = 0; InitializeMouseSelection(Console, Position); MyInvert(Console,&Console->SelectionRect); SetWinText(Console,msgSelectMode,TRUE); // extend selection Position.X = ScreenInfo->ScreenBufferSize.X - 1; Position.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y; ExtendSelection(Console, Position); // restore the old window position SetWindowOrigin(ScreenInfo, TRUE, WindowOrigin); } VOID DoScroll( IN PCONSOLE_INFORMATION Console ) { if (!(Console->Flags & CONSOLE_SCROLLING)) { SetWinText(Console,msgScrollMode,TRUE); Console->Flags |= CONSOLE_SCROLLING; } } VOID ClearScroll( IN PCONSOLE_INFORMATION Console ) { SetWinText(Console,msgScrollMode,FALSE); Console->Flags &= ~CONSOLE_SCROLLING; } VOID ScrollIfNecessary( IN PCONSOLE_INFORMATION Console, IN PSCREEN_INFORMATION ScreenInfo ) { POINT CursorPos; RECT ClientRect; COORD MousePosition; if (Console->Flags & CONSOLE_SELECTING && Console->SelectionFlags & CONSOLE_MOUSE_DOWN) { if (!GetCursorPos(&CursorPos)) { return; } if (!GetClientRect(Console->hWnd,&ClientRect)) { return; } MapWindowPoints(Console->hWnd,NULL,(LPPOINT)&ClientRect,2); if (!(PtInRect(&ClientRect,CursorPos))) { ScreenToClient(Console->hWnd,&CursorPos); MousePosition.X = (SHORT)CursorPos.x; MousePosition.Y = (SHORT)CursorPos.y; if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { MousePosition.X /= SCR_FONTSIZE(ScreenInfo).X; MousePosition.Y /= SCR_FONTSIZE(ScreenInfo).Y; } MousePosition.X += ScreenInfo->Window.Left; MousePosition.Y += ScreenInfo->Window.Top; ExtendSelection(Console, MousePosition ); } } }