409 lines
12 KiB
C++
409 lines
12 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
#include <intsafe.h>
|
|
|
|
#include "misc.h"
|
|
#include "output.h"
|
|
#include "srvinit.h"
|
|
|
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
|
#include "../types/inc/convert.hpp"
|
|
|
|
using Microsoft::Console::Interactivity::ServiceLocator;
|
|
using Microsoft::Console::Render::BlinkingState;
|
|
using Microsoft::Console::VirtualTerminal::VtIo;
|
|
|
|
CONSOLE_INFORMATION::CONSOLE_INFORMATION() :
|
|
// ProcessHandleList initializes itself
|
|
pInputBuffer(nullptr),
|
|
pCurrentScreenBuffer(nullptr),
|
|
ScreenBuffers(nullptr),
|
|
OutputQueue(),
|
|
// ExeAliasList initialized below
|
|
_OriginalTitle(),
|
|
_Title(),
|
|
_LinkTitle(),
|
|
Flags(0),
|
|
PopupCount(0),
|
|
CP(0),
|
|
OutputCP(0),
|
|
CtrlFlags(0),
|
|
LimitingProcessId(0),
|
|
// ColorTable initialized below
|
|
// CPInfo initialized below
|
|
// OutputCPInfo initialized below
|
|
_cookedReadData(nullptr),
|
|
ConsoleIme{},
|
|
_vtIo(),
|
|
_blinker{},
|
|
renderData{}
|
|
{
|
|
ZeroMemory((void*)&CPInfo, sizeof(CPInfo));
|
|
ZeroMemory((void*)&OutputCPInfo, sizeof(OutputCPInfo));
|
|
InitializeCriticalSection(&_csConsoleLock);
|
|
}
|
|
|
|
CONSOLE_INFORMATION::~CONSOLE_INFORMATION()
|
|
{
|
|
DeleteCriticalSection(&_csConsoleLock);
|
|
}
|
|
|
|
bool CONSOLE_INFORMATION::IsConsoleLocked() const
|
|
{
|
|
// The critical section structure's OwningThread field contains the ThreadId despite having the HANDLE type.
|
|
// This requires us to hard cast the ID to compare.
|
|
return _csConsoleLock.OwningThread == (HANDLE)GetCurrentThreadId();
|
|
}
|
|
|
|
#pragma prefast(suppress : 26135, "Adding lock annotation spills into entire project. Future work.")
|
|
void CONSOLE_INFORMATION::LockConsole()
|
|
{
|
|
EnterCriticalSection(&_csConsoleLock);
|
|
}
|
|
|
|
#pragma prefast(suppress : 26135, "Adding lock annotation spills into entire project. Future work.")
|
|
bool CONSOLE_INFORMATION::TryLockConsole()
|
|
{
|
|
return !!TryEnterCriticalSection(&_csConsoleLock);
|
|
}
|
|
|
|
#pragma prefast(suppress : 26135, "Adding lock annotation spills into entire project. Future work.")
|
|
void CONSOLE_INFORMATION::UnlockConsole()
|
|
{
|
|
LeaveCriticalSection(&_csConsoleLock);
|
|
}
|
|
|
|
ULONG CONSOLE_INFORMATION::GetCSRecursionCount()
|
|
{
|
|
return _csConsoleLock.RecursionCount;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - This routine allocates and initialized a console and its associated
|
|
// data - input buffer and screen buffer.
|
|
// - NOTE: Will read global ServiceLocator::LocateGlobals().getConsoleInformation expecting Settings to already be filled.
|
|
// Arguments:
|
|
// - title - Window Title to display
|
|
// Return Value:
|
|
// - STATUS_SUCCESS if successful.
|
|
[[nodiscard]] NTSTATUS CONSOLE_INFORMATION::AllocateConsole(const std::wstring_view title)
|
|
{
|
|
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
|
// Synchronize flags
|
|
WI_SetFlagIf(gci.Flags, CONSOLE_AUTO_POSITION, !!gci.GetAutoPosition());
|
|
WI_SetFlagIf(gci.Flags, CONSOLE_QUICK_EDIT_MODE, !!gci.GetQuickEdit());
|
|
WI_SetFlagIf(gci.Flags, CONSOLE_HISTORY_NODUP, !!gci.GetHistoryNoDup());
|
|
|
|
Selection* const pSelection = &Selection::Instance();
|
|
pSelection->SetLineSelection(!!gci.GetLineSelection());
|
|
|
|
SetConsoleCPInfo(TRUE);
|
|
SetConsoleCPInfo(FALSE);
|
|
|
|
// Initialize input buffer.
|
|
try
|
|
{
|
|
gci.pInputBuffer = new InputBuffer();
|
|
}
|
|
catch (...)
|
|
{
|
|
return NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException());
|
|
}
|
|
|
|
try
|
|
{
|
|
gci.SetTitle(title);
|
|
gci.SetOriginalTitle(std::wstring(TranslateConsoleTitle(gci.GetTitle().c_str(), TRUE, FALSE)));
|
|
}
|
|
catch (...)
|
|
{
|
|
return NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException());
|
|
}
|
|
|
|
NTSTATUS Status = DoCreateScreenBuffer();
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit2;
|
|
}
|
|
|
|
gci.pCurrentScreenBuffer = gci.ScreenBuffers;
|
|
|
|
gci.GetActiveOutputBuffer().ScrollScale = gci.GetScrollScale();
|
|
|
|
gci.ConsoleIme.RefreshAreaAttributes();
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
RIPMSG1(RIP_WARNING, "Console init failed with status 0x%x", Status);
|
|
|
|
delete gci.ScreenBuffers;
|
|
gci.ScreenBuffers = nullptr;
|
|
|
|
ErrorExit2:
|
|
delete gci.pInputBuffer;
|
|
|
|
return Status;
|
|
}
|
|
|
|
VtIo* CONSOLE_INFORMATION::GetVtIo()
|
|
{
|
|
return &_vtIo;
|
|
}
|
|
|
|
bool CONSOLE_INFORMATION::IsInVtIoMode() const
|
|
{
|
|
return _vtIo.IsUsingVt();
|
|
}
|
|
|
|
bool CONSOLE_INFORMATION::HasPendingCookedRead() const noexcept
|
|
{
|
|
return _cookedReadData != nullptr;
|
|
}
|
|
|
|
const COOKED_READ_DATA& CONSOLE_INFORMATION::CookedReadData() const noexcept
|
|
{
|
|
return *_cookedReadData;
|
|
}
|
|
|
|
COOKED_READ_DATA& CONSOLE_INFORMATION::CookedReadData() noexcept
|
|
{
|
|
return *_cookedReadData;
|
|
}
|
|
|
|
void CONSOLE_INFORMATION::SetCookedReadData(COOKED_READ_DATA* readData) noexcept
|
|
{
|
|
_cookedReadData = readData;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Return the active screen buffer of the console.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - the active screen buffer of the console.
|
|
SCREEN_INFORMATION& CONSOLE_INFORMATION::GetActiveOutputBuffer()
|
|
{
|
|
return *pCurrentScreenBuffer;
|
|
}
|
|
|
|
const SCREEN_INFORMATION& CONSOLE_INFORMATION::GetActiveOutputBuffer() const
|
|
{
|
|
return *pCurrentScreenBuffer;
|
|
}
|
|
|
|
bool CONSOLE_INFORMATION::HasActiveOutputBuffer() const
|
|
{
|
|
return (pCurrentScreenBuffer != nullptr);
|
|
}
|
|
|
|
// Method Description:
|
|
// - Return the active input buffer of the console.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - the active input buffer of the console.
|
|
InputBuffer* const CONSOLE_INFORMATION::GetActiveInputBuffer() const
|
|
{
|
|
return pInputBuffer;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Return the default foreground color of the console. If the settings are
|
|
// configured to have a default foreground color (separate from the color
|
|
// table), this will return that value. Otherwise it will return the value
|
|
// from the colortable corresponding to our default attributes.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - the default foreground color of the console.
|
|
COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept
|
|
{
|
|
const auto fg = GetDefaultForegroundColor();
|
|
return fg != INVALID_COLOR ? fg : GetColorTableEntry(LOBYTE(GetFillAttribute()) & FG_ATTRS);
|
|
}
|
|
|
|
// Method Description:
|
|
// - Return the default background color of the console. If the settings are
|
|
// configured to have a default background color (separate from the color
|
|
// table), this will return that value. Otherwise it will return the value
|
|
// from the colortable corresponding to our default attributes.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - the default background color of the console.
|
|
COLORREF CONSOLE_INFORMATION::GetDefaultBackground() const noexcept
|
|
{
|
|
const auto bg = GetDefaultBackgroundColor();
|
|
return bg != INVALID_COLOR ? bg : GetColorTableEntry((LOBYTE(GetFillAttribute()) & BG_ATTRS) >> 4);
|
|
}
|
|
|
|
// Method Description:
|
|
// - Get the colors of a particular text attribute, using our color table,
|
|
// and our configured default attributes.
|
|
// Arguments:
|
|
// - attr: the TextAttribute to retrieve the foreground color of.
|
|
// Return Value:
|
|
// - The color values of the attribute's foreground and background.
|
|
std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr) const noexcept
|
|
{
|
|
_blinkingState.RecordBlinkingUsage(attr);
|
|
return attr.CalculateRgbColors(Get256ColorTable(),
|
|
GetDefaultForeground(),
|
|
GetDefaultBackground(),
|
|
IsScreenReversed(),
|
|
_blinkingState.IsBlinkingFaint());
|
|
}
|
|
|
|
// Method Description:
|
|
// - Set the console's title, and trigger a renderer update of the title.
|
|
// This does not include the title prefix, such as "Mark", "Select", or "Scroll"
|
|
// Arguments:
|
|
// - newTitle: The new value to use for the title
|
|
// Return Value:
|
|
// - <none>
|
|
void CONSOLE_INFORMATION::SetTitle(const std::wstring_view newTitle)
|
|
{
|
|
_Title = std::wstring{ newTitle.begin(), newTitle.end() };
|
|
|
|
auto* const pRender = ServiceLocator::LocateGlobals().pRender;
|
|
if (pRender)
|
|
{
|
|
pRender->TriggerTitleChange();
|
|
}
|
|
}
|
|
|
|
// Method Description:
|
|
// - Set the console title's prefix, and trigger a renderer update of the title.
|
|
// This is the part of the title such as "Mark", "Select", or "Scroll"
|
|
// Arguments:
|
|
// - newTitlePrefix: The new value to use for the title prefix
|
|
// Return Value:
|
|
// - <none>
|
|
void CONSOLE_INFORMATION::SetTitlePrefix(const std::wstring& newTitlePrefix)
|
|
{
|
|
_TitlePrefix = newTitlePrefix;
|
|
|
|
auto* const pRender = ServiceLocator::LocateGlobals().pRender;
|
|
if (pRender)
|
|
{
|
|
pRender->TriggerTitleChange();
|
|
}
|
|
}
|
|
|
|
// Method Description:
|
|
// - Set the value of the console's original title. This is the title the
|
|
// console launched with.
|
|
// Arguments:
|
|
// - originalTitle: The new value to use for the console's original title
|
|
// Return Value:
|
|
// - <none>
|
|
void CONSOLE_INFORMATION::SetOriginalTitle(const std::wstring& originalTitle)
|
|
{
|
|
_OriginalTitle = originalTitle;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Set the value of the console's link title. If the console was launched
|
|
/// from a shortcut, this value will not be the empty string.
|
|
// Arguments:
|
|
// - linkTitle: The new value to use for the console's link title
|
|
// Return Value:
|
|
// - <none>
|
|
void CONSOLE_INFORMATION::SetLinkTitle(const std::wstring& linkTitle)
|
|
{
|
|
_LinkTitle = linkTitle;
|
|
}
|
|
|
|
// Method Description:
|
|
// - return a reference to the console's title.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a reference to the console's title.
|
|
const std::wstring& CONSOLE_INFORMATION::GetTitle() const noexcept
|
|
{
|
|
return _Title;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Return a new wstring representing the actual display value of the title.
|
|
// This is the Prefix+Title.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a new wstring containing the combined prefix and title.
|
|
const std::wstring CONSOLE_INFORMATION::GetTitleAndPrefix() const
|
|
{
|
|
return _TitlePrefix + _Title;
|
|
}
|
|
|
|
// Method Description:
|
|
// - return a reference to the console's original title.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a reference to the console's original title.
|
|
const std::wstring& CONSOLE_INFORMATION::GetOriginalTitle() const noexcept
|
|
{
|
|
return _OriginalTitle;
|
|
}
|
|
|
|
// Method Description:
|
|
// - return a reference to the console's link title.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a reference to the console's link title.
|
|
const std::wstring& CONSOLE_INFORMATION::GetLinkTitle() const noexcept
|
|
{
|
|
return _LinkTitle;
|
|
}
|
|
|
|
// Method Description:
|
|
// - return a reference to the console's cursor blinker.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a reference to the console's cursor blinker.
|
|
Microsoft::Console::CursorBlinker& CONSOLE_INFORMATION::GetCursorBlinker() noexcept
|
|
{
|
|
return _blinker;
|
|
}
|
|
|
|
// Method Description:
|
|
// - return a reference to the console's blinking state.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a reference to the console's blinking state.
|
|
BlinkingState& CONSOLE_INFORMATION::GetBlinkingState() const noexcept
|
|
{
|
|
return _blinkingState;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Generates a CHAR_INFO for this output cell, using the TextAttribute
|
|
// GetLegacyAttributes method to generate the legacy style attributes.
|
|
// Arguments:
|
|
// - cell: The cell to get the CHAR_INFO from
|
|
// Return Value:
|
|
// - a CHAR_INFO containing legacy information about the cell
|
|
CHAR_INFO CONSOLE_INFORMATION::AsCharInfo(const OutputCellView& cell) const noexcept
|
|
{
|
|
CHAR_INFO ci{ 0 };
|
|
ci.Char.UnicodeChar = Utf16ToUcs2(cell.Chars());
|
|
|
|
// If the current text attributes aren't legacy attributes, then
|
|
// use gci to look up the correct legacy attributes to use
|
|
// (for mapping RGB values to the nearest table value)
|
|
const auto& attr = cell.TextAttr();
|
|
ci.Attributes = attr.GetLegacyAttributes();
|
|
ci.Attributes |= cell.DbcsAttr().GeneratePublicApiAttributeFormat();
|
|
return ci;
|
|
}
|