|
|
/*++
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; i<TargetSize.Y; i++) { for (j=0; j<TargetSize.X; j++,CurCharInfo++) { CurCharInfo->Char.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;i<TargetSize.Y;i++) { PWCHAR pwchLineStart = CurChar;
SourcePoint.X = Console->SelectionRect.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;j<TargetSize2.X;j++,CurCharInfo++) { if (!(CurCharInfo->Attributes & 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;i<TargetSize.Y;i++) { PWCHAR pwchLineStart = CurChar;
for (j=0;j<TargetSize.X;j++,CurCharInfo++,CurChar++) { *CurChar = CurCharInfo->Char.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 ); } } }
|