diff --git a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw index 6f69bda90c2..afcdaee51e5 100644 --- a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw @@ -1,17 +1,17 @@ - @@ -137,4 +137,7 @@ Find... The placeholder text in the search dialog TextBox - \ No newline at end of file + + Copy path to file + + diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index b0760a100fe..291e024c060 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "..\..\types\inc\GlyphWidth.hpp" #include "TermControl.g.cpp" @@ -21,6 +22,7 @@ using namespace winrt::Windows::UI::Xaml::Automation::Peers; using namespace winrt::Windows::UI::Core; using namespace winrt::Windows::System; using namespace winrt::Microsoft::Terminal::Settings; +using namespace winrt::Windows::ApplicationModel::DataTransfer; namespace winrt::Microsoft::Terminal::TerminalControl::implementation { @@ -162,6 +164,10 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation _connectionStateChangedRevoker = _connection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) { _ConnectionStateChangedHandlers(*this, nullptr); }); + + _root.AllowDrop(true); + _root.Drop({ get_weak(), &TermControl::_DragDropHandler }); + _root.DragOver({ get_weak(), &TermControl::_DragOverHandler }); } // Method Description: @@ -1390,6 +1396,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } } + // Method Description: + // - Writes the given sequence as input to the active terminal connection, + // Arguments: + // - wstr: the string of characters to write to the terminal connection. + // Return Value: + // - void TermControl::_SendInputToConnection(const std::wstring& wstr) { _connection.WriteInput(wstr); @@ -2150,6 +2162,95 @@ namespace winrt::Microsoft::Terminal::TerminalControl::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 spaces. + // Arguments: + // - e: The DragEventArgs from the Drop event + // Return Value: + // - + winrt::fire_and_forget TermControl::_DoDragDrop(DragEventArgs const e) + { + if (e.DataView().Contains(StandardDataFormats::StorageItems())) + { + auto items = co_await e.DataView().GetStorageItemsAsync(); + if (items.Size() > 0) + { + std::wstring allPaths; + for (auto item : items) + { + // Join the paths with spaces + if (!allPaths.empty()) + { + allPaths += L" "; + } + + std::wstring fullPath{ item.Path() }; + const auto containsSpaces = std::find(fullPath.begin(), + fullPath.end(), + L' ') != fullPath.end(); + + auto lock = _terminal->LockForWriting(); + + if (containsSpaces) + { + fullPath.insert(0, L"\""); + fullPath += L"\""; + } + + allPaths += fullPath; + } + _SendInputToConnection(allPaths); + } + } + } + + // Method Description: + // - Synchronous handler for the "Drop" event. We'll dispatch the async + // _DoDragDrop method to handle this, because getting information about + // the file that was potentially dropped onto us must be done off the UI + // thread. + // Arguments: + // - e: The DragEventArgs from the Drop event + // Return Value: + // - + void TermControl::_DragDropHandler(Windows::Foundation::IInspectable const& /*sender*/, + DragEventArgs const& e) + { + // Dispatch an async method to handle the drop event. + _DoDragDrop(e); + } + + // 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: + // - + void TermControl::_DragOverHandler(Windows::Foundation::IInspectable const& /*sender*/, + DragEventArgs const& e) + { + // Make sure to set the AcceptedOperation, so that we can later recieve the path in the Drop event + e.AcceptedOperation(winrt::Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy); + + // Sets custom UI text + e.DragUIOverride().Caption(RS_(L"DragFileCaption")); + // 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 visibile + e.DragUIOverride().IsGlyphVisible(false); + } + // -------------------------------- WinRT Events --------------------------------- // Winrt events need a method for adding a callback to the event and removing the callback. // These macros will define them both for you. diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index a8d2ec65cb9..3bcd654c831 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -187,6 +187,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void _ScrollbarChangeHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e); void _GotFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e); void _LostFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e); + void _DragDropHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::DragEventArgs const& e); + void _DragOverHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::DragEventArgs const& e); + winrt::fire_and_forget _DoDragDrop(Windows::UI::Xaml::DragEventArgs const e); void _BlinkCursor(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e); void _SetEndSelectionPointAtCursor(Windows::Foundation::Point const& cursorPosition); diff --git a/src/cascadia/TerminalControl/pch.h b/src/cascadia/TerminalControl/pch.h index af78f0de89f..da5fe2052fe 100644 --- a/src/cascadia/TerminalControl/pch.h +++ b/src/cascadia/TerminalControl/pch.h @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include