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.
585 lines
17 KiB
585 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cursor.c
|
|
|
|
Abstract:
|
|
|
|
This file implements the NT console server cursor routines.
|
|
|
|
Author:
|
|
|
|
Therese Stowell (thereses) 5-Dec-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//#define PROFILE_GDI
|
|
#ifdef PROFILE_GDI
|
|
LONG InvertCount;
|
|
#define INVERT_CALL InvertCount++
|
|
#else
|
|
#define INVERT_CALL
|
|
#endif
|
|
|
|
extern UINT guCaretBlinkTime;
|
|
|
|
VOID
|
|
InvertPixels(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine inverts the cursor pixels, making it either visible or
|
|
invisible.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifdef FE_SB
|
|
if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)) {
|
|
PCONVERSIONAREA_INFORMATION ConvAreaInfo;
|
|
SMALL_RECT Region;
|
|
SMALL_RECT CursorRegion;
|
|
SMALL_RECT ClippedRegion;
|
|
|
|
#ifdef DBG_KATTR
|
|
// BeginKAttrCheck(ScreenInfo);
|
|
#endif
|
|
|
|
ConvAreaInfo = ScreenInfo->Console->ConsoleIme.ConvAreaRoot;
|
|
CursorRegion.Left = CursorRegion.Right = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
|
|
CursorRegion.Top = CursorRegion.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
|
|
while (ConvAreaInfo) {
|
|
|
|
if ((ConvAreaInfo->ConversionAreaMode & (CA_HIDDEN+CA_HIDE_FOR_SCROLL))==0) {
|
|
//
|
|
// Do clipping region
|
|
//
|
|
Region.Left = ScreenInfo->Window.Left +
|
|
ConvAreaInfo->CaInfo.rcViewCaWindow.Left +
|
|
ConvAreaInfo->CaInfo.coordConView.X;
|
|
Region.Right = Region.Left +
|
|
(ConvAreaInfo->CaInfo.rcViewCaWindow.Right -
|
|
ConvAreaInfo->CaInfo.rcViewCaWindow.Left);
|
|
Region.Top = ScreenInfo->Window.Top +
|
|
ConvAreaInfo->CaInfo.rcViewCaWindow.Top +
|
|
ConvAreaInfo->CaInfo.coordConView.Y;
|
|
Region.Bottom = Region.Top +
|
|
(ConvAreaInfo->CaInfo.rcViewCaWindow.Bottom -
|
|
ConvAreaInfo->CaInfo.rcViewCaWindow.Top);
|
|
ClippedRegion.Left = max(Region.Left, ScreenInfo->Window.Left);
|
|
ClippedRegion.Top = max(Region.Top, ScreenInfo->Window.Top);
|
|
ClippedRegion.Right = min(Region.Right, ScreenInfo->Window.Right);
|
|
ClippedRegion.Bottom = min(Region.Bottom, ScreenInfo->Window.Bottom);
|
|
if (ClippedRegion.Right < ClippedRegion.Left ||
|
|
ClippedRegion.Bottom < ClippedRegion.Top) {
|
|
;
|
|
}
|
|
else {
|
|
Region = ClippedRegion;
|
|
ClippedRegion.Left = max(Region.Left, CursorRegion.Left);
|
|
ClippedRegion.Top = max(Region.Top, CursorRegion.Top);
|
|
ClippedRegion.Right = min(Region.Right, CursorRegion.Right);
|
|
ClippedRegion.Bottom = min(Region.Bottom, CursorRegion.Bottom);
|
|
if (ClippedRegion.Right < ClippedRegion.Left ||
|
|
ClippedRegion.Bottom < ClippedRegion.Top) {
|
|
;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
ConvAreaInfo = ConvAreaInfo->ConvAreaNext;
|
|
}
|
|
}
|
|
#endif // FE_SB
|
|
|
|
{
|
|
ULONG CursorYSize;
|
|
POLYPATBLT PolyData;
|
|
#ifdef FE_SB
|
|
SHORT RowIndex;
|
|
PROW Row;
|
|
COORD TargetPoint;
|
|
int iTrailing = 0;
|
|
int iDBCursor = 1;
|
|
#endif
|
|
|
|
INVERT_CALL;
|
|
CursorYSize = ScreenInfo->BufferInfo.TextInfo.CursorYSize;
|
|
if (ScreenInfo->BufferInfo.TextInfo.DoubleCursor) {
|
|
if (ScreenInfo->BufferInfo.TextInfo.CursorSize > 50)
|
|
CursorYSize = CursorYSize >> 1;
|
|
else
|
|
CursorYSize = CursorYSize << 1;
|
|
}
|
|
#ifdef FE_SB
|
|
if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
|
|
{
|
|
TargetPoint = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
|
|
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
|
|
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
|
|
ASSERT(Row);
|
|
|
|
if ((Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE) &&
|
|
ScreenInfo->BufferInfo.TextInfo.CursorDBEnable) {
|
|
|
|
iTrailing = 1;
|
|
iDBCursor = 2;
|
|
} else if ((Row->CharRow.KAttrs[TargetPoint.X] & ATTR_LEADING_BYTE) &&
|
|
ScreenInfo->BufferInfo.TextInfo.CursorDBEnable) {
|
|
|
|
iDBCursor = 2;
|
|
}
|
|
}
|
|
|
|
PolyData.x = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X -
|
|
ScreenInfo->Window.Left - iTrailing) * SCR_FONTSIZE(ScreenInfo).X;
|
|
PolyData.y = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y -
|
|
ScreenInfo->Window.Top) * SCR_FONTSIZE(ScreenInfo).Y +
|
|
(CURSOR_Y_OFFSET_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,CursorYSize));
|
|
PolyData.cx = SCR_FONTSIZE(ScreenInfo).X * iDBCursor;
|
|
PolyData.cy = CursorYSize;
|
|
#else
|
|
PolyData.x = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-ScreenInfo->Window.Left)*SCR_FONTSIZE(ScreenInfo).X;
|
|
PolyData.y = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y-ScreenInfo->Window.Top)*SCR_FONTSIZE(ScreenInfo).Y+(CURSOR_Y_OFFSET_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,CursorYSize));
|
|
PolyData.cx = SCR_FONTSIZE(ScreenInfo).X;
|
|
PolyData.cy = CursorYSize;
|
|
#endif
|
|
PolyData.BrClr.hbr = GetStockObject(LTGRAY_BRUSH);
|
|
|
|
PolyPatBlt(ScreenInfo->Console->hDC, PATINVERT, &PolyData, 1, PPB_BRUSH);
|
|
|
|
GdiFlush();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ConsoleShowCursor(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine makes the cursor visible both in the data structures
|
|
and on the screen.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
ASSERT (ScreenInfo->BufferInfo.TextInfo.UpdatingScreen>0);
|
|
if (--ScreenInfo->BufferInfo.TextInfo.UpdatingScreen == 0) {
|
|
ScreenInfo->BufferInfo.TextInfo.CursorOn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ConsoleHideCursor(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine makes the cursor invisible both in the data structures
|
|
and on the screen.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
if (++ScreenInfo->BufferInfo.TextInfo.UpdatingScreen == 1) {
|
|
if (ScreenInfo->BufferInfo.TextInfo.CursorVisible &&
|
|
ScreenInfo->BufferInfo.TextInfo.CursorOn &&
|
|
ScreenInfo->Console->CurrentScreenBuffer == ScreenInfo &&
|
|
!(ScreenInfo->Console->Flags & CONSOLE_IS_ICONIC)) {
|
|
InvertPixels(ScreenInfo);
|
|
ScreenInfo->BufferInfo.TextInfo.CursorOn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SetCursorInformation(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
ULONG Size,
|
|
BOOLEAN Visible
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the cursor size and visibility both in the data structures
|
|
and on the screen.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
Size - cursor size
|
|
|
|
Visible - cursor visibility
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
ConsoleHideCursor(ScreenInfo);
|
|
ScreenInfo->BufferInfo.TextInfo.CursorSize = Size;
|
|
ScreenInfo->BufferInfo.TextInfo.CursorVisible = Visible;
|
|
ScreenInfo->BufferInfo.TextInfo.CursorYSize = (WORD)CURSOR_SIZE_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,ScreenInfo->BufferInfo.TextInfo.CursorSize);
|
|
#ifdef i386
|
|
if ((!(ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)) &&
|
|
ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
|
|
SetCursorInformationHW(ScreenInfo,Size,Visible);
|
|
}
|
|
#endif
|
|
ConsoleShowCursor(ScreenInfo);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SetCursorMode(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
BOOLEAN DoubleCursor
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets a flag saying whether the cursor should be displayed
|
|
with it's default size or it should be modified to indicate the
|
|
insert/overtype mode has changed.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
DoubleCursor - should we indicated non-normal mode
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
if ((ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) &&
|
|
(ScreenInfo->BufferInfo.TextInfo.DoubleCursor != DoubleCursor)) {
|
|
ConsoleHideCursor(ScreenInfo);
|
|
ScreenInfo->BufferInfo.TextInfo.DoubleCursor = DoubleCursor;
|
|
#ifdef i386
|
|
if ((!(ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)) &&
|
|
ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
|
|
SetCursorInformationHW(ScreenInfo,
|
|
ScreenInfo->BufferInfo.TextInfo.CursorSize,
|
|
ScreenInfo->BufferInfo.TextInfo.CursorVisible);
|
|
}
|
|
#endif
|
|
ConsoleShowCursor(ScreenInfo);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
CursorTimerRoutine(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the timer in the console with the focus
|
|
goes off. It blinks the cursor.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (!(ScreenInfo->Console->Flags & CONSOLE_HAS_FOCUS))
|
|
return;
|
|
|
|
if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
|
|
//
|
|
// Update the cursor pos in USER so accessibility will work
|
|
//
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.CursorMoved) {
|
|
|
|
CONSOLE_CARET_INFO ConsoleCaretInfo;
|
|
DWORD dwFlags = 0;
|
|
|
|
ScreenInfo->BufferInfo.TextInfo.CursorMoved = FALSE;
|
|
ConsoleCaretInfo.hwnd = ScreenInfo->Console->hWnd;
|
|
ConsoleCaretInfo.rc.left = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X - ScreenInfo->Window.Left) * SCR_FONTSIZE(ScreenInfo).X;
|
|
ConsoleCaretInfo.rc.top = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - ScreenInfo->Window.Top) * SCR_FONTSIZE(ScreenInfo).Y;
|
|
ConsoleCaretInfo.rc.right = ConsoleCaretInfo.rc.left + SCR_FONTSIZE(ScreenInfo).X;
|
|
ConsoleCaretInfo.rc.bottom = ConsoleCaretInfo.rc.top + SCR_FONTSIZE(ScreenInfo).Y;
|
|
NtUserConsoleControl(ConsoleSetCaretInfo,
|
|
&ConsoleCaretInfo,
|
|
sizeof(ConsoleCaretInfo));
|
|
if (ScreenInfo->BufferInfo.TextInfo.CursorVisible) {
|
|
dwFlags |= CONSOLE_CARET_VISIBLE;
|
|
}
|
|
if (ScreenInfo->Console->Flags & CONSOLE_SELECTING) {
|
|
dwFlags |= CONSOLE_CARET_SELECTION;
|
|
}
|
|
ConsoleNotifyWinEvent(ScreenInfo->Console,
|
|
EVENT_CONSOLE_CARET,
|
|
dwFlags,
|
|
PACKCOORD(ScreenInfo->BufferInfo.TextInfo.CursorPosition));
|
|
}
|
|
|
|
// if the DelayCursor flag has been set, wait one more tick before toggle.
|
|
// This is used to guarantee the cursor is on for a finite period of time
|
|
// after a move and off for a finite period of time after a WriteString
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.DelayCursor) {
|
|
ScreenInfo->BufferInfo.TextInfo.DelayCursor = FALSE;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Don't blink the cursor for remote sessions.
|
|
//
|
|
if ((NtCurrentPeb()->SessionId != WTSGetActiveConsoleSessionId() ||
|
|
(guCaretBlinkTime == (UINT)-1)) &&
|
|
ScreenInfo->BufferInfo.TextInfo.CursorOn) {
|
|
return;
|
|
}
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.CursorVisible &&
|
|
!ScreenInfo->BufferInfo.TextInfo.UpdatingScreen) {
|
|
InvertPixels(ScreenInfo);
|
|
ScreenInfo->BufferInfo.TextInfo.CursorOn = !ScreenInfo->BufferInfo.TextInfo.CursorOn;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef i386
|
|
NTSTATUS
|
|
SetCursorPositionHW(
|
|
IN OUT PSCREEN_INFORMATION ScreenInfo,
|
|
IN COORD Position
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine moves the cursor.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - Pointer to screen buffer information.
|
|
|
|
Position - Contains the new position of the cursor in screen buffer
|
|
coordinates.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if defined(FE_SB)
|
|
FSVIDEO_CURSOR_POSITION CursorPosition;
|
|
SHORT RowIndex;
|
|
PROW Row;
|
|
COORD TargetPoint;
|
|
|
|
if (ScreenInfo->ConvScreenInfo)
|
|
return STATUS_SUCCESS;
|
|
|
|
TargetPoint.X = Position.X;
|
|
TargetPoint.Y = Position.Y;
|
|
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
|
|
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
|
|
|
|
if (!CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
|
|
CursorPosition.dwType = CHAR_TYPE_SBCS;
|
|
else if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE)
|
|
CursorPosition.dwType = CHAR_TYPE_TRAILING;
|
|
else if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_LEADING_BYTE)
|
|
CursorPosition.dwType = CHAR_TYPE_LEADING;
|
|
else
|
|
CursorPosition.dwType = CHAR_TYPE_SBCS;
|
|
|
|
// set cursor position
|
|
|
|
CursorPosition.Coord.Column = Position.X - ScreenInfo->Window.Left;
|
|
CursorPosition.Coord.Row = Position.Y - ScreenInfo->Window.Top;
|
|
#else
|
|
VIDEO_CURSOR_POSITION CursorPosition;
|
|
|
|
// set cursor position
|
|
|
|
CursorPosition.Column = Position.X - ScreenInfo->Window.Left;
|
|
CursorPosition.Row = Position.Y - ScreenInfo->Window.Top;
|
|
#endif
|
|
|
|
return GdiFullscreenControl(FullscreenControlSetCursorPosition,
|
|
(PVOID)&CursorPosition,
|
|
sizeof(CursorPosition),
|
|
NULL,
|
|
0);
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
SetCursorPosition(
|
|
IN OUT PSCREEN_INFORMATION ScreenInfo,
|
|
IN COORD Position,
|
|
IN BOOL TurnOn
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the cursor position in the data structures and on
|
|
the screen.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - pointer to screen info structure.
|
|
|
|
Position - new position of cursor
|
|
|
|
TurnOn - true if cursor should be left on, false if should be left off
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Ensure that the cursor position is within the constraints of the screen
|
|
// buffer.
|
|
//
|
|
if (Position.X >= ScreenInfo->ScreenBufferSize.X ||
|
|
Position.Y >= ScreenInfo->ScreenBufferSize.Y ||
|
|
Position.X < 0 || Position.Y < 0) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ConsoleHideCursor(ScreenInfo);
|
|
ScreenInfo->BufferInfo.TextInfo.CursorPosition = Position;
|
|
#ifdef i386
|
|
if ((!(ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)) &&
|
|
ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
|
|
SetCursorPositionHW(ScreenInfo,Position);
|
|
}
|
|
#endif
|
|
ConsoleShowCursor(ScreenInfo);
|
|
|
|
// if we have the focus, adjust the cursor state
|
|
|
|
if (ScreenInfo->Console->Flags & CONSOLE_HAS_FOCUS) {
|
|
|
|
if (TurnOn) {
|
|
ScreenInfo->BufferInfo.TextInfo.DelayCursor = FALSE;
|
|
CursorTimerRoutine(ScreenInfo);
|
|
} else {
|
|
ScreenInfo->BufferInfo.TextInfo.DelayCursor = TRUE;
|
|
}
|
|
ScreenInfo->BufferInfo.TextInfo.CursorMoved = TRUE;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#ifdef i386
|
|
NTSTATUS
|
|
SetCursorInformationHW(
|
|
PSCREEN_INFORMATION ScreenInfo,
|
|
ULONG Size,
|
|
BOOLEAN Visible
|
|
)
|
|
{
|
|
VIDEO_CURSOR_ATTRIBUTES CursorAttr;
|
|
ULONG FontSizeY;
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.DoubleCursor) {
|
|
if (Size > 50)
|
|
Size = Size >> 1;
|
|
else
|
|
Size = Size << 1;
|
|
}
|
|
ASSERT (Size <= 100 && Size > 0);
|
|
FontSizeY = CONSOLE_WINDOW_SIZE_Y(ScreenInfo) > 25 ? 8 : 16;
|
|
CursorAttr.Height = (USHORT)CURSOR_PERCENTAGE_TO_TOP_SCAN_LINE(FontSizeY,Size);
|
|
CursorAttr.Width = 31;
|
|
CursorAttr.Enable = Visible;
|
|
|
|
return GdiFullscreenControl(FullscreenControlSetCursorAttributes,
|
|
(PVOID)&CursorAttr,
|
|
sizeof(CursorAttr),
|
|
NULL,
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
#endif
|