Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1368 lines
42 KiB

/*++
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
);
}
}
}