void Scraper::syncConsoleContentAndSize()

in src/agent/Scraper.cc [319:387]


void Scraper::syncConsoleContentAndSize(
    bool forceResize,
    ConsoleScreenBufferInfo &finalInfoOut)
{
    // We'll try to avoid freezing the console by reading large chunks (or
    // all!) of the screen buffer without otherwise attempting to synchronize
    // with the console application.  We can only do this on Windows 10 and up
    // because:
    //  - Prior to Windows 8, the size of a ReadConsoleOutputW call was limited
    //    by the ~32KB RPC buffer.
    //  - Prior to Windows 10, an out-of-range read region crashes the caller.
    //    (See misc/WindowsBugCrashReader.cc.)
    //
    if (!m_console.isNewW10() || forceResize) {
        m_console.setFrozen(true);
    }

    const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo();
    bool cursorVisible = true;
    CONSOLE_CURSOR_INFO cursorInfo = {};
    if (!GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo)) {
        trace("GetConsoleCursorInfo failed");
    } else {
        cursorVisible = cursorInfo.bVisible != 0;
    }

    // If an app resizes the buffer height, then we enter "direct mode", where
    // we stop trying to track incremental console changes.
    const bool newDirectMode = (info.bufferSize().Y != BUFFER_LINE_COUNT);
    if (newDirectMode != m_directMode) {
        trace("Entering %s mode", newDirectMode ? "direct" : "scrolling");
        resetConsoleTracking(Terminal::SendClear,
                             newDirectMode ? 0 : info.windowRect().top());
        m_directMode = newDirectMode;

        // When we switch from direct->scrolling mode, make sure the console is
        // the right size.
        if (!m_directMode) {
            m_console.setFrozen(true);
            forceResize = true;
        }
    }

    if (m_directMode) {
        // In direct-mode, resizing the console redraws the terminal, so do it
        // before scraping.
        if (forceResize) {
            resizeImpl(info);
        }
        directScrapeOutput(info, cursorVisible);
    } else {
        if (!m_console.frozen()) {
            if (!scrollingScrapeOutput(info, cursorVisible, true)) {
                m_console.setFrozen(true);
            }
        }
        if (m_console.frozen()) {
            scrollingScrapeOutput(info, cursorVisible, false);
        }
        // In scrolling mode, we want to scrape before resizing, because we'll
        // erase everything in the console buffer up to the top of the console
        // window.
        if (forceResize) {
            resizeImpl(info);
        }
    }

    finalInfoOut = forceResize ? m_consoleBuffer->bufferInfo() : info;
}