Compare commits

...

14 Commits

Author SHA1 Message Date
Dustin L. Howett
17cdf292b5 Enlighten bracketed paste detection for broadcast groups 2026-05-14 20:11:36 -05:00
Dustin L. Howett
ea192b2d94 Translate Drag/Drop paths differently per profile ! 2026-05-14 20:11:36 -05:00
Dustin L. Howett
39601d4703 Remove WriteInputStringWithoutBroadcast and the horrible StringSent event 2026-05-14 20:11:36 -05:00
Dustin L. Howett
9833cbf8ba Port drag-drop to the broadcast helper 2026-05-14 20:11:36 -05:00
Dustin L. Howett
ff8fe85d72 Make Drag/Drop a Page concern, not a TermControl concern 2026-05-14 20:11:36 -05:00
Dustin L. Howett
45813925dd Add a helper, _writeInputStringToControlAndBroadcastGroup
Add the broadcast group helpers

Port paste to the broadcast helpers
2026-05-14 20:11:33 -05:00
Dustin L. Howett
fc37791900 Maintain a weak mapping from control to panecontent to speed up 1:1 control lookups 2026-05-14 20:11:08 -05:00
Dustin L. Howett
d0b9c0a0b0 Remove manual broadcasting since WriteInputString calls StringSent (!) 2026-05-14 20:10:55 -05:00
Dustin L. Howett
441ec83514 Clarify hasAnyUnbracketed comment 2026-04-30 10:40:19 -05:00
Dustin L. Howett
39316fb266 Ah, RawWriteString was load bearing; return it as a stopgap 2026-04-30 10:12:47 -05:00
Dustin L. Howett
ed93677edf Remove PasteFromClipboardEventArgs entirely 2026-04-29 19:13:31 -05:00
Dustin L. Howett
d6d3be40cc Remove the paste backflow event handler, and use WriteInputString directly 2026-04-29 19:12:25 -05:00
Dustin L. Howett
39822d1a5e Control: make bubbled events use the Control's identity as sender
I've audited all the events, and the only one that tried to use IControlInteractivity or similar was Paste
2026-04-29 19:12:24 -05:00
Dustin L. Howett
1395d17e07 TermControl: replace SendInput/PasteText with WriteInputString(Type)
and Port the rest of the app to WriteInputString
2026-04-29 19:12:22 -05:00
27 changed files with 455 additions and 471 deletions

View File

@@ -185,7 +185,8 @@ namespace winrt::TerminalApp::implementation
{
if (const auto termControl{ _senderOrActiveControl(sender) })
{
termControl.SendInput(realArgs.Input());
const auto broadcastGroup{ _getBroadcastGroupFromControl(termControl) };
_writeInputStringToBroadcastGroup(broadcastGroup, realArgs.Input(), WriteInputStringType::Raw);
args.Handled(true);
}
}
@@ -452,8 +453,11 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandlePasteText(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_PasteText();
args.Handled(true);
if (const auto& control{ _GetActiveControl() })
{
_PasteFromClipboardHandler(control, nullptr);
args.Handled(true);
}
}
void TerminalPage::_HandleNewTab(const IInspectable& /*sender*/,

View File

@@ -3044,14 +3044,15 @@ void Pane::BroadcastChar(const winrt::Microsoft::Terminal::Control::TermControl&
}
void Pane::BroadcastString(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl,
const winrt::hstring& text)
const winrt::hstring& text,
const winrt::Microsoft::Terminal::Control::WriteInputStringType type)
{
WalkTree([&](const auto& pane) {
if (const auto& termControl{ pane->GetTerminalControl() })
{
if (termControl != sourceControl && !termControl.ReadOnly())
{
termControl.RawWriteString(text);
termControl.WriteInputString(text, type);
}
}
});

View File

@@ -152,7 +152,7 @@ public:
void EnableBroadcast(bool enabled);
void BroadcastKey(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const WORD vkey, const WORD scanCode, const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool keyDown);
void BroadcastChar(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const wchar_t vkey, const WORD scanCode, const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers);
void BroadcastString(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const winrt::hstring& text);
void BroadcastString(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const winrt::hstring& text, const winrt::Microsoft::Terminal::Control::WriteInputStringType type);
void UpdateResources(const PaneResources& resources);

View File

@@ -929,4 +929,12 @@
<data name="InvalidRegex" xml:space="preserve">
<value>An invalid regular expression was found.</value>
</data>
<data name="DragFileCaption" xml:space="preserve">
<value>Paste path to file</value>
<comment>The displayed caption for dragging a file onto a terminal.</comment>
</data>
<data name="DragTextCaption" xml:space="preserve">
<value>Paste text</value>
<comment>The displayed caption for dragging text onto a terminal.</comment>
</data>
</root>

View File

@@ -2174,7 +2174,6 @@ namespace winrt::TerminalApp::implementation
// Always clear out old ones, just in case.
events.KeySent.revoke();
events.CharSent.revoke();
events.StringSent.revoke();
if (newIsBroadcasting)
{
@@ -2215,17 +2214,6 @@ namespace winrt::TerminalApp::implementation
}
}
});
events.StringSent = termControl.StringSent(winrt::auto_revoke, [weakThis](auto&& sender, auto&& e) {
if (const auto tab{ weakThis.get() })
{
if (tab->_tabStatus.IsInputBroadcastActive())
{
tab->_rootPane->BroadcastString(sender.try_as<TermControl>(),
e.Text());
}
}
});
}
void Tab::ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,

View File

@@ -186,7 +186,6 @@ namespace winrt::TerminalApp::implementation
// These events literally only apply if the content is a TermControl.
winrt::Microsoft::Terminal::Control::TermControl::KeySent_revoker KeySent;
winrt::Microsoft::Terminal::Control::TermControl::CharSent_revoker CharSent;
winrt::Microsoft::Terminal::Control::TermControl::StringSent_revoker StringSent;
winrt::TerminalApp::TerminalPaneContent::RestartTerminalRequested_revoker RestartTerminalRequested;
};

View File

@@ -37,6 +37,7 @@ using namespace winrt::Microsoft::Terminal::TerminalConnection;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Storage::Streams;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Core;
@@ -1964,6 +1965,9 @@ namespace winrt::TerminalApp::implementation
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
term.DragOver({ this, &TerminalPage::_ControlDragOverHandler });
term.Drop({ this, &TerminalPage::_ControlDragDropHandler });
// Add an event handler for when the terminal or tab wants to set a
// progress indicator on the taskbar
term.SetTaskbarProgress({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
@@ -2945,9 +2949,7 @@ namespace winrt::TerminalApp::implementation
// - Sends the text back to the TermControl through the event's
// `HandleClipboardData` member function.
// - Does some of this in a background thread, as to not hang/crash the UI thread.
// Arguments:
// - eventArgs: the PasteFromClipboard event sent from the TermControl
safe_void_coroutine TerminalPage::_PasteFromClipboardHandler(const IInspectable sender, const PasteFromClipboardEventArgs eventArgs)
safe_void_coroutine TerminalPage::_PasteFromClipboardHandler(const IInspectable sender, const IInspectable /* args */)
try
{
// The old Win32 clipboard API as used below is somewhere in the order of 300-1000x faster than
@@ -2955,8 +2957,19 @@ namespace winrt::TerminalApp::implementation
const auto weakThis = get_weak();
const auto dispatcher = Dispatcher();
const auto globalSettings = _settings.GlobalSettings();
const auto bracketedPaste = eventArgs.BracketedPasteEnabled();
const auto sourceId = sender.try_as<ControlInteractivity>().Id();
const auto control = sender.as<TermControl>();
const auto broadcastGroup = _getBroadcastGroupFromControl(control);
// Used to determine whether to emit empty pastes and strip extra whitespace
const auto anyHasBracketedPaste = std::any_of(std::begin(broadcastGroup), std::end(broadcastGroup), [](auto&& content) {
const auto control{ content.GetTermControl() };
return control && !control.ReadOnly() && control.BracketedPasteEnabled();
});
// Used to determine whether to warn on multi-line paste
// If none lack bracketed paste, we can skip the warning.
const auto anyHasUnbracketedPaste = !anyHasBracketedPaste || std::any_of(std::begin(broadcastGroup), std::end(broadcastGroup), [](auto&& content) {
const auto control{ content.GetTermControl() };
return control && !control.ReadOnly() && !control.BracketedPasteEnabled();
});
// GetClipboardData might block for up to 30s for delay-rendered contents.
co_await winrt::resume_background();
@@ -2967,8 +2980,11 @@ namespace winrt::TerminalApp::implementation
text = clipboard::read();
}
if (!bracketedPaste && globalSettings.TrimPaste())
if (!anyHasBracketedPaste && globalSettings.TrimPaste())
{
// Warning - when broadcast is enabled, this will trim the paste for all receivers.
// Until we propagate this decision-making elsewhere, this is safer; broadcast will not auto-submit commands in other panes.
// Tracked in GH#20164
text = winrt::hstring{ Utils::TrimPaste(text) };
}
@@ -2976,7 +2992,7 @@ namespace winrt::TerminalApp::implementation
// Bracketed Paste provides an application a way to know whether the
// user pasted, even if there was no applicable content on it. This
// behavior is observed in GNOME Terminal, among others.
if (!bracketedPaste && text.empty())
if (!anyHasBracketedPaste && text.empty())
{
co_return;
}
@@ -2988,7 +3004,7 @@ namespace winrt::TerminalApp::implementation
// 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;
warnMultiLine = anyHasUnbracketedPaste;
break;
case WarnAboutMultiLinePaste::Always:
warnMultiLine = true;
@@ -3058,30 +3074,7 @@ namespace winrt::TerminalApp::implementation
// This will end up calling ConptyConnection::WriteInput which calls WriteFile which may block for
// an indefinite amount of time. Avoid freezes and deadlocks by running this on a background thread.
assert(!dispatcher.HasThreadAccess());
eventArgs.HandleClipboardData(text);
// GH#18821: If broadcast input is active, paste the same text into all other
// panes on the tab. We do this here (rather than re-reading the
// clipboard per-pane) so that only one paste warning is shown.
co_await wil::resume_foreground(dispatcher);
if (const auto strongThis = weakThis.get())
{
if (const auto& tab{ strongThis->_GetFocusedTabImpl() })
{
if (tab->TabStatus().IsInputBroadcastActive())
{
tab->GetRootPane()->WalkTree([&](auto&& pane) {
if (const auto control = pane->GetTerminalControl())
{
if (control.ContentId() != sourceId && !control.ReadOnly())
{
control.RawWriteString(text);
}
}
});
}
}
}
_writeInputStringToBroadcastGroup(broadcastGroup, text, WriteInputStringType::Clipboard);
}
CATCH_LOG();
@@ -3436,16 +3429,6 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Paste text from the Windows Clipboard to the focused terminal
void TerminalPage::_PasteText()
{
if (const auto& control{ _GetActiveControl() })
{
control.PasteTextFromClipboard();
}
}
// Function Description:
// - Called when the settings button is clicked. ShellExecutes the settings
// file, as to open it in the default editor for .json files. Does this in
@@ -5827,4 +5810,326 @@ namespace winrt::TerminalApp::implementation
return profileMenuItemFlyout;
}
static void _translatePathInPlace(std::wstring& fullPath, PathTranslationStyle translationStyle)
{
static constexpr wil::zwstring_view s_pathPrefixes[] = {
{},
/* WSL */ L"/mnt/",
/* Cygwin */ L"/cygdrive/",
/* MSYS2 */ L"/",
/* MinGW */ {},
};
static constexpr wil::zwstring_view sSingleQuoteEscape = L"'\\''";
static constexpr auto cchSingleQuoteEscape = sSingleQuoteEscape.size();
if (translationStyle == PathTranslationStyle::None)
{
return;
}
// All of the other path translation modes current result in /-delimited paths
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
// Escape single quotes, assuming translated paths are always quoted by a pair of single quotes.
size_t pos = 0;
while ((pos = fullPath.find(L'\'', pos)) != std::wstring::npos)
{
// ' -> '\'' (for POSIX shell)
fullPath.replace(pos, 1, sSingleQuoteEscape);
// Arithmetic overflow cannot occur here.
pos += cchSingleQuoteEscape;
}
if (translationStyle == PathTranslationStyle::MinGW)
{
return;
}
if (fullPath.size() >= 2 && fullPath.at(1) == L':')
{
// C:/foo/bar -> Cc/foo/bar
fullPath.at(1) = til::tolower_ascii(fullPath.at(0));
// Cc/foo/bar -> [PREFIX]c/foo/bar
fullPath.replace(0, 1, s_pathPrefixes[static_cast<int>(translationStyle)]);
}
else if (translationStyle == PathTranslationStyle::WSL)
{
// Stripping the UNC name and distribution prefix only applies to WSL.
static constexpr std::wstring_view wslPathPrefixes[] = { L"//wsl.localhost/", L"//wsl$/" };
for (auto prefix : wslPathPrefixes)
{
if (til::starts_with(fullPath, prefix))
{
if (const auto idx = fullPath.find(L'/', prefix.size()); idx != std::wstring::npos)
{
// //wsl.localhost/Ubuntu-18.04/foo/bar -> /foo/bar
fullPath.erase(0, idx);
}
else
{
// //wsl.localhost/Ubuntu-18.04 -> /
fullPath = L"/";
}
break;
}
}
}
}
// Method Description:
// - Handle the DragOver event. We'll signal that the drag operation we
// support is the "copy" operation, and we'll also customize the
// appearance of the drag-drop UI, by removing the preview and setting a
// custom caption. For more information, see
// https://docs.microsoft.com/en-us/windows/uwp/design/input/drag-and-drop#customize-the-ui
// Arguments:
// - e: The DragEventArgs from the DragOver event
// Return Value:
// - <none>
void TerminalPage::_ControlDragOverHandler(const Windows::Foundation::IInspectable& /*sender*/,
const DragEventArgs& e)
{
// We can only handle drag/dropping StorageItems (files) and plain Text
// currently. If the format on the clipboard is anything else, returning
// early here will prevent the drag/drop from doing anything.
if (!(e.DataView().Contains(StandardDataFormats::StorageItems()) ||
e.DataView().Contains(StandardDataFormats::Text())))
{
return;
}
// Make sure to set the AcceptedOperation, so that we can later receive the path in the Drop event
e.AcceptedOperation(DataPackageOperation::Copy);
// Sets custom UI text
if (e.DataView().Contains(StandardDataFormats::StorageItems()))
{
e.DragUIOverride().Caption(RS_(L"DragFileCaption"));
}
else if (e.DataView().Contains(StandardDataFormats::Text()))
{
e.DragUIOverride().Caption(RS_(L"DragTextCaption"));
}
// Sets if the caption is visible
e.DragUIOverride().IsCaptionVisible(true);
// Sets if the dragged content is visible
e.DragUIOverride().IsContentVisible(false);
// Sets if the glyph is visible
e.DragUIOverride().IsGlyphVisible(false);
}
// Method Description:
// - Async handler for the "Drop" event. If a file was dropped onto our
// root, we'll try to get the path of the file dropped onto us, and write
// the full path of the file to our terminal connection. Like conhost, if
// the path contains a space, we'll wrap the path in quotes.
// - Unlike conhost, if multiple files are dropped onto the terminal, we'll
// write all the paths to the terminal, separated by spaces.
// Arguments:
// - e: The DragEventArgs from the Drop event
// Return Value:
// - <none>
safe_void_coroutine TerminalPage::_ControlDragDropHandler(Windows::Foundation::IInspectable sender,
DragEventArgs e)
{
auto dispatcher = Dispatcher();
auto weak = get_weak();
const auto control = sender.as<TermControl>();
const auto broadcastGroup = _getBroadcastGroupFromControl(control);
if (_hostingHwnd)
{
SetForegroundWindow(*_hostingHwnd);
}
if (e.DataView().Contains(StandardDataFormats::ApplicationLink()))
{
try
{
auto link{ co_await e.DataView().GetApplicationLinkAsync() };
if (const auto strong = weak.get())
{
_writeInputStringToBroadcastGroup(broadcastGroup, link.AbsoluteUri(), WriteInputStringType::Clipboard);
}
}
CATCH_LOG();
}
else if (e.DataView().Contains(StandardDataFormats::WebLink()))
{
try
{
auto link{ co_await e.DataView().GetWebLinkAsync() };
if (const auto strong = weak.get())
{
_writeInputStringToBroadcastGroup(broadcastGroup, link.AbsoluteUri(), WriteInputStringType::Clipboard);
}
}
CATCH_LOG();
}
else if (e.DataView().Contains(StandardDataFormats::Text()))
{
try
{
auto text{ co_await e.DataView().GetTextAsync() };
if (const auto strong = weak.get())
{
_writeInputStringToBroadcastGroup(broadcastGroup, text, WriteInputStringType::Clipboard);
}
}
CATCH_LOG();
}
// StorageItem must be last. Some applications put hybrid data format items
// in a drop message and we'll eat a crash when we request them.
// Those applications usually include Text as well, so having storage items
// last makes sure we'll hit text before getting to them.
else if (e.DataView().Contains(StandardDataFormats::StorageItems()))
{
Windows::Foundation::Collections::IVectorView<Windows::Storage::IStorageItem> items;
try
{
items = co_await e.DataView().GetStorageItemsAsync();
}
CATCH_LOG();
if (items && items.Size() > 0)
{
std::vector<std::wstring> fullPaths;
// GH#14628: Workaround for GetStorageItemsAsync() only returning 16 items
// at most when dragging and dropping from archives (zip, 7z, rar, etc.)
if (items.Size() == 16 && e.DataView().Contains(winrt::hstring{ L"FileDrop" }))
{
auto fileDropData = co_await e.DataView().GetDataAsync(winrt::hstring{ L"FileDrop" });
if (fileDropData != nullptr)
{
auto stream = fileDropData.as<IRandomAccessStream>();
stream.Seek(0);
const uint32_t streamSize = gsl::narrow_cast<uint32_t>(stream.Size());
const Buffer buf(streamSize);
const auto buffer = co_await stream.ReadAsync(buf, streamSize, InputStreamOptions::None);
const HGLOBAL hGlobal = buffer.data();
const auto count = DragQueryFileW(static_cast<HDROP>(hGlobal), 0xFFFFFFFF, nullptr, 0);
fullPaths.reserve(count);
for (unsigned int i = 0; i < count; i++)
{
std::wstring path;
path.resize(wil::max_path_length);
const auto charsCopied = DragQueryFileW(static_cast<HDROP>(hGlobal), i, path.data(), wil::max_path_length);
if (charsCopied > 0)
{
path.resize(charsCopied);
fullPaths.emplace_back(std::move(path));
}
}
}
}
else
{
fullPaths.reserve(items.Size());
for (const auto& item : items)
{
fullPaths.emplace_back(item.Path());
}
}
const auto strong = weak.get();
if (!strong)
{
co_return;
}
// TODO(DH) the fuckin' delimiter from DragDropDelimiter
std::unordered_map<PathTranslationStyle, winrt::hstring> translatedPaths;
for (auto&& target : broadcastGroup)
{
const auto profile{ target.GetProfile() };
auto translationStyle{ profile.PathTranslationStyle() };
const auto broadcastTargetControl{ target.GetTermControl() };
if (broadcastTargetControl.ReadOnly())
{
continue;
}
auto [it, isNew] = translatedPaths.try_emplace(translationStyle, winrt::hstring{});
if (isNew)
{
std::wstring allPathsString;
for (auto fullPath : fullPaths)
{
// Join the paths with spaces
if (!allPathsString.empty())
{
allPathsString += L" ";
}
_translatePathInPlace(fullPath, translationStyle);
// All translated paths get quotes, and all strings spaces get quotes; all translated paths get single quotes
const auto quotesNeeded = translationStyle != PathTranslationStyle::None || fullPath.find(L' ') != std::wstring::npos;
const auto quotesChar = translationStyle != PathTranslationStyle::None ? L'\'' : L'"';
// Append fullPath and also wrap it in quotes if needed
if (quotesNeeded)
{
allPathsString.push_back(quotesChar);
}
allPathsString.append(fullPath);
if (quotesNeeded)
{
allPathsString.push_back(quotesChar);
}
}
it->second = winrt::hstring{ allPathsString };
}
broadcastTargetControl.WriteInputString(it->second, WriteInputStringType::Clipboard);
}
}
}
}
TerminalPage::broadcast_group TerminalPage::_getBroadcastGroupFromControl(const TermControl& control)
{
TerminalPage::broadcast_group contents;
auto controlContent{ TerminalPaneContent::ContentFromControl(control) };
if (controlContent)
{
contents.emplace_back(controlContent);
}
if (const auto& tab{ _GetFocusedTabImpl() })
{
if (tab->TabStatus().IsInputBroadcastActive())
{
tab->GetRootPane()->WalkTree([&](auto&& pane) {
if (auto content = pane->GetContent(); content && content != controlContent)
{
if (const auto termContent{ content.try_as<TerminalPaneContent>() })
{
contents.emplace_back(*termContent);
}
}
});
}
}
return contents;
}
void TerminalPage::_writeInputStringToBroadcastGroup(const TerminalPage::broadcast_group& broadcastGroup, const winrt::hstring text, WriteInputStringType type)
{
for (auto&& content : broadcastGroup)
{
auto nextControl{ content.GetTermControl() };
if (!nextControl.ReadOnly())
{
nextControl.WriteInputString(text, type);
}
}
}
}

View File

@@ -420,7 +420,7 @@ namespace winrt::TerminalApp::implementation
void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::Control::KeyChord& keyChord);
safe_void_coroutine _PasteFromClipboardHandler(const IInspectable sender,
const Microsoft::Terminal::Control::PasteFromClipboardEventArgs eventArgs);
const IInspectable eventArgs);
safe_void_coroutine _OpenHyperlinkHandler(const IInspectable sender, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs);
static bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
@@ -437,6 +437,9 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine _ControlNoticeRaisedHandler(const IInspectable sender, const Microsoft::Terminal::Control::NoticeEventArgs eventArgs);
void _ShowControlNoticeDialog(const winrt::hstring& title, const winrt::hstring& message);
safe_void_coroutine _ControlDragDropHandler(Windows::Foundation::IInspectable sender, Windows::UI::Xaml::DragEventArgs e);
void _ControlDragOverHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::DragEventArgs& e);
safe_void_coroutine _LaunchSettings(const Microsoft::Terminal::Settings::Model::SettingsTarget target);
void _TabDragStarted(const IInspectable& sender, const IInspectable& eventArgs);
@@ -571,6 +574,10 @@ namespace winrt::TerminalApp::implementation
void _activePaneChanged(winrt::TerminalApp::Tab tab, Windows::Foundation::IInspectable args);
safe_void_coroutine _doHandleSuggestions(Microsoft::Terminal::Settings::Model::SuggestionsArgs realArgs);
using broadcast_group = til::small_vector<TerminalApp::TerminalPaneContent, 1>;
broadcast_group _getBroadcastGroupFromControl(const Microsoft::Terminal::Control::TermControl& control);
void _writeInputStringToBroadcastGroup(const broadcast_group& broadcastGroup, const winrt::hstring text, Microsoft::Terminal::Control::WriteInputStringType type);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View File

@@ -20,6 +20,8 @@ using namespace winrt::Microsoft::Terminal::TerminalConnection;
namespace winrt::TerminalApp::implementation
{
til::shared_mutex<std::unordered_map<void*, winrt::weak_ref<TerminalApp::implementation::TerminalPaneContent>>> TerminalPaneContent::_controlToContentMap{};
TerminalPaneContent::TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const std::shared_ptr<TerminalSettingsCache>& cache,
const winrt::Microsoft::Terminal::Control::TermControl& control) :
@@ -28,6 +30,9 @@ namespace winrt::TerminalApp::implementation
_profile{ profile }
{
_setupControlEvents();
auto map{ _controlToContentMap.lock() };
map->insert_or_assign(winrt::get_abi(control), get_weak());
}
void TerminalPaneContent::_setupControlEvents()
@@ -72,6 +77,11 @@ namespace winrt::TerminalApp::implementation
_control.Close();
{
auto map{ _controlToContentMap.lock() };
map->erase(winrt::get_abi(_control));
}
// Clear out our media player callbacks, and stop any playing media. This
// will prevent the callback from being triggered after we've closed, and
// also make sure that our sound stops when we're closed.
@@ -371,4 +381,14 @@ namespace winrt::TerminalApp::implementation
{
return _control.CharacterDimensions();
}
TerminalApp::TerminalPaneContent TerminalPaneContent::ContentFromControl(const winrt::Microsoft::Terminal::Control::TermControl& control)
{
const auto map{ _controlToContentMap.lock_shared() };
if (auto found{ map->find(winrt::get_abi(control)) }; found != map->end())
{
return *found->second.get();
}
return { nullptr };
}
}

View File

@@ -55,9 +55,13 @@ namespace winrt::TerminalApp::implementation
til::typed_event<TerminalApp::TerminalPaneContent, winrt::Windows::Foundation::IInspectable> RestartTerminalRequested;
static TerminalApp::TerminalPaneContent ContentFromControl(const winrt::Microsoft::Terminal::Control::TermControl& control);
// See BasicPaneEvents for most generic event definitions
private:
static til::shared_mutex<std::unordered_map<void*, winrt::weak_ref<TerminalApp::implementation::TerminalPaneContent>>> _controlToContentMap;
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };

View File

@@ -34,6 +34,7 @@
#include <winrt/Windows.Globalization.h>
#include <winrt/Windows.Graphics.Display.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.Text.h>
@@ -88,6 +89,7 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include <til/mutex.h>
#include <til/winrt.h>
#include <SafeDispatcherTimer.h>

View File

@@ -498,7 +498,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - wstr: the string of characters to write to the terminal connection.
// Return Value:
// - <none>
void ControlCore::SendInput(const std::wstring_view wstr)
void ControlCore::_sendInput(const std::wstring_view wstr)
{
if (wstr.empty())
{
@@ -554,7 +554,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
if (out)
{
SendInput(*out);
_sendInput(*out);
return true;
}
return false;
@@ -712,7 +712,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
if (out)
{
SendInput(*out);
_sendInput(*out);
return true;
}
return false;
@@ -731,7 +731,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
if (out)
{
SendInput(*out);
_sendInput(*out);
return true;
}
return false;
@@ -1451,24 +1451,34 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Method Description:
// - Pre-process text pasted (presumably from the clipboard)
// before sending it over the terminal's connection.
void ControlCore::PasteText(const winrt::hstring& hstr)
void ControlCore::WriteInputString(const std::wstring_view& str, WriteInputStringType type)
{
using namespace ::Microsoft::Console::Utils;
auto filtered = FilterStringForPaste(hstr, CarriageReturnNewline | ControlCodes);
if (BracketedPasteEnabled())
switch (type)
{
filtered.insert(0, L"\x1b[200~");
filtered.append(L"\x1b[201~");
case WriteInputStringType::Clipboard:
{
using namespace ::Microsoft::Console::Utils;
auto filtered = FilterStringForPaste(str, CarriageReturnNewline | ControlCodes);
if (BracketedPasteEnabled())
{
filtered.insert(0, L"\x1b[200~");
filtered.append(L"\x1b[201~");
}
// It's important to not hold the terminal lock while calling this function as sending the data may take a long time.
_sendInput(filtered);
const auto lock = _terminal->LockForWriting();
_terminal->ClearSelection();
_updateSelectionUI();
_terminal->TrySnapOnInput();
return;
}
case WriteInputStringType::Raw:
_sendInput(str);
return;
}
// It's important to not hold the terminal lock while calling this function as sending the data may take a long time.
SendInput(filtered);
const auto lock = _terminal->LockForWriting();
_terminal->ClearSelection();
_updateSelectionUI();
_terminal->TrySnapOnInput();
}
FontInfo ControlCore::GetFont() const
@@ -2197,7 +2207,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Sending input requires that we're unlocked, because
// writing the input pipe may block indefinitely.
const auto suspension = _terminal->SuspendLock();
SendInput(buffer);
_sendInput(buffer);
}
}
}

View File

@@ -122,8 +122,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::color ForegroundColor() const;
til::color BackgroundColor() const;
void SendInput(std::wstring_view wstr);
void PasteText(const winrt::hstring& hstr);
void WriteInputString(const std::wstring_view& str, WriteInputStringType type);
bool CopySelectionToClipboard(bool singleLine, bool withControlSequences, const CopyFormat formats);
void SelectAll();
void ClearSelection();
@@ -320,6 +319,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _handleControlC();
void _sendInputToConnection(std::wstring_view wstr);
void _sendInput(std::wstring_view wstr);
#pragma region TerminalCoreCallbacks
void _terminalWarningBell();

View File

@@ -68,6 +68,14 @@ namespace Microsoft.Terminal.Control
Boolean SearchRegexInvalid;
};
enum WriteInputStringType
{
// Text which is to be passed through unmodified.
Raw,
// Text which is to be treated as clipboard input, stripped and formatted according to the application's wishes.
Clipboard,
};
[default_interface] runtimeclass SelectionColor
{
SelectionColor();
@@ -128,8 +136,7 @@ namespace Microsoft.Terminal.Control
Boolean SendCharEvent(Char ch,
Int16 scanCode,
Microsoft.Terminal.Core.ControlKeyStates modifiers);
void SendInput(String text);
void PasteText(String text);
void WriteInputString(String text, WriteInputStringType type);
void SelectAll();
void ClearSelection();
Boolean ToggleBlockSelection();

View File

@@ -242,14 +242,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - Initiate a paste operation.
void ControlInteractivity::RequestPasteTextFromClipboard()
{
auto args = winrt::make<PasteFromClipboardEventArgs>(
[core = _core](const winrt::hstring& wstr) {
core->PasteText(wstr);
},
_core->BracketedPasteEnabled());
// send paste event up to TermApp
PasteFromClipboard.raise(*this, std::move(args));
PasteFromClipboard.raise(*this, nullptr);
}
void ControlInteractivity::PointerPressed(const uint32_t /*pointerId*/,

View File

@@ -92,7 +92,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void AttachToNewControl();
til::typed_event<IInspectable, Control::OpenHyperlinkEventArgs> OpenHyperlink;
til::typed_event<IInspectable, Control::PasteFromClipboardEventArgs> PasteFromClipboard;
til::typed_event<IInspectable, IInspectable> PasteFromClipboard;
til::typed_event<IInspectable, Control::ScrollPositionChangedArgs> ScrollPositionChanged;
til::typed_event<IInspectable, Control::ContextMenuRequestedEventArgs> ContextMenuRequested;

View File

@@ -68,7 +68,7 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
event Windows.Foundation.TypedEventHandler<Object, Object> PasteFromClipboard;
event Windows.Foundation.TypedEventHandler<Object, Object> Closed;

View File

@@ -7,7 +7,6 @@
#include "TitleChangedEventArgs.g.cpp"
#include "ContextMenuRequestedEventArgs.g.cpp"
#include "WriteToClipboardEventArgs.g.cpp"
#include "PasteFromClipboardEventArgs.g.cpp"
#include "OpenHyperlinkEventArgs.g.cpp"
#include "NoticeEventArgs.g.cpp"
#include "ScrollPositionChangedArgs.g.cpp"
@@ -18,6 +17,5 @@
#include "CompletionsChangedEventArgs.g.cpp"
#include "KeySentEventArgs.g.cpp"
#include "CharSentEventArgs.g.cpp"
#include "StringSentEventArgs.g.cpp"
#include "SearchMissingCommandEventArgs.g.cpp"
#include "WindowSizeChangedEventArgs.g.cpp"

View File

@@ -7,7 +7,6 @@
#include "TitleChangedEventArgs.g.h"
#include "ContextMenuRequestedEventArgs.g.h"
#include "WriteToClipboardEventArgs.g.h"
#include "PasteFromClipboardEventArgs.g.h"
#include "OpenHyperlinkEventArgs.g.h"
#include "NoticeEventArgs.g.h"
#include "ScrollPositionChangedArgs.g.h"
@@ -18,7 +17,6 @@
#include "CompletionsChangedEventArgs.g.h"
#include "KeySentEventArgs.g.h"
#include "CharSentEventArgs.g.h"
#include "StringSentEventArgs.g.h"
#include "SearchMissingCommandEventArgs.g.h"
#include "WindowSizeChangedEventArgs.g.h"
@@ -83,24 +81,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::string _rtf;
};
struct PasteFromClipboardEventArgs : public PasteFromClipboardEventArgsT<PasteFromClipboardEventArgs>
{
public:
PasteFromClipboardEventArgs(std::function<void(const hstring&)> clipboardDataHandler, bool bracketedPasteEnabled) :
m_clipboardDataHandler(clipboardDataHandler),
_BracketedPasteEnabled{ bracketedPasteEnabled } {}
void HandleClipboardData(hstring value)
{
m_clipboardDataHandler(value);
};
WINRT_PROPERTY(bool, BracketedPasteEnabled, false);
private:
std::function<void(const hstring&)> m_clipboardDataHandler;
};
struct OpenHyperlinkEventArgs : public OpenHyperlinkEventArgsT<OpenHyperlinkEventArgs>
{
public:
@@ -232,15 +212,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WINRT_PROPERTY(winrt::Microsoft::Terminal::Core::ControlKeyStates, Modifiers);
};
struct StringSentEventArgs : public StringSentEventArgsT<StringSentEventArgs>
{
public:
StringSentEventArgs(const winrt::hstring& text) :
_Text(text) {}
WINRT_PROPERTY(winrt::hstring, Text);
};
struct SearchMissingCommandEventArgs : public SearchMissingCommandEventArgsT<SearchMissingCommandEventArgs>
{
public:

View File

@@ -68,12 +68,6 @@ namespace Microsoft.Terminal.Control
byte[] Rtf { get; }; // UTF-8, as required by "Rich Text Format"
}
runtimeclass PasteFromClipboardEventArgs
{
void HandleClipboardData(String data);
Boolean BracketedPasteEnabled { get; };
}
runtimeclass OpenHyperlinkEventArgs
{
OpenHyperlinkEventArgs(String uri);
@@ -149,11 +143,6 @@ namespace Microsoft.Terminal.Control
Microsoft.Terminal.Core.ControlKeyStates Modifiers { get; };
}
runtimeclass StringSentEventArgs
{
String Text { get; };
}
runtimeclass SearchMissingCommandEventArgs
{
String MissingCommand { get; };

View File

@@ -137,14 +137,6 @@
<value>Find</value>
<comment>The placeholder text in the search box control.</comment>
</data>
<data name="DragFileCaption" xml:space="preserve">
<value>Paste path to file</value>
<comment>The displayed caption for dragging a file onto a terminal.</comment>
</data>
<data name="DragTextCaption" xml:space="preserve">
<value>Paste text</value>
<comment>The displayed caption for dragging text onto a terminal.</comment>
</data>
<data name="SearchBox_CaseSensitivity.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Case Sensitivity</value>
<comment>The name of the case sensitivity button on the search box control for accessibility.</comment>

View File

@@ -23,8 +23,6 @@ using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::ViewManagement;
using namespace winrt::Windows::UI::Input;
using namespace winrt::Windows::System;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Storage::Streams;
// The minimum delay between updates to the scroll bar's values.
// The updates are throttled to limit power usage.
@@ -89,72 +87,6 @@ static Microsoft::Console::TSF::Handle& GetTSFHandle()
namespace winrt::Microsoft::Terminal::Control::implementation
{
static void _translatePathInPlace(std::wstring& fullPath, PathTranslationStyle translationStyle)
{
static constexpr wil::zwstring_view s_pathPrefixes[] = {
{},
/* WSL */ L"/mnt/",
/* Cygwin */ L"/cygdrive/",
/* MSYS2 */ L"/",
/* MinGW */ {},
};
static constexpr wil::zwstring_view sSingleQuoteEscape = L"'\\''";
static constexpr auto cchSingleQuoteEscape = sSingleQuoteEscape.size();
if (translationStyle == PathTranslationStyle::None)
{
return;
}
// All of the other path translation modes current result in /-delimited paths
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
// Escape single quotes, assuming translated paths are always quoted by a pair of single quotes.
size_t pos = 0;
while ((pos = fullPath.find(L'\'', pos)) != std::wstring::npos)
{
// ' -> '\'' (for POSIX shell)
fullPath.replace(pos, 1, sSingleQuoteEscape);
// Arithmetic overflow cannot occur here.
pos += cchSingleQuoteEscape;
}
if (translationStyle == PathTranslationStyle::MinGW)
{
return;
}
if (fullPath.size() >= 2 && fullPath.at(1) == L':')
{
// C:/foo/bar -> Cc/foo/bar
fullPath.at(1) = til::tolower_ascii(fullPath.at(0));
// Cc/foo/bar -> [PREFIX]c/foo/bar
fullPath.replace(0, 1, s_pathPrefixes[static_cast<int>(translationStyle)]);
}
else if (translationStyle == PathTranslationStyle::WSL)
{
// Stripping the UNC name and distribution prefix only applies to WSL.
static constexpr std::wstring_view wslPathPrefixes[] = { L"//wsl.localhost/", L"//wsl$/" };
for (auto prefix : wslPathPrefixes)
{
if (til::starts_with(fullPath, prefix))
{
if (const auto idx = fullPath.find(L'/', prefix.size()); idx != std::wstring::npos)
{
// //wsl.localhost/Ubuntu-18.04/foo/bar -> /foo/bar
fullPath.erase(0, idx);
}
else
{
// //wsl.localhost/Ubuntu-18.04 -> /
fullPath = L"/";
}
break;
}
}
}
}
TsfDataProvider::TsfDataProvider(TermControl* termControl) noexcept :
_termControl{ termControl }
{
@@ -238,7 +170,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return;
}
core->SendInput(text);
core->WriteInputString(text, WriteInputStringType::Raw);
}
::Microsoft::Console::Render::Renderer* TsfDataProvider::GetRenderer()
@@ -912,19 +844,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - wstr: the string of characters to write to the terminal connection.
// Return Value:
// - <none>
void TermControl::SendInput(const winrt::hstring& wstr)
void TermControl::WriteInputString(const winrt::hstring& wstr, WriteInputStringType type)
{
// Dismiss any previewed input.
PreviewInput(hstring{});
// only broadcast if there's an actual listener. Saves the overhead of some object creation.
if (StringSent)
{
StringSent.raise(*this, winrt::make<StringSentEventArgs>(wstr));
}
RawWriteString(wstr);
_core.WriteInputString(wstr, type);
}
void TermControl::ClearBuffer(Control::ClearBufferType clearType)
{
_core.ClearBuffer(clearType);
@@ -1524,11 +1450,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.SendCharEvent(character, scanCode, modifiers);
}
void TermControl::RawWriteString(const winrt::hstring& text)
{
_core.SendInput(text);
}
// Method Description:
// - Manually handles key events for certain keys that can't be passed to us
// normally. Namely, the keys we're concerned with are F7 down and Alt up.
@@ -1675,7 +1596,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// If it encounters a string that isn't, cppwinrt will abort().
// It should already be null-terminated, but let's make sure to not crash.
buf[buf_len] = L'\0';
_core.SendInput(std::wstring_view{ &buf[0], buf_len });
_core.WriteInputString(std::wstring_view{ &buf[0], buf_len }, WriteInputStringType::Raw);
}
s = {};
@@ -3069,230 +2990,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return std::pow(cursorDistanceFromBorder, 2.0) / 25.0 + 2.0;
}
// Method Description:
// - Async handler for the "Drop" event. If a file was dropped onto our
// root, we'll try to get the path of the file dropped onto us, and write
// the full path of the file to our terminal connection. Like conhost, if
// the path contains a space, we'll wrap the path in quotes.
// - Unlike conhost, if multiple files are dropped onto the terminal, we'll
// write all the paths to the terminal, separated by the configured delimiter.
// Arguments:
// - e: The DragEventArgs from the Drop event
// Return Value:
// - <none>
safe_void_coroutine TermControl::_DragDropHandler(Windows::Foundation::IInspectable /*sender*/,
DragEventArgs e)
{
if (_IsClosing())
{
co_return;
}
if (const auto hwnd = reinterpret_cast<HWND>(OwningHwnd()))
{
SetForegroundWindow(hwnd);
}
const auto weak = get_weak();
if (e.DataView().Contains(StandardDataFormats::ApplicationLink()))
{
try
{
auto link{ co_await e.DataView().GetApplicationLinkAsync() };
if (const auto strong = weak.get())
{
_pasteTextWithBroadcast(link.AbsoluteUri());
}
}
CATCH_LOG();
}
else if (e.DataView().Contains(StandardDataFormats::WebLink()))
{
try
{
auto link{ co_await e.DataView().GetWebLinkAsync() };
if (const auto strong = weak.get())
{
_pasteTextWithBroadcast(link.AbsoluteUri());
}
}
CATCH_LOG();
}
else if (e.DataView().Contains(StandardDataFormats::Text()))
{
try
{
auto text{ co_await e.DataView().GetTextAsync() };
if (const auto strong = weak.get())
{
_pasteTextWithBroadcast(text);
}
}
CATCH_LOG();
}
// StorageItem must be last. Some applications put hybrid data format items
// in a drop message and we'll eat a crash when we request them.
// Those applications usually include Text as well, so having storage items
// last makes sure we'll hit text before getting to them.
else if (e.DataView().Contains(StandardDataFormats::StorageItems()))
{
Windows::Foundation::Collections::IVectorView<Windows::Storage::IStorageItem> items;
try
{
items = co_await e.DataView().GetStorageItemsAsync();
}
CATCH_LOG();
if (items && items.Size() > 0)
{
std::vector<std::wstring> fullPaths;
// GH#14628: Workaround for GetStorageItemsAsync() only returning 16 items
// at most when dragging and dropping from archives (zip, 7z, rar, etc.)
if (items.Size() == 16 && e.DataView().Contains(winrt::hstring{ L"FileDrop" }))
{
auto fileDropData = co_await e.DataView().GetDataAsync(winrt::hstring{ L"FileDrop" });
if (fileDropData != nullptr)
{
auto stream = fileDropData.as<IRandomAccessStream>();
stream.Seek(0);
const uint32_t streamSize = gsl::narrow_cast<uint32_t>(stream.Size());
const Buffer buf(streamSize);
const auto buffer = co_await stream.ReadAsync(buf, streamSize, InputStreamOptions::None);
const HGLOBAL hGlobal = buffer.data();
const auto count = DragQueryFileW(static_cast<HDROP>(hGlobal), 0xFFFFFFFF, nullptr, 0);
fullPaths.reserve(count);
for (unsigned int i = 0; i < count; i++)
{
std::wstring path;
path.resize(wil::max_path_length);
const auto charsCopied = DragQueryFileW(static_cast<HDROP>(hGlobal), i, path.data(), wil::max_path_length);
if (charsCopied > 0)
{
path.resize(charsCopied);
fullPaths.emplace_back(std::move(path));
}
}
}
}
else
{
fullPaths.reserve(items.Size());
for (const auto& item : items)
{
fullPaths.emplace_back(item.Path());
}
}
const auto strong = weak.get();
if (!strong)
{
co_return;
}
std::wstring allPathsString;
const auto delimiter{ _core.Settings().DragDropDelimiter() };
for (auto& fullPath : fullPaths)
{
// Join the paths with the delimiter
if (!allPathsString.empty())
{
allPathsString += delimiter;
}
const auto translationStyle{ _core.Settings().PathTranslationStyle() };
_translatePathInPlace(fullPath, translationStyle);
// All translated paths get quotes, and all strings spaces get quotes; all translated paths get single quotes
const auto quotesNeeded = translationStyle != PathTranslationStyle::None || fullPath.find(L' ') != std::wstring::npos;
const auto quotesChar = translationStyle != PathTranslationStyle::None ? L'\'' : L'"';
// Append fullPath and also wrap it in quotes if needed
if (quotesNeeded)
{
allPathsString.push_back(quotesChar);
}
allPathsString.append(fullPath);
if (quotesNeeded)
{
allPathsString.push_back(quotesChar);
}
}
_pasteTextWithBroadcast(winrt::hstring{ allPathsString });
}
}
}
// Method Description:
// - Paste this text, and raise a StringSent, to potentially broadcast this
// text to other controls in the app. For certain interactions, like
// drag/dropping a file, we want to act like we "pasted" the text (even if
// the text didn't come from the clipboard). This lets those interactions
// broadcast as well.
void TermControl::_pasteTextWithBroadcast(const winrt::hstring& text)
{
// only broadcast if there's an actual listener. Saves the overhead of some object creation.
if (StringSent)
{
StringSent.raise(*this, winrt::make<StringSentEventArgs>(text));
}
_core.PasteText(text);
}
// Method Description:
// - Handle the DragOver event. We'll signal that the drag operation we
// support is the "copy" operation, and we'll also customize the
// appearance of the drag-drop UI, by removing the preview and setting a
// custom caption. For more information, see
// https://docs.microsoft.com/en-us/windows/uwp/design/input/drag-and-drop#customize-the-ui
// Arguments:
// - e: The DragEventArgs from the DragOver event
// Return Value:
// - <none>
void TermControl::_DragOverHandler(const Windows::Foundation::IInspectable& /*sender*/,
const DragEventArgs& e)
{
if (_IsClosing())
{
return;
}
// We can only handle drag/dropping StorageItems (files) and plain Text
// currently. If the format on the clipboard is anything else, returning
// early here will prevent the drag/drop from doing anything.
if (!(e.DataView().Contains(StandardDataFormats::StorageItems()) ||
e.DataView().Contains(StandardDataFormats::Text())))
{
return;
}
// Make sure to set the AcceptedOperation, so that we can later receive the path in the Drop event
e.AcceptedOperation(DataPackageOperation::Copy);
// Sets custom UI text
if (e.DataView().Contains(StandardDataFormats::StorageItems()))
{
e.DragUIOverride().Caption(RS_(L"DragFileCaption"));
}
else if (e.DataView().Contains(StandardDataFormats::Text()))
{
e.DragUIOverride().Caption(RS_(L"DragTextCaption"));
}
// Sets if the caption is visible
e.DragUIOverride().IsCaptionVisible(true);
// Sets if the dragged content is visible
e.DragUIOverride().IsContentVisible(false);
// Sets if the glyph is visible
e.DragUIOverride().IsGlyphVisible(false);
}
// Method description:
// - Checks if the uri is valid and sends an event if so
// Arguments:

View File

@@ -125,7 +125,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ResetFontSize();
winrt::Windows::Foundation::Size GetFontSize() const;
void SendInput(const winrt::hstring& input);
void WriteInputString(const winrt::hstring& wstr, WriteInputStringType type);
void ClearBuffer(Control::ClearBufferType clearType);
void ToggleShaderEffects();
@@ -179,7 +179,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool RawWriteKeyEvent(const WORD vkey, const WORD scanCode, const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool keyDown);
bool RawWriteChar(const wchar_t character, const WORD scanCode, const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers);
void RawWriteString(const winrt::hstring& text);
void ShowContextMenu();
bool OpenQuickFixMenu();
@@ -213,7 +212,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<> WarningBell;
til::typed_event<IInspectable, Control::KeySentEventArgs> KeySent;
til::typed_event<IInspectable, Control::CharSentEventArgs> CharSent;
til::typed_event<IInspectable, Control::StringSentEventArgs> StringSent;
til::typed_event<IInspectable, Control::SearchMissingCommandEventArgs> SearchMissingCommand;
til::typed_event<IInspectable, Control::WindowSizeChangedEventArgs> WindowSizeChanged;
@@ -229,7 +227,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
BUBBLED_FORWARDED_TYPED_EVENT(CompletionsChanged, IInspectable, Control::CompletionsChangedEventArgs);
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, IInspectable);
// clang-format on
@@ -378,9 +376,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _GotFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
void _LostFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
safe_void_coroutine _DragDropHandler(Windows::Foundation::IInspectable sender, Windows::UI::Xaml::DragEventArgs e);
void _DragOverHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::DragEventArgs& e);
safe_void_coroutine _HyperlinkHandler(Windows::Foundation::IInspectable sender, Control::OpenHyperlinkEventArgs e);
void _BellLightOff(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
@@ -429,8 +424,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::Point _toPosInDips(const Core::Point terminalCellPos);
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
void _pasteTextWithBroadcast(const winrt::hstring& text);
void _contextMenuHandler(IInspectable sender, Control::ContextMenuRequestedEventArgs args);
void _showContextMenuAt(const winrt::Windows::Foundation::Point& controlRelativePos);

View File

@@ -64,7 +64,7 @@ namespace Microsoft.Terminal.Control
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, Object> PasteFromClipboard;
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
@@ -80,7 +80,6 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, KeySentEventArgs> KeySent;
event Windows.Foundation.TypedEventHandler<Object, CharSentEventArgs> CharSent;
event Windows.Foundation.TypedEventHandler<Object, StringSentEventArgs> StringSent;
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
@@ -127,10 +126,9 @@ namespace Microsoft.Terminal.Control
void ResetFontSize();
void ToggleShaderEffects();
void SendInput(String input);
Boolean RawWriteKeyEvent(UInt16 vkey, UInt16 scanCode, Microsoft.Terminal.Core.ControlKeyStates modifiers, Boolean keyDown);
Boolean RawWriteChar(Char character, UInt16 scanCode, Microsoft.Terminal.Core.ControlKeyStates modifiers);
void RawWriteString(String text);
void WriteInputString(String text, WriteInputStringType type);
void BellLightOn();

View File

@@ -20,8 +20,6 @@
AllowFocusOnInteraction="True"
Background="Transparent"
CharacterReceived="_CharacterHandler"
DragOver="_DragOverHandler"
Drop="_DragDropHandler"
GotFocus="_GotFocusHandler"
IsTabStop="True"
KeyUp="_KeyUpHandler"

View File

@@ -48,7 +48,6 @@
#include <winrt/Windows.ui.xaml.markup.h>
#include <winrt/Windows.ui.xaml.shapes.h>
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.UI.Xaml.Shapes.h>

View File

@@ -153,9 +153,9 @@ public:
// _core.TitleChanged({ get_weak(), &TermControl::_bubbleTitleChanged });
#define BUBBLED_FORWARDED_TYPED_EVENT(name, sender, args) \
TYPED_EVENT(name, sender, args) \
void _bubble##name(const sender& s, const args& a) \
void _bubble##name(const sender&, const args& a) \
{ \
_##name##Handlers(s, a); \
_##name##Handlers(*this, a); \
}
// Use this macro to quick implement both the getter and setter for a property.