mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 04:38:24 -06:00
Don't trim bracketed pastes (#19067)
* Moves clipboard writing from `ControlCore` to `TerminalPage`. This requires adding a bunch of event types and logic. This is technically not needed anymore after changing the direction of this PR, but I kept it because it's better. * Add a `WarnAboutMultiLinePaste` enum to differentiate between "paste without warning always/never/if-bracketed-paste-disabled". Closes #13014 Closes https://github.com/microsoft/edit/issues/279 ## Validation Steps Performed * Launch Microsoft Edit and copy text with a trailing newline * Paste it with Ctrl+Shift+V * It's pasted as it was copied ✅ * Changing the setting to "always" always warns ✅ Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
This commit is contained in:
parent
5b41f14660
commit
e2f3e53064
@ -548,7 +548,9 @@ namespace winrt::TerminalApp::implementation
|
|||||||
{
|
{
|
||||||
if (const auto& realArgs = args.ActionArgs().try_as<CopyTextArgs>())
|
if (const auto& realArgs = args.ActionArgs().try_as<CopyTextArgs>())
|
||||||
{
|
{
|
||||||
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), realArgs.CopyFormatting());
|
const auto copyFormatting = realArgs.CopyFormatting();
|
||||||
|
const auto format = copyFormatting ? copyFormatting.Value() : _settings.GlobalSettings().CopyFormatting();
|
||||||
|
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), format);
|
||||||
args.Handled(handled);
|
args.Handled(handled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,121 @@ namespace winrt
|
|||||||
using VirtualKeyModifiers = Windows::System::VirtualKeyModifiers;
|
using VirtualKeyModifiers = Windows::System::VirtualKeyModifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace clipboard
|
||||||
|
{
|
||||||
|
wil::unique_close_clipboard_call open(HWND hwnd)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
// OpenClipboard may fail to acquire the internal lock --> retry.
|
||||||
|
for (DWORD sleep = 10;; sleep *= 2)
|
||||||
|
{
|
||||||
|
if (OpenClipboard(hwnd))
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 10 iterations
|
||||||
|
if (sleep > 10000)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Sleep(sleep);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wil::unique_close_clipboard_call{ success };
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(wil::zwstring_view text, std::string_view html, std::string_view rtf)
|
||||||
|
{
|
||||||
|
static const auto regular = [](const UINT format, const void* src, const size_t bytes) {
|
||||||
|
wil::unique_hglobal handle{ THROW_LAST_ERROR_IF_NULL(GlobalAlloc(GMEM_MOVEABLE, bytes)) };
|
||||||
|
|
||||||
|
const auto locked = GlobalLock(handle.get());
|
||||||
|
memcpy(locked, src, bytes);
|
||||||
|
GlobalUnlock(handle.get());
|
||||||
|
|
||||||
|
THROW_LAST_ERROR_IF_NULL(SetClipboardData(format, handle.get()));
|
||||||
|
handle.release();
|
||||||
|
};
|
||||||
|
static const auto registered = [](const wchar_t* format, const void* src, size_t bytes) {
|
||||||
|
const auto id = RegisterClipboardFormatW(format);
|
||||||
|
if (!id)
|
||||||
|
{
|
||||||
|
LOG_LAST_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
regular(id, src, bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
EmptyClipboard();
|
||||||
|
|
||||||
|
if (!text.empty())
|
||||||
|
{
|
||||||
|
// 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.
|
||||||
|
regular(CF_UNICODETEXT, text.c_str(), (text.size() + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!html.empty())
|
||||||
|
{
|
||||||
|
registered(L"HTML Format", html.data(), html.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rtf.empty())
|
||||||
|
{
|
||||||
|
registered(L"Rich Text Format", rtf.data(), rtf.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::hstring read()
|
||||||
|
{
|
||||||
|
// This handles most cases of pasting text as the OS converts most formats to CF_UNICODETEXT automatically.
|
||||||
|
if (const auto handle = GetClipboardData(CF_UNICODETEXT))
|
||||||
|
{
|
||||||
|
const wil::unique_hglobal_locked lock{ handle };
|
||||||
|
const auto str = static_cast<const wchar_t*>(lock.get());
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto maxLen = GlobalSize(handle) / sizeof(wchar_t);
|
||||||
|
const auto len = wcsnlen(str, maxLen);
|
||||||
|
return winrt::hstring{ str, gsl::narrow_cast<uint32_t>(len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// We get CF_HDROP when a user copied a file with Ctrl+C in Explorer and pastes that into the terminal (among others).
|
||||||
|
if (const auto handle = GetClipboardData(CF_HDROP))
|
||||||
|
{
|
||||||
|
const wil::unique_hglobal_locked lock{ handle };
|
||||||
|
const auto drop = static_cast<HDROP>(lock.get());
|
||||||
|
if (!drop)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cap = DragQueryFileW(drop, 0, nullptr, 0);
|
||||||
|
if (cap == 0)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buffer = winrt::impl::hstring_builder{ cap };
|
||||||
|
const auto len = DragQueryFileW(drop, 0, buffer.data(), cap + 1);
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.to_hstring();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace clipboard
|
||||||
|
|
||||||
namespace winrt::TerminalApp::implementation
|
namespace winrt::TerminalApp::implementation
|
||||||
{
|
{
|
||||||
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
|
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
|
||||||
@ -1793,7 +1908,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
{
|
{
|
||||||
term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
|
term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
|
||||||
|
|
||||||
// Add an event handler when the terminal wants to paste data from the Clipboard.
|
term.WriteToClipboard({ get_weak(), &TerminalPage::_copyToClipboard });
|
||||||
term.PasteFromClipboard({ this, &TerminalPage::_PasteFromClipboardHandler });
|
term.PasteFromClipboard({ this, &TerminalPage::_PasteFromClipboardHandler });
|
||||||
|
|
||||||
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
|
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
|
||||||
@ -1815,9 +1930,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
});
|
});
|
||||||
|
|
||||||
term.ShowWindowChanged({ get_weak(), &TerminalPage::_ShowWindowChangedHandler });
|
term.ShowWindowChanged({ get_weak(), &TerminalPage::_ShowWindowChangedHandler });
|
||||||
|
|
||||||
term.SearchMissingCommand({ get_weak(), &TerminalPage::_SearchMissingCommandHandler });
|
term.SearchMissingCommand({ get_weak(), &TerminalPage::_SearchMissingCommandHandler });
|
||||||
|
|
||||||
term.WindowSizeChanged({ get_weak(), &TerminalPage::_WindowSizeChanged });
|
term.WindowSizeChanged({ get_weak(), &TerminalPage::_WindowSizeChanged });
|
||||||
|
|
||||||
// Don't even register for the event if the feature is compiled off.
|
// Don't even register for the event if the feature is compiled off.
|
||||||
@ -2739,75 +2852,6 @@ namespace winrt::TerminalApp::implementation
|
|||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
|
|
||||||
{
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
// OpenClipboard may fail to acquire the internal lock --> retry.
|
|
||||||
for (DWORD sleep = 10;; sleep *= 2)
|
|
||||||
{
|
|
||||||
if (OpenClipboard(hwnd))
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 10 iterations
|
|
||||||
if (sleep > 10000)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Sleep(sleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wil::unique_close_clipboard_call{ success };
|
|
||||||
}
|
|
||||||
|
|
||||||
static winrt::hstring _extractClipboard()
|
|
||||||
{
|
|
||||||
// This handles most cases of pasting text as the OS converts most formats to CF_UNICODETEXT automatically.
|
|
||||||
if (const auto handle = GetClipboardData(CF_UNICODETEXT))
|
|
||||||
{
|
|
||||||
const wil::unique_hglobal_locked lock{ handle };
|
|
||||||
const auto str = static_cast<const wchar_t*>(lock.get());
|
|
||||||
if (!str)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto maxLen = GlobalSize(handle) / sizeof(wchar_t);
|
|
||||||
const auto len = wcsnlen(str, maxLen);
|
|
||||||
return winrt::hstring{ str, gsl::narrow_cast<uint32_t>(len) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// We get CF_HDROP when a user copied a file with Ctrl+C in Explorer and pastes that into the terminal (among others).
|
|
||||||
if (const auto handle = GetClipboardData(CF_HDROP))
|
|
||||||
{
|
|
||||||
const wil::unique_hglobal_locked lock{ handle };
|
|
||||||
const auto drop = static_cast<HDROP>(lock.get());
|
|
||||||
if (!drop)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto cap = DragQueryFileW(drop, 0, nullptr, 0);
|
|
||||||
if (cap == 0)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto buffer = winrt::impl::hstring_builder{ cap };
|
|
||||||
const auto len = DragQueryFileW(drop, 0, buffer.data(), cap + 1);
|
|
||||||
if (len == 0)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.to_hstring();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function Description:
|
// Function Description:
|
||||||
// - This function is called when the `TermControl` requests that we send
|
// - This function is called when the `TermControl` requests that we send
|
||||||
// it the clipboard's content.
|
// it the clipboard's content.
|
||||||
@ -2827,36 +2871,51 @@ namespace winrt::TerminalApp::implementation
|
|||||||
const auto weakThis = get_weak();
|
const auto weakThis = get_weak();
|
||||||
const auto dispatcher = Dispatcher();
|
const auto dispatcher = Dispatcher();
|
||||||
const auto globalSettings = _settings.GlobalSettings();
|
const auto globalSettings = _settings.GlobalSettings();
|
||||||
|
const auto bracketedPaste = eventArgs.BracketedPasteEnabled();
|
||||||
|
|
||||||
// GetClipboardData might block for up to 30s for delay-rendered contents.
|
// GetClipboardData might block for up to 30s for delay-rendered contents.
|
||||||
co_await winrt::resume_background();
|
co_await winrt::resume_background();
|
||||||
|
|
||||||
winrt::hstring text;
|
winrt::hstring text;
|
||||||
if (const auto clipboard = _openClipboard(nullptr))
|
if (const auto clipboard = clipboard::open(nullptr))
|
||||||
{
|
{
|
||||||
text = _extractClipboard();
|
text = clipboard::read();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalSettings.TrimPaste())
|
if (!bracketedPaste && globalSettings.TrimPaste())
|
||||||
{
|
{
|
||||||
text = { Utils::TrimPaste(text) };
|
text = winrt::hstring{ Utils::TrimPaste(text) };
|
||||||
if (text.empty())
|
}
|
||||||
{
|
|
||||||
// Text is all white space, nothing to paste
|
if (text.empty())
|
||||||
co_return;
|
{
|
||||||
}
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool warnMultiLine = false;
|
||||||
|
switch (globalSettings.WarnAboutMultiLinePaste())
|
||||||
|
{
|
||||||
|
case WarnAboutMultiLinePaste::Automatic:
|
||||||
|
// NOTE that this is unsafe, because a shell that doesn't support bracketed paste
|
||||||
|
// will allow an attacker to enable the mode, not realize that, and then accept
|
||||||
|
// the paste as if it was a series of legitimate commands. See GH#13014.
|
||||||
|
warnMultiLine = !bracketedPaste;
|
||||||
|
break;
|
||||||
|
case WarnAboutMultiLinePaste::Always:
|
||||||
|
warnMultiLine = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnMultiLine = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the requesting terminal is in bracketed paste mode, then we don't need to warn about a multi-line paste.
|
|
||||||
auto warnMultiLine = globalSettings.WarnAboutMultiLinePaste() && !eventArgs.BracketedPasteEnabled();
|
|
||||||
if (warnMultiLine)
|
if (warnMultiLine)
|
||||||
{
|
{
|
||||||
const auto isNewLineLambda = [](auto c) { return c == L'\n' || c == L'\r'; };
|
const std::wstring_view view{ text };
|
||||||
const auto hasNewLine = std::find_if(text.cbegin(), text.cend(), isNewLineLambda) != text.cend();
|
warnMultiLine = view.find_first_of(L"\r\n") != std::wstring_view::npos;
|
||||||
warnMultiLine = hasNewLine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const std::size_t minimumSizeForWarning = 1024 * 5; // 5 KiB
|
constexpr std::size_t minimumSizeForWarning = 1024 * 5; // 5 KiB
|
||||||
const auto warnLargeText = text.size() > minimumSizeForWarning && globalSettings.WarnAboutLargePaste();
|
const auto warnLargeText = text.size() > minimumSizeForWarning && globalSettings.WarnAboutLargePaste();
|
||||||
|
|
||||||
if (warnMultiLine || warnLargeText)
|
if (warnMultiLine || warnLargeText)
|
||||||
@ -2866,7 +2925,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
if (const auto strongThis = weakThis.get())
|
if (const auto strongThis = weakThis.get())
|
||||||
{
|
{
|
||||||
// We have to initialize the dialog here to be able to change the text of the text block within it
|
// We have to initialize the dialog here to be able to change the text of the text block within it
|
||||||
FindName(L"MultiLinePasteDialog").try_as<WUX::Controls::ContentDialog>();
|
std::ignore = FindName(L"MultiLinePasteDialog");
|
||||||
ClipboardText().Text(text);
|
ClipboardText().Text(text);
|
||||||
|
|
||||||
// The vertical offset on the scrollbar does not reset automatically, so reset it manually
|
// The vertical offset on the scrollbar does not reset automatically, so reset it manually
|
||||||
@ -3047,7 +3106,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// - formats: dictate which formats need to be copied
|
// - formats: dictate which formats need to be copied
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - true iff we we able to copy text (if a selection was active)
|
// - true iff we we able to copy text (if a selection was active)
|
||||||
bool TerminalPage::_CopyText(const bool dismissSelection, const bool singleLine, const bool withControlSequences, const Windows::Foundation::IReference<CopyFormat>& formats)
|
bool TerminalPage::_CopyText(const bool dismissSelection, const bool singleLine, const bool withControlSequences, const CopyFormat formats)
|
||||||
{
|
{
|
||||||
if (const auto& control{ _GetActiveControl() })
|
if (const auto& control{ _GetActiveControl() })
|
||||||
{
|
{
|
||||||
@ -3190,6 +3249,21 @@ namespace winrt::TerminalApp::implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalPage::_copyToClipboard(const IInspectable, const WriteToClipboardEventArgs args) const
|
||||||
|
{
|
||||||
|
if (const auto clipboard = clipboard::open(_hostingHwnd.value_or(nullptr)))
|
||||||
|
{
|
||||||
|
const auto plain = args.Plain();
|
||||||
|
const auto html = args.Html();
|
||||||
|
const auto rtf = args.Rtf();
|
||||||
|
|
||||||
|
clipboard::write(
|
||||||
|
{ plain.data(), plain.size() },
|
||||||
|
{ reinterpret_cast<const char*>(html.data()), html.size() },
|
||||||
|
{ reinterpret_cast<const char*>(rtf.data()), rtf.size() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Paste text from the Windows Clipboard to the focused terminal
|
// - Paste text from the Windows Clipboard to the focused terminal
|
||||||
void TerminalPage::_PasteText()
|
void TerminalPage::_PasteText()
|
||||||
|
|||||||
@ -413,10 +413,11 @@ namespace winrt::TerminalApp::implementation
|
|||||||
bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
|
bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
|
||||||
|
|
||||||
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
|
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
|
||||||
bool _CopyText(const bool dismissSelection, const bool singleLine, const bool withControlSequences, const Windows::Foundation::IReference<Microsoft::Terminal::Control::CopyFormat>& formats);
|
bool _CopyText(bool dismissSelection, bool singleLine, bool withControlSequences, Microsoft::Terminal::Control::CopyFormat formats);
|
||||||
|
|
||||||
safe_void_coroutine _SetTaskbarProgressHandler(const IInspectable sender, const IInspectable eventArgs);
|
safe_void_coroutine _SetTaskbarProgressHandler(const IInspectable sender, const IInspectable eventArgs);
|
||||||
|
|
||||||
|
void _copyToClipboard(IInspectable, Microsoft::Terminal::Control::WriteToClipboardEventArgs args) const;
|
||||||
void _PasteText();
|
void _PasteText();
|
||||||
|
|
||||||
safe_void_coroutine _ControlNoticeRaisedHandler(const IInspectable sender, const Microsoft::Terminal::Control::NoticeEventArgs eventArgs);
|
safe_void_coroutine _ControlNoticeRaisedHandler(const IInspectable sender, const Microsoft::Terminal::Control::NoticeEventArgs eventArgs);
|
||||||
|
|||||||
@ -104,8 +104,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// GH#8969: pre-seed working directory to prevent potential races
|
// GH#8969: pre-seed working directory to prevent potential races
|
||||||
_terminal->SetWorkingDirectory(_settings->StartingDirectory());
|
_terminal->SetWorkingDirectory(_settings->StartingDirectory());
|
||||||
|
|
||||||
auto pfnCopyToClipboard = [this](auto&& PH1) { _terminalCopyToClipboard(std::forward<decltype(PH1)>(PH1)); };
|
_terminal->SetCopyToClipboardCallback([this](wil::zwstring_view wstr) {
|
||||||
_terminal->SetCopyToClipboardCallback(pfnCopyToClipboard);
|
WriteToClipboard.raise(*this, winrt::make<WriteToClipboardEventArgs>(winrt::hstring{ std::wstring_view{ wstr } }, std::string{}, std::string{}));
|
||||||
|
});
|
||||||
|
|
||||||
auto pfnWarningBell = [this] { _terminalWarningBell(); };
|
auto pfnWarningBell = [this] { _terminalWarningBell(); };
|
||||||
_terminal->SetWarningBellCallback(pfnWarningBell);
|
_terminal->SetWarningBellCallback(pfnWarningBell);
|
||||||
@ -599,7 +600,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
else if (vkey == VK_RETURN && !mods.IsCtrlPressed() && !mods.IsAltPressed())
|
else if (vkey == VK_RETURN && !mods.IsCtrlPressed() && !mods.IsAltPressed())
|
||||||
{
|
{
|
||||||
// [Shift +] Enter --> copy text
|
// [Shift +] Enter --> copy text
|
||||||
CopySelectionToClipboard(mods.IsShiftPressed(), false, nullptr);
|
CopySelectionToClipboard(mods.IsShiftPressed(), false, _settings->CopyFormatting());
|
||||||
_terminal->ClearSelection();
|
_terminal->ClearSelection();
|
||||||
_updateSelectionUI();
|
_updateSelectionUI();
|
||||||
return true;
|
return true;
|
||||||
@ -1263,89 +1264,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
_updateSelectionUI();
|
_updateSelectionUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
|
|
||||||
{
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
// OpenClipboard may fail to acquire the internal lock --> retry.
|
|
||||||
for (DWORD sleep = 10;; sleep *= 2)
|
|
||||||
{
|
|
||||||
if (OpenClipboard(hwnd))
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 10 iterations
|
|
||||||
if (sleep > 10000)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Sleep(sleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wil::unique_close_clipboard_call{ success };
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _copyToClipboard(const UINT format, const void* src, const size_t bytes)
|
|
||||||
{
|
|
||||||
wil::unique_hglobal handle{ THROW_LAST_ERROR_IF_NULL(GlobalAlloc(GMEM_MOVEABLE, bytes)) };
|
|
||||||
|
|
||||||
const auto locked = GlobalLock(handle.get());
|
|
||||||
memcpy(locked, src, bytes);
|
|
||||||
GlobalUnlock(handle.get());
|
|
||||||
|
|
||||||
THROW_LAST_ERROR_IF_NULL(SetClipboardData(format, handle.get()));
|
|
||||||
handle.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _copyToClipboardRegisteredFormat(const wchar_t* format, const void* src, size_t bytes)
|
|
||||||
{
|
|
||||||
const auto id = RegisterClipboardFormatW(format);
|
|
||||||
if (!id)
|
|
||||||
{
|
|
||||||
LOG_LAST_ERROR();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_copyToClipboard(id, src, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copyToClipboard(wil::zwstring_view text, std::string_view html, std::string_view rtf)
|
|
||||||
{
|
|
||||||
const auto clipboard = _openClipboard(nullptr);
|
|
||||||
if (!clipboard)
|
|
||||||
{
|
|
||||||
LOG_LAST_ERROR();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyClipboard();
|
|
||||||
|
|
||||||
if (!text.empty())
|
|
||||||
{
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!html.empty())
|
|
||||||
{
|
|
||||||
_copyToClipboardRegisteredFormat(L"HTML Format", html.data(), html.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rtf.empty())
|
|
||||||
{
|
|
||||||
_copyToClipboardRegisteredFormat(L"Rich Text Format", rtf.data(), rtf.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the Terminal wants to set something to the clipboard, i.e.
|
|
||||||
// when an OSC 52 is emitted.
|
|
||||||
void ControlCore::_terminalCopyToClipboard(wil::zwstring_view wstr)
|
|
||||||
{
|
|
||||||
copyToClipboard(wstr, {}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Given a copy-able selection, get the selected text from the buffer and send it to the
|
// - Given a copy-able selection, get the selected text from the buffer and send it to the
|
||||||
// Windows Clipboard (CascadiaWin32:main.cpp).
|
// Windows Clipboard (CascadiaWin32:main.cpp).
|
||||||
@ -1356,7 +1274,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// if we should defer which formats are copied to the global setting
|
// if we should defer which formats are copied to the global setting
|
||||||
bool ControlCore::CopySelectionToClipboard(bool singleLine,
|
bool ControlCore::CopySelectionToClipboard(bool singleLine,
|
||||||
bool withControlSequences,
|
bool withControlSequences,
|
||||||
const Windows::Foundation::IReference<CopyFormat>& formats)
|
const CopyFormat formats)
|
||||||
{
|
{
|
||||||
::Microsoft::Terminal::Core::Terminal::TextCopyData payload;
|
::Microsoft::Terminal::Core::Terminal::TextCopyData payload;
|
||||||
{
|
{
|
||||||
@ -1368,19 +1286,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use action's copyFormatting if it's present, else fall back to globally
|
const auto copyHtml = WI_IsFlagSet(formats, CopyFormat::HTML);
|
||||||
// set copyFormatting.
|
const auto copyRtf = WI_IsFlagSet(formats, CopyFormat::RTF);
|
||||||
const auto copyFormats = formats != nullptr ? formats.Value() : _settings->CopyFormatting();
|
|
||||||
|
|
||||||
const auto copyHtml = WI_IsFlagSet(copyFormats, CopyFormat::HTML);
|
|
||||||
const auto copyRtf = WI_IsFlagSet(copyFormats, CopyFormat::RTF);
|
|
||||||
|
|
||||||
// extract text from buffer
|
// extract text from buffer
|
||||||
// RetrieveSelectedTextFromBuffer will lock while it's reading
|
// RetrieveSelectedTextFromBuffer will lock while it's reading
|
||||||
payload = _terminal->RetrieveSelectedTextFromBuffer(singleLine, withControlSequences, copyHtml, copyRtf);
|
payload = _terminal->RetrieveSelectedTextFromBuffer(singleLine, withControlSequences, copyHtml, copyRtf);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyToClipboard(payload.plainText, payload.html, payload.rtf);
|
WriteToClipboard.raise(
|
||||||
|
*this,
|
||||||
|
winrt::make<WriteToClipboardEventArgs>(
|
||||||
|
winrt::hstring{ payload.plainText },
|
||||||
|
std::move(payload.html),
|
||||||
|
std::move(payload.rtf)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
|
|
||||||
void SendInput(std::wstring_view wstr);
|
void SendInput(std::wstring_view wstr);
|
||||||
void PasteText(const winrt::hstring& hstr);
|
void PasteText(const winrt::hstring& hstr);
|
||||||
bool CopySelectionToClipboard(bool singleLine, bool withControlSequences, const Windows::Foundation::IReference<CopyFormat>& formats);
|
bool CopySelectionToClipboard(bool singleLine, bool withControlSequences, const CopyFormat formats);
|
||||||
void SelectAll();
|
void SelectAll();
|
||||||
void ClearSelection();
|
void ClearSelection();
|
||||||
bool ToggleBlockSelection();
|
bool ToggleBlockSelection();
|
||||||
@ -277,6 +277,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
til::typed_event<IInspectable, Control::FontSizeChangedArgs> FontSizeChanged;
|
til::typed_event<IInspectable, Control::FontSizeChangedArgs> FontSizeChanged;
|
||||||
|
|
||||||
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
|
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
|
||||||
|
til::typed_event<IInspectable, Control::WriteToClipboardEventArgs> WriteToClipboard;
|
||||||
til::typed_event<> WarningBell;
|
til::typed_event<> WarningBell;
|
||||||
til::typed_event<> TabColorChanged;
|
til::typed_event<> TabColorChanged;
|
||||||
til::typed_event<> BackgroundColorChanged;
|
til::typed_event<> BackgroundColorChanged;
|
||||||
@ -325,7 +326,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
void _sendInputToConnection(std::wstring_view wstr);
|
void _sendInputToConnection(std::wstring_view wstr);
|
||||||
|
|
||||||
#pragma region TerminalCoreCallbacks
|
#pragma region TerminalCoreCallbacks
|
||||||
void _terminalCopyToClipboard(wil::zwstring_view wstr);
|
|
||||||
void _terminalWarningBell();
|
void _terminalWarningBell();
|
||||||
void _terminalTitleChanged(std::wstring_view wstr);
|
void _terminalTitleChanged(std::wstring_view wstr);
|
||||||
void _terminalScrollPositionChanged(const int viewTop,
|
void _terminalScrollPositionChanged(const int viewTop,
|
||||||
|
|||||||
@ -185,6 +185,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
|
|
||||||
// These events are called from some background thread
|
// These events are called from some background thread
|
||||||
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||||
|
event Windows.Foundation.TypedEventHandler<Object, WriteToClipboardEventArgs> WriteToClipboard;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
|
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
|
||||||
|
|||||||
@ -199,7 +199,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// if we should defer which formats are copied to the global setting
|
// if we should defer which formats are copied to the global setting
|
||||||
bool ControlInteractivity::CopySelectionToClipboard(bool singleLine,
|
bool ControlInteractivity::CopySelectionToClipboard(bool singleLine,
|
||||||
bool withControlSequences,
|
bool withControlSequences,
|
||||||
const Windows::Foundation::IReference<CopyFormat>& formats)
|
const CopyFormat formats)
|
||||||
{
|
{
|
||||||
if (_core)
|
if (_core)
|
||||||
{
|
{
|
||||||
@ -316,7 +316,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Try to copy the text and clear the selection
|
// Try to copy the text and clear the selection
|
||||||
const auto successfulCopy = CopySelectionToClipboard(shiftEnabled, false, nullptr);
|
const auto successfulCopy = CopySelectionToClipboard(shiftEnabled, false, _core->Settings().CopyFormatting());
|
||||||
_core->ClearSelection();
|
_core->ClearSelection();
|
||||||
if (_core->CopyOnSelect() || !successfulCopy)
|
if (_core->CopyOnSelect() || !successfulCopy)
|
||||||
{
|
{
|
||||||
@ -461,7 +461,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// IMPORTANT!
|
// IMPORTANT!
|
||||||
// DO NOT clear the selection here!
|
// DO NOT clear the selection here!
|
||||||
// Otherwise, the selection will be cleared immediately after you make it.
|
// Otherwise, the selection will be cleared immediately after you make it.
|
||||||
CopySelectionToClipboard(false, false, nullptr);
|
CopySelectionToClipboard(false, false, _core->Settings().CopyFormatting());
|
||||||
}
|
}
|
||||||
|
|
||||||
_singleClickTouchdownPos = std::nullopt;
|
_singleClickTouchdownPos = std::nullopt;
|
||||||
|
|||||||
@ -84,7 +84,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
|
|
||||||
bool CopySelectionToClipboard(bool singleLine,
|
bool CopySelectionToClipboard(bool singleLine,
|
||||||
bool withControlSequences,
|
bool withControlSequences,
|
||||||
const Windows::Foundation::IReference<CopyFormat>& formats);
|
const CopyFormat formats);
|
||||||
void RequestPasteTextFromClipboard();
|
void RequestPasteTextFromClipboard();
|
||||||
void SetEndSelectionPoint(const Core::Point pixelPosition);
|
void SetEndSelectionPoint(const Core::Point pixelPosition);
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
|
|
||||||
InteractivityAutomationPeer OnCreateAutomationPeer();
|
InteractivityAutomationPeer OnCreateAutomationPeer();
|
||||||
|
|
||||||
Boolean CopySelectionToClipboard(Boolean singleLine, Boolean withControlSequences, Windows.Foundation.IReference<CopyFormat> formats);
|
Boolean CopySelectionToClipboard(Boolean singleLine, Boolean withControlSequences, CopyFormat formats);
|
||||||
void RequestPasteTextFromClipboard();
|
void RequestPasteTextFromClipboard();
|
||||||
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);
|
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "FontSizeChangedArgs.g.cpp"
|
#include "FontSizeChangedArgs.g.cpp"
|
||||||
#include "TitleChangedEventArgs.g.cpp"
|
#include "TitleChangedEventArgs.g.cpp"
|
||||||
#include "ContextMenuRequestedEventArgs.g.cpp"
|
#include "ContextMenuRequestedEventArgs.g.cpp"
|
||||||
|
#include "WriteToClipboardEventArgs.g.cpp"
|
||||||
#include "PasteFromClipboardEventArgs.g.cpp"
|
#include "PasteFromClipboardEventArgs.g.cpp"
|
||||||
#include "OpenHyperlinkEventArgs.g.cpp"
|
#include "OpenHyperlinkEventArgs.g.cpp"
|
||||||
#include "NoticeEventArgs.g.cpp"
|
#include "NoticeEventArgs.g.cpp"
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "FontSizeChangedArgs.g.h"
|
#include "FontSizeChangedArgs.g.h"
|
||||||
#include "TitleChangedEventArgs.g.h"
|
#include "TitleChangedEventArgs.g.h"
|
||||||
#include "ContextMenuRequestedEventArgs.g.h"
|
#include "ContextMenuRequestedEventArgs.g.h"
|
||||||
|
#include "WriteToClipboardEventArgs.g.h"
|
||||||
#include "PasteFromClipboardEventArgs.g.h"
|
#include "PasteFromClipboardEventArgs.g.h"
|
||||||
#include "OpenHyperlinkEventArgs.g.h"
|
#include "OpenHyperlinkEventArgs.g.h"
|
||||||
#include "NoticeEventArgs.g.h"
|
#include "NoticeEventArgs.g.h"
|
||||||
@ -56,6 +57,32 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
WINRT_PROPERTY(winrt::Windows::Foundation::Point, Position);
|
WINRT_PROPERTY(winrt::Windows::Foundation::Point, Position);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WriteToClipboardEventArgs : WriteToClipboardEventArgsT<WriteToClipboardEventArgs>
|
||||||
|
{
|
||||||
|
WriteToClipboardEventArgs(winrt::hstring&& plain, std::string&& html, std::string&& rtf) :
|
||||||
|
_plain(std::move(plain)),
|
||||||
|
_html(std::move(html)),
|
||||||
|
_rtf(std::move(rtf))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::hstring Plain() const noexcept { return _plain; }
|
||||||
|
winrt::com_array<uint8_t> Html() noexcept { return _cast(_html); }
|
||||||
|
winrt::com_array<uint8_t> Rtf() noexcept { return _cast(_rtf); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static winrt::com_array<uint8_t> _cast(const std::string& str)
|
||||||
|
{
|
||||||
|
const auto beg = reinterpret_cast<const uint8_t*>(str.data());
|
||||||
|
const auto len = str.size();
|
||||||
|
return { beg, beg + len };
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::hstring _plain;
|
||||||
|
std::string _html;
|
||||||
|
std::string _rtf;
|
||||||
|
};
|
||||||
|
|
||||||
struct PasteFromClipboardEventArgs : public PasteFromClipboardEventArgsT<PasteFromClipboardEventArgs>
|
struct PasteFromClipboardEventArgs : public PasteFromClipboardEventArgsT<PasteFromClipboardEventArgs>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -6,6 +6,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
[flags]
|
[flags]
|
||||||
enum CopyFormat
|
enum CopyFormat
|
||||||
{
|
{
|
||||||
|
None = 0x0,
|
||||||
HTML = 0x1,
|
HTML = 0x1,
|
||||||
RTF = 0x2,
|
RTF = 0x2,
|
||||||
All = 0xffffffff
|
All = 0xffffffff
|
||||||
@ -31,6 +32,13 @@ namespace Microsoft.Terminal.Control
|
|||||||
AlphanumericHalfWidth,
|
AlphanumericHalfWidth,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum WarnAboutMultiLinePaste
|
||||||
|
{
|
||||||
|
Automatic,
|
||||||
|
Always,
|
||||||
|
Never,
|
||||||
|
};
|
||||||
|
|
||||||
runtimeclass FontSizeChangedArgs
|
runtimeclass FontSizeChangedArgs
|
||||||
{
|
{
|
||||||
Int32 Width { get; };
|
Int32 Width { get; };
|
||||||
@ -47,6 +55,13 @@ namespace Microsoft.Terminal.Control
|
|||||||
String Title;
|
String Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runtimeclass WriteToClipboardEventArgs
|
||||||
|
{
|
||||||
|
String Plain { get; }; // UTF-16, as required by CF_UNICODETEXT
|
||||||
|
byte[] Html { get; }; // UTF-8, as required by "HTML Format"
|
||||||
|
byte[] Rtf { get; }; // UTF-8, as required by "Rich Text Format"
|
||||||
|
}
|
||||||
|
|
||||||
runtimeclass PasteFromClipboardEventArgs
|
runtimeclass PasteFromClipboardEventArgs
|
||||||
{
|
{
|
||||||
void HandleClipboardData(String data);
|
void HandleClipboardData(String data);
|
||||||
|
|||||||
@ -330,6 +330,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
_revokers.RestartTerminalRequested = _core.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleRestartTerminalRequested });
|
_revokers.RestartTerminalRequested = _core.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleRestartTerminalRequested });
|
||||||
_revokers.SearchMissingCommand = _core.SearchMissingCommand(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSearchMissingCommand });
|
_revokers.SearchMissingCommand = _core.SearchMissingCommand(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSearchMissingCommand });
|
||||||
_revokers.WindowSizeChanged = _core.WindowSizeChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWindowSizeChanged });
|
_revokers.WindowSizeChanged = _core.WindowSizeChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWindowSizeChanged });
|
||||||
|
_revokers.WriteToClipboard = _core.WriteToClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWriteToClipboard });
|
||||||
|
|
||||||
_revokers.PasteFromClipboard = _interactivity.PasteFromClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubblePasteFromClipboard });
|
_revokers.PasteFromClipboard = _interactivity.PasteFromClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubblePasteFromClipboard });
|
||||||
|
|
||||||
@ -2634,7 +2635,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// - withControlSequences: if enabled, the copied plain text contains color/style ANSI escape codes from the selection
|
// - withControlSequences: if enabled, the copied plain text contains color/style ANSI escape codes from the selection
|
||||||
// - formats: which formats to copy (defined by action's CopyFormatting arg). nullptr
|
// - formats: which formats to copy (defined by action's CopyFormatting arg). nullptr
|
||||||
// if we should defer which formats are copied to the global setting
|
// if we should defer which formats are copied to the global setting
|
||||||
bool TermControl::CopySelectionToClipboard(bool dismissSelection, bool singleLine, bool withControlSequences, const Windows::Foundation::IReference<CopyFormat>& formats)
|
bool TermControl::CopySelectionToClipboard(bool dismissSelection, bool singleLine, bool withControlSequences, const CopyFormat formats)
|
||||||
{
|
{
|
||||||
if (_IsClosing())
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
@ -4153,7 +4154,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
const IInspectable& /*args*/)
|
const IInspectable& /*args*/)
|
||||||
{
|
{
|
||||||
// formats = nullptr -> copy all formats
|
// formats = nullptr -> copy all formats
|
||||||
_interactivity.CopySelectionToClipboard(false, false, nullptr);
|
_interactivity.CopySelectionToClipboard(false, false, _core.Settings().CopyFormatting());
|
||||||
ContextMenu().Hide();
|
ContextMenu().Hide();
|
||||||
SelectionContextMenu().Hide();
|
SelectionContextMenu().Hide();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
|
|
||||||
hstring GetProfileName() const;
|
hstring GetProfileName() const;
|
||||||
|
|
||||||
bool CopySelectionToClipboard(bool dismissSelection, bool singleLine, bool withControlSequences, const Windows::Foundation::IReference<CopyFormat>& formats);
|
bool CopySelectionToClipboard(bool dismissSelection, bool singleLine, bool withControlSequences, const CopyFormat formats);
|
||||||
void PasteTextFromClipboard();
|
void PasteTextFromClipboard();
|
||||||
void SelectAll();
|
void SelectAll();
|
||||||
bool ToggleBlockSelection();
|
bool ToggleBlockSelection();
|
||||||
@ -227,8 +227,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
BUBBLED_FORWARDED_TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
BUBBLED_FORWARDED_TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||||
BUBBLED_FORWARDED_TYPED_EVENT(CompletionsChanged, IInspectable, Control::CompletionsChangedEventArgs);
|
BUBBLED_FORWARDED_TYPED_EVENT(CompletionsChanged, IInspectable, Control::CompletionsChangedEventArgs);
|
||||||
BUBBLED_FORWARDED_TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);
|
BUBBLED_FORWARDED_TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);
|
||||||
|
BUBBLED_FORWARDED_TYPED_EVENT(WriteToClipboard, IInspectable, Control::WriteToClipboardEventArgs);
|
||||||
BUBBLED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
BUBBLED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -463,6 +463,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
Control::ControlCore::UpdateSelectionMarkers_revoker UpdateSelectionMarkers;
|
Control::ControlCore::UpdateSelectionMarkers_revoker UpdateSelectionMarkers;
|
||||||
Control::ControlCore::OpenHyperlink_revoker coreOpenHyperlink;
|
Control::ControlCore::OpenHyperlink_revoker coreOpenHyperlink;
|
||||||
Control::ControlCore::TitleChanged_revoker TitleChanged;
|
Control::ControlCore::TitleChanged_revoker TitleChanged;
|
||||||
|
Control::ControlCore::WriteToClipboard_revoker WriteToClipboard;
|
||||||
Control::ControlCore::TabColorChanged_revoker TabColorChanged;
|
Control::ControlCore::TabColorChanged_revoker TabColorChanged;
|
||||||
Control::ControlCore::TaskbarProgressChanged_revoker TaskbarProgressChanged;
|
Control::ControlCore::TaskbarProgressChanged_revoker TaskbarProgressChanged;
|
||||||
Control::ControlCore::ConnectionStateChanged_revoker ConnectionStateChanged;
|
Control::ControlCore::ConnectionStateChanged_revoker ConnectionStateChanged;
|
||||||
|
|||||||
@ -53,6 +53,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
Microsoft.Terminal.Control.IControlSettings Settings { get; };
|
Microsoft.Terminal.Control.IControlSettings Settings { get; };
|
||||||
|
|
||||||
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||||
|
event Windows.Foundation.TypedEventHandler<Object, WriteToClipboardEventArgs> WriteToClipboard;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||||
@ -87,7 +88,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
|
event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, Object> RestartTerminalRequested;
|
event Windows.Foundation.TypedEventHandler<Object, Object> RestartTerminalRequested;
|
||||||
|
|
||||||
Boolean CopySelectionToClipboard(Boolean dismissSelection, Boolean singleLine, Boolean withControlSequences, Windows.Foundation.IReference<CopyFormat> formats);
|
Boolean CopySelectionToClipboard(Boolean dismissSelection, Boolean singleLine, Boolean withControlSequences, CopyFormat formats);
|
||||||
void PasteTextFromClipboard();
|
void PasteTextFromClipboard();
|
||||||
void SelectAll();
|
void SelectAll();
|
||||||
Boolean ToggleBlockSelection();
|
Boolean ToggleBlockSelection();
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include "Interaction.h"
|
#include "Interaction.h"
|
||||||
#include "Interaction.g.cpp"
|
#include "Interaction.g.cpp"
|
||||||
|
|
||||||
|
#include "EnumEntry.h"
|
||||||
|
|
||||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||||
|
|
||||||
@ -13,6 +15,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
Interaction::Interaction()
|
Interaction::Interaction()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
INITIALIZE_BINDABLE_ENUM_SETTING(WarnAboutMultiLinePaste, WarnAboutMultiLinePaste, winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste, L"Globals_WarnAboutMultiLinePaste", L"Content");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interaction::OnNavigatedTo(const NavigationEventArgs& e)
|
void Interaction::OnNavigatedTo(const NavigationEventArgs& e)
|
||||||
|
|||||||
@ -16,6 +16,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
|
|
||||||
til::property_changed_event PropertyChanged;
|
til::property_changed_event PropertyChanged;
|
||||||
WINRT_OBSERVABLE_PROPERTY(Editor::InteractionViewModel, ViewModel, PropertyChanged.raise, nullptr);
|
WINRT_OBSERVABLE_PROPERTY(Editor::InteractionViewModel, ViewModel, PropertyChanged.raise, nullptr);
|
||||||
|
GETSET_BINDABLE_ENUM_SETTING(WarnAboutMultiLinePaste, winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste, ViewModel().WarnAboutMultiLinePaste);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,5 +9,8 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||||||
{
|
{
|
||||||
Interaction();
|
Interaction();
|
||||||
InteractionViewModel ViewModel { get; };
|
InteractionViewModel ViewModel { get; };
|
||||||
|
|
||||||
|
IInspectable CurrentWarnAboutMultiLinePaste;
|
||||||
|
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> WarnAboutMultiLinePasteList { get; };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -142,8 +142,11 @@
|
|||||||
|
|
||||||
<!-- Multi Line Paste Warning -->
|
<!-- Multi Line Paste Warning -->
|
||||||
<local:SettingContainer x:Uid="Globals_WarnAboutMultiLinePaste">
|
<local:SettingContainer x:Uid="Globals_WarnAboutMultiLinePaste">
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.WarnAboutMultiLinePaste, Mode=TwoWay}"
|
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||||
|
ItemsSource="{x:Bind WarnAboutMultiLinePasteList}"
|
||||||
|
SelectedItem="{x:Bind CurrentWarnAboutMultiLinePaste, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource ComboBoxSettingStyle}" />
|
||||||
</local:SettingContainer>
|
</local:SettingContainer>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -30,7 +30,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ConfirmCloseAllTabs);
|
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ConfirmCloseAllTabs);
|
||||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, InputServiceWarning);
|
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, InputServiceWarning);
|
||||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, WarnAboutLargePaste);
|
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, WarnAboutLargePaste);
|
||||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, WarnAboutMultiLinePaste);
|
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Microsoft.Terminal.Control.WarnAboutMultiLinePaste, WarnAboutMultiLinePaste);
|
||||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, EnableColorSelection);
|
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, EnableColorSelection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1924,10 +1924,26 @@
|
|||||||
<value>Warn when "Touch Keyboard and Handwriting Panel Service" is disabled</value>
|
<value>Warn when "Touch Keyboard and Handwriting Panel Service" is disabled</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Globals_WarnAboutLargePaste.Header" xml:space="preserve">
|
<data name="Globals_WarnAboutLargePaste.Header" xml:space="preserve">
|
||||||
<value>Warn when trying to paste more than 5 KiB of characters</value>
|
<value>Warn when pasting more than 5 KiB</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Globals_WarnAboutMultiLinePaste.Header" xml:space="preserve">
|
<data name="Globals_WarnAboutMultiLinePaste.Header" xml:space="preserve">
|
||||||
<value>Warn when trying to paste a "new line" character</value>
|
<value>Warn when pasting newlines</value>
|
||||||
|
</data>
|
||||||
|
<data name="Globals_WarnAboutMultiLinePaste.HelpText" xml:space="preserve">
|
||||||
|
<value>If your shell does not support "bracketed paste" mode, we recommend setting this to "Always" for security reasons.</value>
|
||||||
|
<comment>"bracketed paste" is a technical term referring to escape sequences. "Always" is a setting, as in "Always VS Never".</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Globals_WarnAboutMultiLinePasteAutomatic.Content" xml:space="preserve">
|
||||||
|
<value>Only if "bracketed paste" is disabled</value>
|
||||||
|
<comment>"bracketed paste" is a technical term referring to terminal escape sequences.</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Globals_WarnAboutMultiLinePasteAlways.Content" xml:space="preserve">
|
||||||
|
<value>Always</value>
|
||||||
|
<comment>As in: Always VS Never</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Globals_WarnAboutMultiLinePasteNever.Content" xml:space="preserve">
|
||||||
|
<value>Never</value>
|
||||||
|
<comment>As in: Always VS Never</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="Settings_PortableModeNote.Text" xml:space="preserve">
|
<data name="Settings_PortableModeNote.Text" xml:space="preserve">
|
||||||
<value>Windows Terminal is running in portable mode.</value>
|
<value>Windows Terminal is running in portable mode.</value>
|
||||||
|
|||||||
@ -42,6 +42,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
DEFINE_ENUM_MAP(Microsoft::Terminal::Core::MatchMode, MatchMode);
|
DEFINE_ENUM_MAP(Microsoft::Terminal::Core::MatchMode, MatchMode);
|
||||||
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::GraphicsAPI, GraphicsAPI);
|
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::GraphicsAPI, GraphicsAPI);
|
||||||
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::TextMeasurement, TextMeasurement);
|
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::TextMeasurement, TextMeasurement);
|
||||||
|
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::WarnAboutMultiLinePaste, WarnAboutMultiLinePaste);
|
||||||
|
|
||||||
// Profile Settings
|
// Profile Settings
|
||||||
DEFINE_ENUM_MAP(Model::CloseOnExitMode, CloseOnExitMode);
|
DEFINE_ENUM_MAP(Model::CloseOnExitMode, CloseOnExitMode);
|
||||||
|
|||||||
@ -38,6 +38,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Core::MatchMode> MatchMode();
|
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Core::MatchMode> MatchMode();
|
||||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::GraphicsAPI> GraphicsAPI();
|
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::GraphicsAPI> GraphicsAPI();
|
||||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::TextMeasurement> TextMeasurement();
|
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::TextMeasurement> TextMeasurement();
|
||||||
|
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste> WarnAboutMultiLinePaste();
|
||||||
|
|
||||||
// Profile Settings
|
// Profile Settings
|
||||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, CloseOnExitMode> CloseOnExitMode();
|
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, CloseOnExitMode> CloseOnExitMode();
|
||||||
|
|||||||
@ -20,6 +20,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Core.MatchMode> MatchMode { get; };
|
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Core.MatchMode> MatchMode { get; };
|
||||||
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.GraphicsAPI> GraphicsAPI { get; };
|
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.GraphicsAPI> GraphicsAPI { get; };
|
||||||
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.TextMeasurement> TextMeasurement { get; };
|
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.TextMeasurement> TextMeasurement { get; };
|
||||||
|
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.WarnAboutMultiLinePaste> WarnAboutMultiLinePaste { get; };
|
||||||
|
|
||||||
// Profile Settings
|
// Profile Settings
|
||||||
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.CloseOnExitMode> CloseOnExitMode { get; };
|
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.CloseOnExitMode> CloseOnExitMode { get; };
|
||||||
|
|||||||
@ -70,7 +70,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
INHERITABLE_SETTING(Boolean, InputServiceWarning);
|
INHERITABLE_SETTING(Boolean, InputServiceWarning);
|
||||||
INHERITABLE_SETTING(Microsoft.Terminal.Control.CopyFormat, CopyFormatting);
|
INHERITABLE_SETTING(Microsoft.Terminal.Control.CopyFormat, CopyFormatting);
|
||||||
INHERITABLE_SETTING(Boolean, WarnAboutLargePaste);
|
INHERITABLE_SETTING(Boolean, WarnAboutLargePaste);
|
||||||
INHERITABLE_SETTING(Boolean, WarnAboutMultiLinePaste);
|
INHERITABLE_SETTING(Microsoft.Terminal.Control.WarnAboutMultiLinePaste, WarnAboutMultiLinePaste);
|
||||||
INHERITABLE_SETTING(Boolean, TrimPaste);
|
INHERITABLE_SETTING(Boolean, TrimPaste);
|
||||||
INHERITABLE_SETTING(LaunchPosition, InitialPosition);
|
INHERITABLE_SETTING(LaunchPosition, InitialPosition);
|
||||||
INHERITABLE_SETTING(Boolean, CenterOnLaunch);
|
INHERITABLE_SETTING(Boolean, CenterOnLaunch);
|
||||||
|
|||||||
@ -46,7 +46,7 @@ Author(s):
|
|||||||
X(bool, InputServiceWarning, "warning.inputService", true) \
|
X(bool, InputServiceWarning, "warning.inputService", true) \
|
||||||
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, "copyFormatting", 0) \
|
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, "copyFormatting", 0) \
|
||||||
X(bool, WarnAboutLargePaste, "warning.largePaste", true) \
|
X(bool, WarnAboutLargePaste, "warning.largePaste", true) \
|
||||||
X(bool, WarnAboutMultiLinePaste, "warning.multiLinePaste", true) \
|
X(winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste, WarnAboutMultiLinePaste, "warning.multiLinePaste", winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste::Automatic) \
|
||||||
X(Model::LaunchPosition, InitialPosition, "initialPosition", nullptr, nullptr) \
|
X(Model::LaunchPosition, InitialPosition, "initialPosition", nullptr, nullptr) \
|
||||||
X(bool, CenterOnLaunch, "centerOnLaunch", false) \
|
X(bool, CenterOnLaunch, "centerOnLaunch", false) \
|
||||||
X(Model::FirstWindowPreference, FirstWindowPreference, "firstWindowPreference", FirstWindowPreference::DefaultProfile) \
|
X(Model::FirstWindowPreference, FirstWindowPreference, "firstWindowPreference", FirstWindowPreference::DefaultProfile) \
|
||||||
|
|||||||
@ -841,3 +841,29 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::PathTranslationStyle)
|
|||||||
pair_type{ "mingw", ValueType::MinGW },
|
pair_type{ "mingw", ValueType::MinGW },
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste)
|
||||||
|
{
|
||||||
|
JSON_MAPPINGS(3) = {
|
||||||
|
pair_type{ "automatic", ValueType::Automatic },
|
||||||
|
pair_type{ "always", ValueType::Always },
|
||||||
|
pair_type{ "never", ValueType::Never },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override mapping parser to add boolean parsing
|
||||||
|
::winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste FromJson(const Json::Value& json)
|
||||||
|
{
|
||||||
|
if (json.isBool())
|
||||||
|
{
|
||||||
|
return json.asBool() ? ValueType::Automatic : ValueType::Never;
|
||||||
|
}
|
||||||
|
return EnumMapper::FromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanConvert(const Json::Value& json)
|
||||||
|
{
|
||||||
|
return EnumMapper::CanConvert(json) || json.isBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
using EnumMapper::TypeDescription;
|
||||||
|
};
|
||||||
|
|||||||
@ -128,7 +128,7 @@ namespace SettingsModelUnitTests
|
|||||||
"warning.confirmCloseAllTabs" : true,
|
"warning.confirmCloseAllTabs" : true,
|
||||||
"warning.inputService" : true,
|
"warning.inputService" : true,
|
||||||
"warning.largePaste" : true,
|
"warning.largePaste" : true,
|
||||||
"warning.multiLinePaste" : true,
|
"warning.multiLinePaste" : "automatic",
|
||||||
|
|
||||||
"actions": [],
|
"actions": [],
|
||||||
"keybindings": []
|
"keybindings": []
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user