mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 13:56:33 -06:00
Merge remote-tracking branch 'origin/main' into feature/llm
This commit is contained in:
commit
10f8933d15
@ -13,6 +13,7 @@
|
|||||||
#include "srvinit.h"
|
#include "srvinit.h"
|
||||||
|
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
|
#include "../interactivity/win32/CustomWindowMessages.h"
|
||||||
#include "../types/inc/convert.hpp"
|
#include "../types/inc/convert.hpp"
|
||||||
|
|
||||||
using Microsoft::Console::Interactivity::ServiceLocator;
|
using Microsoft::Console::Interactivity::ServiceLocator;
|
||||||
@ -179,6 +180,32 @@ void CONSOLE_INFORMATION::SetBracketedPasteMode(const bool enabled) noexcept
|
|||||||
_bracketedPasteMode = enabled;
|
_bracketedPasteMode = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CONSOLE_INFORMATION::CopyTextToClipboard(const std::wstring_view text)
|
||||||
|
{
|
||||||
|
const auto window = ServiceLocator::LocateConsoleWindow();
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
// The clipboard can only be updated from the main GUI thread, so we
|
||||||
|
// need to post a message to trigger the actual copy operation. But if
|
||||||
|
// the pending clipboard content is already set, a message would have
|
||||||
|
// already been posted, so there's no need to post another one.
|
||||||
|
const auto clipboardMessageSent = _pendingClipboardText.has_value();
|
||||||
|
_pendingClipboardText = text;
|
||||||
|
if (!clipboardMessageSent)
|
||||||
|
{
|
||||||
|
PostMessageW(window->GetWindowHandle(), CM_UPDATE_CLIPBOARD, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::wstring> CONSOLE_INFORMATION::UsePendingClipboardText()
|
||||||
|
{
|
||||||
|
// Once the pending text has been used, we clear the variable to let the
|
||||||
|
// CopyTextToClipboard method know that the last CM_UPDATE_CLIPBOARD message
|
||||||
|
// has been processed, and future updates will require another message.
|
||||||
|
return std::exchange(_pendingClipboardText, {});
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Return the active screen buffer of the console.
|
// - Return the active screen buffer of the console.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|||||||
@ -280,9 +280,9 @@ unsigned int ConhostInternalGetSet::GetInputCodePage() const
|
|||||||
// - content - the text to be copied.
|
// - content - the text to be copied.
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void ConhostInternalGetSet::CopyToClipboard(const wil::zwstring_view /*content*/)
|
void ConhostInternalGetSet::CopyToClipboard(const wil::zwstring_view content)
|
||||||
{
|
{
|
||||||
// TODO
|
ServiceLocator::LocateGlobals().getConsoleInformation().CopyTextToClipboard(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
|
|||||||
@ -126,6 +126,8 @@ public:
|
|||||||
|
|
||||||
bool GetBracketedPasteMode() const noexcept;
|
bool GetBracketedPasteMode() const noexcept;
|
||||||
void SetBracketedPasteMode(const bool enabled) noexcept;
|
void SetBracketedPasteMode(const bool enabled) noexcept;
|
||||||
|
void CopyTextToClipboard(const std::wstring_view text);
|
||||||
|
std::optional<std::wstring> UsePendingClipboardText();
|
||||||
|
|
||||||
void SetTitle(const std::wstring_view newTitle);
|
void SetTitle(const std::wstring_view newTitle);
|
||||||
void SetTitlePrefix(const std::wstring_view newTitlePrefix);
|
void SetTitlePrefix(const std::wstring_view newTitlePrefix);
|
||||||
@ -160,6 +162,7 @@ private:
|
|||||||
SCREEN_INFORMATION* pCurrentScreenBuffer = nullptr;
|
SCREEN_INFORMATION* pCurrentScreenBuffer = nullptr;
|
||||||
COOKED_READ_DATA* _cookedReadData = nullptr; // non-ownership pointer
|
COOKED_READ_DATA* _cookedReadData = nullptr; // non-ownership pointer
|
||||||
bool _bracketedPasteMode = false;
|
bool _bracketedPasteMode = false;
|
||||||
|
std::optional<std::wstring> _pendingClipboardText;
|
||||||
|
|
||||||
Microsoft::Console::VirtualTerminal::VtIo _vtIo;
|
Microsoft::Console::VirtualTerminal::VtIo _vtIo;
|
||||||
Microsoft::Console::CursorBlinker _blinker;
|
Microsoft::Console::CursorBlinker _blinker;
|
||||||
|
|||||||
@ -24,6 +24,22 @@ using namespace Microsoft::Console::Types;
|
|||||||
|
|
||||||
#pragma region Public Methods
|
#pragma region Public Methods
|
||||||
|
|
||||||
|
void Clipboard::CopyText(const std::wstring& text)
|
||||||
|
{
|
||||||
|
const auto clipboard = _openClipboard(ServiceLocator::LocateConsoleWindow()->GetWindowHandle());
|
||||||
|
if (!clipboard)
|
||||||
|
{
|
||||||
|
LOG_LAST_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyClipboard();
|
||||||
|
// As per: https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
|
||||||
|
// CF_UNICODETEXT: [...] A null character signals the end of the data.
|
||||||
|
// --> We add +1 to the length. This works because .c_str() is null-terminated.
|
||||||
|
_copyToClipboard(CF_UNICODETEXT, text.c_str(), (text.size() + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - fAlsoCopyFormatting - Place colored HTML & RTF text onto the clipboard as well as the usual plain text.
|
// - fAlsoCopyFormatting - Place colored HTML & RTF text onto the clipboard as well as the usual plain text.
|
||||||
// Return Value:
|
// Return Value:
|
||||||
|
|||||||
@ -29,4 +29,6 @@
|
|||||||
#define CM_SET_KEYBOARD_LAYOUT (WM_USER+19)
|
#define CM_SET_KEYBOARD_LAYOUT (WM_USER+19)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CM_UPDATE_CLIPBOARD (WM_USER+20)
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|||||||
@ -29,6 +29,7 @@ namespace Microsoft::Console::Interactivity::Win32
|
|||||||
public:
|
public:
|
||||||
static Clipboard& Instance();
|
static Clipboard& Instance();
|
||||||
|
|
||||||
|
void CopyText(const std::wstring& text);
|
||||||
void Copy(_In_ const bool fAlsoCopyFormatting = false);
|
void Copy(_In_ const bool fAlsoCopyFormatting = false);
|
||||||
void Paste();
|
void Paste();
|
||||||
void PasteDrop(HDROP drop);
|
void PasteDrop(HDROP drop);
|
||||||
|
|||||||
@ -773,6 +773,15 @@ static constexpr TsfDataProvider s_tsfDataProvider;
|
|||||||
}
|
}
|
||||||
#endif // DBG
|
#endif // DBG
|
||||||
|
|
||||||
|
case CM_UPDATE_CLIPBOARD:
|
||||||
|
{
|
||||||
|
if (const auto clipboardText = gci.UsePendingClipboardText())
|
||||||
|
{
|
||||||
|
Clipboard::Instance().CopyText(clipboardText.value());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case EVENT_CONSOLE_CARET:
|
case EVENT_CONSOLE_CARET:
|
||||||
case EVENT_CONSOLE_UPDATE_REGION:
|
case EVENT_CONSOLE_UPDATE_REGION:
|
||||||
case EVENT_CONSOLE_UPDATE_SIMPLE:
|
case EVENT_CONSOLE_UPDATE_SIMPLE:
|
||||||
|
|||||||
@ -237,6 +237,7 @@ void SixelParser::_executeNextLine()
|
|||||||
_imageCursor.y += _sixelHeight;
|
_imageCursor.y += _sixelHeight;
|
||||||
_availablePixelHeight -= _sixelHeight;
|
_availablePixelHeight -= _sixelHeight;
|
||||||
_resizeImageBuffer(_sixelHeight);
|
_resizeImageBuffer(_sixelHeight);
|
||||||
|
_fillImageBackgroundWhenScrolled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SixelParser::_executeMoveToHome()
|
void SixelParser::_executeMoveToHome()
|
||||||
@ -341,6 +342,12 @@ void SixelParser::_initRasterAttributes(const VTInt macroParameter, const Dispat
|
|||||||
|
|
||||||
// By default, the filled area will cover the maximum extent allowed.
|
// By default, the filled area will cover the maximum extent allowed.
|
||||||
_backgroundSize = { til::CoordTypeMax, til::CoordTypeMax };
|
_backgroundSize = { til::CoordTypeMax, til::CoordTypeMax };
|
||||||
|
|
||||||
|
// If the image ends up extending beyond the bottom of the page, we may need
|
||||||
|
// to perform additional background filling as the screen is scrolled, which
|
||||||
|
// requires us to track the area filled so far. This will be initialized, if
|
||||||
|
// necessary, in the _fillImageBackground method below.
|
||||||
|
_filledBackgroundHeight = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SixelParser::_updateRasterAttributes(const VTParameters& rasterAttributes)
|
void SixelParser::_updateRasterAttributes(const VTParameters& rasterAttributes)
|
||||||
@ -373,6 +380,15 @@ void SixelParser::_updateRasterAttributes(const VTParameters& rasterAttributes)
|
|||||||
// back to the dimensions from an earlier raster attributes command.
|
// back to the dimensions from an earlier raster attributes command.
|
||||||
_backgroundSize.width = width > 0 ? width : _backgroundSize.width;
|
_backgroundSize.width = width > 0 ? width : _backgroundSize.width;
|
||||||
_backgroundSize.height = height > 0 ? height : _backgroundSize.height;
|
_backgroundSize.height = height > 0 ? height : _backgroundSize.height;
|
||||||
|
|
||||||
|
// If the aspect ratio has changed, the image height may increase, and that
|
||||||
|
// could potentially trigger a scroll requiring the background to be filled.
|
||||||
|
_fillImageBackgroundWhenScrolled();
|
||||||
|
|
||||||
|
// And while not documented, we know from testing on a VT330 that the raster
|
||||||
|
// attributes command should also trigger a carriage return. This applies
|
||||||
|
// regardless of whether the requested aspect ratio is valid or not.
|
||||||
|
_executeCarriageReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SixelParser::_scrollTextBuffer(Page& page, const int scrollAmount)
|
void SixelParser::_scrollTextBuffer(Page& page, const int scrollAmount)
|
||||||
@ -656,24 +672,60 @@ void SixelParser::_fillImageBackground()
|
|||||||
{
|
{
|
||||||
_backgroundFillRequired = false;
|
_backgroundFillRequired = false;
|
||||||
|
|
||||||
const auto backgroundHeight = std::min(_backgroundSize.height, _availablePixelHeight);
|
|
||||||
const auto backgroundWidth = std::min(_backgroundSize.width, _availablePixelWidth);
|
|
||||||
_resizeImageBuffer(backgroundHeight);
|
|
||||||
|
|
||||||
// When a background fill is requested, we prefill the buffer with the 0
|
// When a background fill is requested, we prefill the buffer with the 0
|
||||||
// color index, up to the boundaries set by the raster attributes (or if
|
// color index, up to the boundaries set by the raster attributes (or if
|
||||||
// none were given, up to the page boundaries). The actual image output
|
// none were given, up to the page boundaries). The actual image output
|
||||||
// isn't limited by the background dimensions though.
|
// isn't limited by the background dimensions though.
|
||||||
static constexpr auto backgroundPixel = IndexedPixel{};
|
const auto backgroundHeight = std::min(_backgroundSize.height, _availablePixelHeight);
|
||||||
const auto backgroundOffset = _imageCursor.y * _imageMaxWidth;
|
_resizeImageBuffer(backgroundHeight);
|
||||||
auto dst = std::next(_imageBuffer.begin(), backgroundOffset);
|
_fillImageBackground(backgroundHeight);
|
||||||
for (auto i = 0; i < backgroundHeight; i++)
|
// When the image extends beyond the page boundaries, and the screen is
|
||||||
{
|
// scrolled, we also need to fill the newly exposed lines, so we keep a
|
||||||
std::fill_n(dst, backgroundWidth, backgroundPixel);
|
// record of the area filled so far. Initially this is considered to be
|
||||||
std::advance(dst, _imageMaxWidth);
|
// the available height, even if it wasn't all filled to start with.
|
||||||
}
|
_filledBackgroundHeight = _imageCursor.y + _availablePixelHeight;
|
||||||
|
_fillImageBackgroundWhenScrolled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_imageWidth = std::max(_imageWidth, backgroundWidth);
|
void SixelParser::_fillImageBackground(const int backgroundHeight)
|
||||||
|
{
|
||||||
|
static constexpr auto backgroundPixel = IndexedPixel{};
|
||||||
|
const auto backgroundWidth = std::min(_backgroundSize.width, _availablePixelWidth);
|
||||||
|
const auto backgroundOffset = _imageCursor.y * _imageMaxWidth;
|
||||||
|
auto dst = std::next(_imageBuffer.begin(), backgroundOffset);
|
||||||
|
for (auto i = 0; i < backgroundHeight; i++)
|
||||||
|
{
|
||||||
|
std::fill_n(dst, backgroundWidth, backgroundPixel);
|
||||||
|
std::advance(dst, _imageMaxWidth);
|
||||||
|
}
|
||||||
|
_imageWidth = std::max(_imageWidth, backgroundWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SixelParser::_fillImageBackgroundWhenScrolled()
|
||||||
|
{
|
||||||
|
// If _filledBackgroundHeight is set, that means a background fill has been
|
||||||
|
// requested, and we need to extend that area whenever the image is about to
|
||||||
|
// overrun it. The newly filled area is a multiple of the cell height (this
|
||||||
|
// is to match the behavior of the original hardware terminals).
|
||||||
|
const auto imageHeight = _imageCursor.y + _sixelHeight;
|
||||||
|
if (_filledBackgroundHeight && imageHeight > _filledBackgroundHeight) [[unlikely]]
|
||||||
|
{
|
||||||
|
_filledBackgroundHeight = (imageHeight + _cellSize.height - 1) / _cellSize.height * _cellSize.height;
|
||||||
|
const auto additionalFillHeight = *_filledBackgroundHeight - _imageCursor.y;
|
||||||
|
_resizeImageBuffer(additionalFillHeight);
|
||||||
|
_fillImageBackground(additionalFillHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SixelParser::_decreaseFilledBackgroundHeight(const int decreasedHeight) noexcept
|
||||||
|
{
|
||||||
|
// Sometimes the top of the image buffer may be clipped (e.g. when the image
|
||||||
|
// scrolls off the top of a margin area). When that occurs, our record of
|
||||||
|
// the filled height will need to be decreased to account for the new start.
|
||||||
|
if (_filledBackgroundHeight) [[unlikely]]
|
||||||
|
{
|
||||||
|
_filledBackgroundHeight = *_filledBackgroundHeight - decreasedHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,11 +769,13 @@ void SixelParser::_eraseImageBufferRows(const int rowCount, const til::CoordType
|
|||||||
const auto bufferOffsetEnd = bufferOffset + pixelCount * _imageMaxWidth;
|
const auto bufferOffsetEnd = bufferOffset + pixelCount * _imageMaxWidth;
|
||||||
if (static_cast<size_t>(bufferOffsetEnd) >= _imageBuffer.size()) [[unlikely]]
|
if (static_cast<size_t>(bufferOffsetEnd) >= _imageBuffer.size()) [[unlikely]]
|
||||||
{
|
{
|
||||||
|
_decreaseFilledBackgroundHeight(_imageCursor.y);
|
||||||
_imageBuffer.clear();
|
_imageBuffer.clear();
|
||||||
_imageCursor.y = 0;
|
_imageCursor.y = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_decreaseFilledBackgroundHeight(pixelCount);
|
||||||
_imageBuffer.erase(_imageBuffer.begin() + bufferOffset, _imageBuffer.begin() + bufferOffsetEnd);
|
_imageBuffer.erase(_imageBuffer.begin() + bufferOffset, _imageBuffer.begin() + bufferOffsetEnd);
|
||||||
_imageCursor.y -= pixelCount;
|
_imageCursor.y -= pixelCount;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,6 +89,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
til::CoordType _pendingTextScrollCount = 0;
|
til::CoordType _pendingTextScrollCount = 0;
|
||||||
til::size _backgroundSize;
|
til::size _backgroundSize;
|
||||||
bool _backgroundFillRequired = false;
|
bool _backgroundFillRequired = false;
|
||||||
|
std::optional<til::CoordType> _filledBackgroundHeight;
|
||||||
|
|
||||||
void _initColorMap(const VTParameter backgroundColor);
|
void _initColorMap(const VTParameter backgroundColor);
|
||||||
void _defineColor(const VTParameters& colorParameters);
|
void _defineColor(const VTParameters& colorParameters);
|
||||||
@ -109,6 +110,9 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
void _initImageBuffer();
|
void _initImageBuffer();
|
||||||
void _resizeImageBuffer(const til::CoordType requiredHeight);
|
void _resizeImageBuffer(const til::CoordType requiredHeight);
|
||||||
void _fillImageBackground();
|
void _fillImageBackground();
|
||||||
|
void _fillImageBackground(const int backgroundHeight);
|
||||||
|
void _fillImageBackgroundWhenScrolled();
|
||||||
|
void _decreaseFilledBackgroundHeight(const int decreasedHeight) noexcept;
|
||||||
void _writeToImageBuffer(const int sixelValue, const int repeatCount);
|
void _writeToImageBuffer(const int sixelValue, const int repeatCount);
|
||||||
void _eraseImageBufferRows(const int rowCount, const til::CoordType startRow = 0) noexcept;
|
void _eraseImageBufferRows(const int rowCount, const til::CoordType startRow = 0) noexcept;
|
||||||
void _maybeFlushImageBuffer(const bool endOfSequence = false);
|
void _maybeFlushImageBuffer(const bool endOfSequence = false);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user