OcConsoleLib: Fix cursor colour and visibility in Shell

This commit is contained in:
vit9696 2020-02-07 00:50:37 +03:00
parent a58cacdf16
commit e77d4d8f82

View File

@ -158,9 +158,6 @@ STATIC UINTN mConsoleWidth;
STATIC UINTN mConsoleHeight;
STATIC UINTN mConsoleMaxPosX;
STATIC UINTN mConsoleMaxPosY;
STATIC UINTN mCursorPosX;
STATIC UINTN mCursorPosY;
STATIC BOOLEAN mCursorOnscreen;
STATIC UINT8 mFontScale;
STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mBackgroundColor;
STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mForegroundColor;
@ -202,9 +199,6 @@ RenderChar (
DstBuffer = &mCharacterBuffer[0].Raw;
if ((Char >= 0 && Char < ISO_CHAR_MIN) || Char == ' ' || Char == '\t' || Char == 0x7F) {
//
// I am not positive we can skip drawing step for these symbols.
//
SetMem32 (DstBuffer, TGT_CHAR_AREA * sizeof (DstBuffer[0]), mBackgroundColor.Raw);
} else {
@ -252,66 +246,66 @@ RenderChar (
}
/**
Render cursor onscreen.
Swap cursor visibility onscreen.
@param[in] Enabled Whether cursor should be drawn.
@param[in] Enabled Whether cursor is visible.
@param[in] PosX Character X position.
@param[in] PosY Character Y position.
**/
STATIC
VOID
RenderCursor (
FlushCursor (
IN BOOLEAN Enabled,
IN UINTN PosX,
IN UINTN PosY
)
{
//
// Enabled but already drawn.
//
if (Enabled && mCursorOnscreen && PosX == mCursorPosX && PosY == mCursorPosY) {
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Colour;
if (!Enabled) {
return;
}
//
// Hide previous.
// UEFI only has one cursor at a time. UEFI Shell edit command has a cursor and a mouse
// pointer, which are not connected. To be able to draw both at a time UEFI Shell constantly
// redraws both the cursor and the mouse pointer. To do that it constantly flips bg and fg
// colours as well as cursor visibility.
// It seems that the Shell implementation relies on an undocumented feature (is that a bug?)
// of hiding an already drawn cursor with a space with inverted attributes.
// This is weird but EDK II implementation seems to match the logic, and as a result we
// track cursor visibility or easily optimise this logic.
//
if (mCursorOnscreen) {
mGraphicsOutput->Blt (
mGraphicsOutput,
&mBackgroundColor.Pixel,
EfiBltVideoFill,
0,
0,
TGT_PADD_WIDTH + mCursorPosX * TGT_CHAR_WIDTH + TGT_CURSOR_X,
TGT_PADD_HEIGHT + mCursorPosY * TGT_CHAR_HEIGHT + TGT_CURSOR_Y,
TGT_CURSOR_WIDTH,
TGT_CURSOR_HEIGHT,
0
);
mCursorOnscreen = FALSE;
Status = mGraphicsOutput->Blt (
mGraphicsOutput,
&Colour.Pixel,
EfiBltVideoToBltBuffer,
TGT_PADD_WIDTH + PosX * TGT_CHAR_WIDTH + TGT_CURSOR_X,
TGT_PADD_HEIGHT + PosY * TGT_CHAR_HEIGHT + TGT_CURSOR_Y,
0,
0,
1,
1,
0
);
if (EFI_ERROR (Status)) {
return;
}
//
// Draw new.
//
if (Enabled) {
mGraphicsOutput->Blt (
mGraphicsOutput,
&mForegroundColor.Pixel,
EfiBltVideoFill,
0,
0,
TGT_PADD_WIDTH + PosX * TGT_CHAR_WIDTH + TGT_CURSOR_X,
TGT_PADD_HEIGHT + PosY * TGT_CHAR_HEIGHT + TGT_CURSOR_Y,
TGT_CURSOR_WIDTH,
TGT_CURSOR_HEIGHT,
0
);
mCursorPosX = PosX;
mCursorPosY = PosY;
mCursorOnscreen = TRUE;
}
mGraphicsOutput->Blt (
mGraphicsOutput,
Colour.Raw == mForegroundColor.Raw ? &mBackgroundColor.Pixel : &mForegroundColor.Pixel,
EfiBltVideoFill,
0,
0,
TGT_PADD_WIDTH + PosX * TGT_CHAR_WIDTH + TGT_CURSOR_X,
TGT_PADD_HEIGHT + PosY * TGT_CHAR_HEIGHT + TGT_CURSOR_Y,
TGT_CURSOR_WIDTH,
TGT_CURSOR_HEIGHT,
0
);
}
STATIC
@ -320,11 +314,6 @@ RenderScroll (
VOID
)
{
//
// Hide previous cursor.
//
RenderCursor (FALSE, 0, 0);
//
// Move data.
//
@ -409,9 +398,6 @@ AsciiTextReset (
This->Mode->CursorColumn = 0;
This->Mode->CursorRow = 0;
This->Mode->Attribute = (ARRAY_SIZE (mGraphicsEfiColors) / 2) - 1;
mCursorOnscreen = FALSE;
mCursorPosX = 0;
mCursorPosY = 0;
mConsoleMaxPosX = 0;
mConsoleMaxPosY = 0;
mBackgroundColor.Raw = mGraphicsEfiColors[0];
@ -459,6 +445,8 @@ AsciiTextOutputString (
This->Mode->CursorRow = 0;
}
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
for (Index = 0; String[Index] != '\0'; ++Index) {
//
// Carriage return should just move the cursor back.
@ -503,14 +491,12 @@ AsciiTextOutputString (
//
// New line with scroll.
//
This->Mode->CursorColumn = 0;
RenderScroll ();
This->Mode->CursorColumn = 0;
}
}
if (This->Mode->CursorVisible) {
RenderCursor (TRUE, This->Mode->CursorColumn, This->Mode->CursorRow);
}
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
gBS->RestoreTPL (OldTpl);
@ -589,21 +575,27 @@ AsciiTextSetAttribute (
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
FgColor = BitFieldRead32 (Attribute, 0, 3);
BgColor = BitFieldRead32 (Attribute, 4, 6);
if (Attribute != This->Mode->Attribute) {
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
//
// Once we change the background we should redraw everything.
//
if (mGraphicsEfiColors[BgColor] != mBackgroundColor.Raw) {
mConsoleMaxPosX = mConsoleWidth + SCR_PADD;
mConsoleMaxPosY = mConsoleHeight + SCR_PADD;
FgColor = BitFieldRead32 (Attribute, 0, 3);
BgColor = BitFieldRead32 (Attribute, 4, 6);
//
// Once we change the background we should redraw everything.
//
if (mGraphicsEfiColors[BgColor] != mBackgroundColor.Raw) {
mConsoleMaxPosX = mConsoleWidth + SCR_PADD;
mConsoleMaxPosY = mConsoleHeight + SCR_PADD;
}
mForegroundColor.Raw = mGraphicsEfiColors[FgColor];
mBackgroundColor.Raw = mGraphicsEfiColors[BgColor];
This->Mode->Attribute = Attribute;
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
}
mForegroundColor.Raw = mGraphicsEfiColors[FgColor];
mBackgroundColor.Raw = mGraphicsEfiColors[BgColor];
This->Mode->Attribute = Attribute;
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
}
@ -621,10 +613,6 @@ AsciiTextClearScreen (
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
mCursorOnscreen = FALSE;
This->Mode->CursorColumn = 0;
This->Mode->CursorRow = 0;
//
// X coordinate points to the right most coordinate of the last printed
// character, but after this character we may also have cursor.
@ -633,9 +621,6 @@ AsciiTextClearScreen (
Width = TGT_PADD_WIDTH + (mConsoleMaxPosX + 1) * TGT_CHAR_WIDTH;
Height = TGT_PADD_HEIGHT + (mConsoleMaxPosY + 1) * TGT_CHAR_HEIGHT;
//
// We clear in any case as we do not detect cursor state.
//
mGraphicsOutput->Blt (
mGraphicsOutput,
&mBackgroundColor.Pixel,
@ -649,6 +634,13 @@ AsciiTextClearScreen (
0
);
//
// Handle cursor.
//
This->Mode->CursorColumn = 0;
This->Mode->CursorRow = 0;
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
//
// We do not reset max here, as we may still scroll (e.g. in shell via page buttons).
//
@ -672,13 +664,12 @@ AsciiTextSetCursorPosition (
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
if (Column < mConsoleWidth && Row < mConsoleHeight) {
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
This->Mode->CursorColumn = (INT32) Column;
This->Mode->CursorRow = (INT32) Row;
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
mConsoleMaxPosX = MAX (mConsoleMaxPosX, Column);
mConsoleMaxPosY = MAX (mConsoleMaxPosY, Row);
if (This->Mode->CursorVisible) {
RenderCursor (TRUE, This->Mode->CursorColumn, This->Mode->CursorRow);
}
Status = EFI_SUCCESS;
} else {
Status = EFI_UNSUPPORTED;
@ -699,8 +690,9 @@ AsciiTextEnableCursor (
EFI_TPL OldTpl;
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
This->Mode->CursorVisible = Visible;
RenderCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
}