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
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
|
|
);
|
|
}
|
|
}
|
|
}
|