// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "precomp.h" #include #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(), _Prefix(), _TitleAndPrefix(), _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); // TranslateConsoleTitle must have a null terminated string. // This should only happen once on startup so the copy shouldn't be costly // but could be eliminated by rewriting TranslateConsoleTitle. const std::wstring nullTerminatedTitle{ gci.GetTitle() }; gci.SetOriginalTitle(std::wstring(TranslateConsoleTitle(nullTerminatedTitle.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: // - // 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: // - // Return Value: // - the active input buffer of the console. InputBuffer* const CONSOLE_INFORMATION::GetActiveInputBuffer() const { return pInputBuffer; } // 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 and background color of. // Return Value: // - The color values of the attribute's foreground and background. std::pair CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr) const noexcept { _blinkingState.RecordBlinkingUsage(attr); return attr.CalculateRgbColors( GetColorTable(), GetDefaultForegroundIndex(), GetDefaultBackgroundIndex(), 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: // - void CONSOLE_INFORMATION::SetTitle(const std::wstring_view newTitle) { _Title = std::wstring{ newTitle.begin(), newTitle.end() }; _TitleAndPrefix = _Prefix + _Title; 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: // - void CONSOLE_INFORMATION::SetTitlePrefix(const std::wstring_view newTitlePrefix) { _Prefix = newTitlePrefix; _TitleAndPrefix = _Prefix + _Title; 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: // - void CONSOLE_INFORMATION::SetOriginalTitle(const std::wstring_view 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: // - void CONSOLE_INFORMATION::SetLinkTitle(const std::wstring_view linkTitle) { _LinkTitle = linkTitle; } // Method Description: // - return a reference to the console's title. // Arguments: // - // Return Value: // - the console's title. const std::wstring_view 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: // - // Return Value: // - the combined prefix and title. const std::wstring_view CONSOLE_INFORMATION::GetTitleAndPrefix() const { return _TitleAndPrefix; } // Method Description: // - return a reference to the console's original title. // Arguments: // - // Return Value: // - the console's original title. const std::wstring_view CONSOLE_INFORMATION::GetOriginalTitle() const noexcept { return _OriginalTitle; } // Method Description: // - return a reference to the console's link title. // Arguments: // - // Return Value: // - the console's link title. const std::wstring_view CONSOLE_INFORMATION::GetLinkTitle() const noexcept { return _LinkTitle; } // Method Description: // - return a reference to the console's cursor blinker. // Arguments: // - // 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: // - // 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; }