Windows2000/private/ntos/w32/ntcon/server/clipbrd.c
2020-09-30 17:12:32 +02:00

1251 lines
38 KiB
C

/*++
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
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);
}
}
VOID
CancelMouseSelection(
IN PCONSOLE_INFORMATION Console
)
/*++
This routine terminates a mouse selection.
--*/
{
// 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();
}
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
Console->SelectionAnchor = MousePosition;
Console->SelectionRect.Left = Console->SelectionRect.Right = Console->SelectionAnchor.X;
Console->SelectionRect.Top = Console->SelectionRect.Bottom = Console->SelectionAnchor.Y;
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 = (PWCHAR)ConsoleHeapAlloc(MAKE_TAG(TMP_DBCS_TAG), (sizeof(WCHAR) * TargetSize.Y * (TargetSize.X + iExtra) + sizeof(WCHAR)));
if (TmpClipboardData == NULL) {
return;
}
} else {
TmpClipboardData = NULL;
}
Selection = (PCHAR_INFO)ConsoleHeapAlloc(MAKE_TAG(TMP_TAG), sizeof(CHAR_INFO) * (TargetSize.X + iExtra) * TargetSize.Y * iFeReserve);
if (Selection == NULL) {
if (TmpClipboardData)
ConsoleHeapFree(TmpClipboardData);
return;
}
#else
Selection = (PCHAR_INFO)ConsoleHeapAlloc(MAKE_TAG(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
}
/*++
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 = (PINPUT_RECORD)ConsoleHeapAlloc(MAKE_TAG(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 sucking 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);
hDCMemSource = CreateCompatibleDC(Console->hDC);
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;
Console->SelectionAnchor.X = Console->SelectionRect.Left = Console->SelectionRect.Right = 0;
Console->SelectionAnchor.Y = Console->SelectionRect.Top = Console->SelectionRect.Bottom = 0;
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
);
}
}
}