mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-11 00:31:11 +00:00
Compare commits
30 Commits
dev/lhecke
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70d905b658 | ||
|
|
9a6ded2e39 | ||
|
|
eac27dbe25 | ||
|
|
d3a98b3754 | ||
|
|
d234049640 | ||
|
|
4ab628d62f | ||
|
|
8309901fc9 | ||
|
|
015c5e8b93 | ||
|
|
1726176c85 | ||
|
|
3b02c96bd5 | ||
|
|
dc448b4781 | ||
|
|
75ea5f3aab | ||
|
|
6ac5137ba8 | ||
|
|
7b524b0d31 | ||
|
|
654416cdc1 | ||
|
|
cae6f04cfb | ||
|
|
9208222884 | ||
|
|
8b67ed7779 | ||
|
|
c4f623aaf0 | ||
|
|
3d83cc348a | ||
|
|
8e170eb643 | ||
|
|
0f339d2498 | ||
|
|
054f173995 | ||
|
|
1fd87fecdf | ||
|
|
e9b2e5184a | ||
|
|
f0f75dcdd0 | ||
|
|
006da6a549 | ||
|
|
67d854821f | ||
|
|
65bc163da4 | ||
|
|
ce375fa7f3 |
1
.github/actions/spelling/allow/allow.txt
vendored
1
.github/actions/spelling/allow/allow.txt
vendored
@@ -117,6 +117,7 @@ uiatextrange
|
||||
UIs
|
||||
und
|
||||
unregister
|
||||
urxvt
|
||||
versioned
|
||||
vsdevcmd
|
||||
walkthrough
|
||||
|
||||
@@ -461,4 +461,35 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
co_await winrt::resume_background();
|
||||
_monarch.RequestSendContent(args);
|
||||
}
|
||||
|
||||
// Attempt to summon an existing window. This static function does NOT
|
||||
// pre-register as the monarch. This is used for activations from a
|
||||
// notification, where this process should NEVER become its own window.
|
||||
bool WindowManager::SummonForNotification(const uint64_t windowId)
|
||||
{
|
||||
auto monarch = create_instance<Remoting::IMonarch>(Monarch_clsid,
|
||||
CLSCTX_LOCAL_SERVER);
|
||||
|
||||
if (monarch == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
SummonWindowSelectionArgs args{};
|
||||
args.WindowID(windowId);
|
||||
|
||||
// Summon the window...
|
||||
// * On its current desktop
|
||||
// * Without a dropdown
|
||||
// * On the monitor it is already on
|
||||
// * Do not toggle, just make visible.
|
||||
const Remoting::SummonWindowBehavior summonArgs{};
|
||||
summonArgs.MoveToCurrentDesktop(false);
|
||||
summonArgs.DropdownDuration(0);
|
||||
summonArgs.ToMonitor(Remoting::MonitorBehavior::InPlace);
|
||||
summonArgs.ToggleVisibility(false);
|
||||
|
||||
args.SummonBehavior(summonArgs);
|
||||
monarch.SummonWindow(args);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds);
|
||||
winrt::fire_and_forget RequestSendContent(Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
static bool SummonForNotification(const uint64_t windowId);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
|
||||
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Microsoft.Terminal.Remoting
|
||||
void RequestMoveContent(String window, String content, UInt32 tabIndex, Windows.Foundation.IReference<Windows.Foundation.Rect> bounds);
|
||||
void RequestSendContent(RequestReceiveContentArgs args);
|
||||
|
||||
static Boolean SummonForNotification(UInt64 windowId);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <inc/WindowingBehavior.h>
|
||||
#include <LibraryResources.h>
|
||||
#include <WtExeUtils.h>
|
||||
#include <TerminalCore/ControlKeyStates.hpp>
|
||||
#include <til/latch.h>
|
||||
|
||||
@@ -45,6 +46,9 @@ using namespace ::Microsoft::Console;
|
||||
using namespace ::Microsoft::Terminal::Core;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using namespace winrt::Windows::UI::Notifications;
|
||||
using namespace winrt::Windows::Data::Xml::Dom;
|
||||
|
||||
#define HOOKUP_ACTION(action) _actionDispatch->action({ this, &TerminalPage::_Handle##action });
|
||||
|
||||
namespace winrt
|
||||
@@ -1671,6 +1675,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
term.CompletionsChanged({ get_weak(), &TerminalPage::_ControlCompletionsChangedHandler });
|
||||
}
|
||||
|
||||
winrt::weak_ref<TermControl> weakTerm{ term };
|
||||
term.ContextMenu().Opening([weak = get_weak(), weakTerm](auto&& sender, auto&& /*args*/) {
|
||||
if (const auto& page{ weak.get() })
|
||||
@@ -1684,6 +1689,7 @@ namespace winrt::TerminalApp::implementation
|
||||
page->_PopulateContextMenu(weakTerm.get(), sender.try_as<MUX::Controls::CommandBarFlyout>(), true);
|
||||
}
|
||||
});
|
||||
term.SendNotification({ get_weak(), &TerminalPage::_SendNotificationHandler });
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -2958,6 +2964,110 @@ namespace winrt::TerminalApp::implementation
|
||||
_ShowWindowChangedHandlers(*this, args);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handler for a control's SendNotification event. `args` will contain the
|
||||
// title and body of the notification requested by the client application.
|
||||
// - This will only actually send a notification when the sender is
|
||||
// - in an inactive window OR
|
||||
// - in an inactive tab.
|
||||
winrt::fire_and_forget TerminalPage::_SendNotificationHandler(const IInspectable sender,
|
||||
const Microsoft::Terminal::Control::SendNotificationArgs args)
|
||||
{
|
||||
// This never works as expected when we're an elevated instance. The
|
||||
// notification will end up launching an unelevated instance to handle
|
||||
// it, and there's no good way to get back to the elevated one.
|
||||
// Possibly revisit after GH #13276.
|
||||
//
|
||||
// We're using CanDragDrop, because TODO! I bet this works with UAC disabled
|
||||
if (!CanDragDrop())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto weakThis = get_weak();
|
||||
|
||||
co_await resume_foreground(Dispatcher());
|
||||
auto page{ weakThis.get() };
|
||||
if (page)
|
||||
{
|
||||
// If the window is inactive, we always want to send the notification.
|
||||
//
|
||||
// Otherwise, we only want to send the notification for panes in inactive tabs.
|
||||
if (_activated)
|
||||
{
|
||||
auto foundControl = false;
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
activeTab->GetRootPane()->WalkTree([&](auto&& pane) {
|
||||
if (const auto& term{ pane->GetTerminalControl() })
|
||||
{
|
||||
if (term == sender)
|
||||
{
|
||||
foundControl = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// The control that sent this is in the active tab. We
|
||||
// should only send the notification if the window was
|
||||
// inactive.
|
||||
if (foundControl)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
}
|
||||
|
||||
_sendNotification(args.Title(), args.Body());
|
||||
}
|
||||
}
|
||||
|
||||
// Actually write the payload to a XML doc and load it into a ToastNotification.
|
||||
void TerminalPage::_sendNotification(const std::wstring_view title,
|
||||
const std::wstring_view body)
|
||||
{
|
||||
// ToastNotificationManager::CreateToastNotifier doesn't work in
|
||||
// unpackaged scenarios without an AUMID. We probably don't have one if
|
||||
// we're unpackaged. Unpackaged isn't a wholly supported scenario
|
||||
// anyways, so let's just bail.
|
||||
|
||||
if (!IsPackaged())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static winrt::hstring xmlTemplate{ L"\
|
||||
<toast>\
|
||||
<visual>\
|
||||
<binding template=\"ToastGeneric\">\
|
||||
<text></text>\
|
||||
<text></text>\
|
||||
</binding>\
|
||||
</visual>\
|
||||
</toast>" };
|
||||
|
||||
XmlDocument doc;
|
||||
doc.LoadXml(xmlTemplate);
|
||||
// Populate with text and values
|
||||
auto payload{ fmt::format(L"window={}&tabIndex=0", WindowProperties().WindowId()) };
|
||||
doc.DocumentElement().SetAttribute(L"launch", payload);
|
||||
doc.SelectSingleNode(L"//text[1]").InnerText(title);
|
||||
doc.SelectSingleNode(L"//text[2]").InnerText(body);
|
||||
|
||||
// Construct the notification
|
||||
ToastNotification notification{ doc };
|
||||
|
||||
// lazy-init
|
||||
if (!_toastNotifier)
|
||||
{
|
||||
_toastNotifier = ToastNotificationManager::CreateToastNotifier();
|
||||
}
|
||||
|
||||
// And show it!
|
||||
_toastNotifier.Show(notification);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Paste text from the Windows Clipboard to the focused terminal
|
||||
void TerminalPage::_PasteText()
|
||||
|
||||
@@ -287,6 +287,9 @@ namespace winrt::TerminalApp::implementation
|
||||
__declspec(noinline) SuggestionsControl _loadSuggestionsElementSlowPath();
|
||||
bool _suggestionsControlIs(winrt::Windows::UI::Xaml::Visibility visibility);
|
||||
|
||||
// todo! maybe move to TerminalWindow
|
||||
winrt::Windows::UI::Notifications::ToastNotifier _toastNotifier{ nullptr };
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
|
||||
|
||||
void _ShowAboutDialog();
|
||||
@@ -543,6 +546,9 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Control::TermControl _senderOrActiveControl(const winrt::Windows::Foundation::IInspectable& sender);
|
||||
winrt::com_ptr<TerminalTab> _senderOrFocusedTab(const IInspectable& sender);
|
||||
|
||||
winrt::fire_and_forget _SendNotificationHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::SendNotificationArgs args);
|
||||
|
||||
void _sendNotification(const std::wstring_view title, const std::wstring_view body);
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
|
||||
#include <winrt/Windows.ApplicationModel.Activation.h>
|
||||
#include <winrt/Windows.Data.Xml.Dom.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.Metadata.h>
|
||||
@@ -35,6 +37,7 @@
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
#include <winrt/Windows.UI.Input.h>
|
||||
#include <winrt/Windows.UI.Notifications.h>
|
||||
#include <winrt/Windows.UI.Text.h>
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
#include <winrt/Windows.UI.Xaml.Automation.Peers.h>
|
||||
|
||||
@@ -126,6 +126,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto pfnCompletionsChanged = [=](auto&& menuJson, auto&& replaceLength) { _terminalCompletionsChanged(menuJson, replaceLength); };
|
||||
_terminal->CompletionsChangedCallback(pfnCompletionsChanged);
|
||||
|
||||
auto pfnSendNotification = std::bind(&ControlCore::_terminalSendNotification, this, std::placeholders::_1, std::placeholders::_2);
|
||||
_terminal->SetSendNotificationCallback(pfnSendNotification);
|
||||
|
||||
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
|
||||
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
|
||||
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
|
||||
@@ -1585,6 +1588,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_midiAudio.PlayNote(reinterpret_cast<HWND>(_owningHwnd), noteNumber, velocity, std::chrono::duration_cast<std::chrono::milliseconds>(duration));
|
||||
}
|
||||
|
||||
void ControlCore::_terminalSendNotification(const std::wstring_view title,
|
||||
const std::wstring_view body)
|
||||
{
|
||||
const auto e = winrt::make_self<implementation::SendNotificationArgs>(title, body);
|
||||
_SendNotificationHandlers(*this, *e);
|
||||
}
|
||||
|
||||
bool ControlCore::HasSelection() const
|
||||
{
|
||||
const auto lock = _terminal->LockForReading();
|
||||
|
||||
@@ -280,6 +280,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(SendNotification, IInspectable, Control::SendNotificationArgs);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
@@ -372,6 +374,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::fire_and_forget _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
|
||||
|
||||
void _terminalSendNotification(const std::wstring_view title,
|
||||
const std::wstring_view body);
|
||||
#pragma endregion
|
||||
|
||||
MidiAudio _midiAudio;
|
||||
|
||||
@@ -190,5 +190,7 @@ namespace Microsoft.Terminal.Control
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, CompletionsChangedEventArgs> CompletionsChanged;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, SendNotificationArgs> SendNotification;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,3 +20,4 @@
|
||||
#include "KeySentEventArgs.g.cpp"
|
||||
#include "CharSentEventArgs.g.cpp"
|
||||
#include "StringSentEventArgs.g.cpp"
|
||||
#include "SendNotificationArgs.g.cpp"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "KeySentEventArgs.g.h"
|
||||
#include "CharSentEventArgs.g.h"
|
||||
#include "StringSentEventArgs.g.h"
|
||||
#include "SendNotificationArgs.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
@@ -251,6 +252,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, Text);
|
||||
};
|
||||
|
||||
struct SendNotificationArgs : public SendNotificationArgsT<SendNotificationArgs>
|
||||
{
|
||||
public:
|
||||
SendNotificationArgs(const std::wstring_view title,
|
||||
const std::wstring_view body) :
|
||||
_Title(title),
|
||||
_Body(body)
|
||||
{
|
||||
}
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, Title);
|
||||
WINRT_PROPERTY(winrt::hstring, Body);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
|
||||
@@ -121,4 +121,10 @@ namespace Microsoft.Terminal.Control
|
||||
{
|
||||
String Text { get; };
|
||||
}
|
||||
|
||||
runtimeclass SendNotificationArgs
|
||||
{
|
||||
String Title { get; };
|
||||
String Body { get; };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_revokers.PasteFromClipboard = _interactivity.PasteFromClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubblePasteFromClipboard });
|
||||
|
||||
// Re-raise the event with us as the sender.
|
||||
_core.SendNotification([weakThis = get_weak()](auto s, auto e) {
|
||||
if (auto self{ weakThis.get() })
|
||||
{
|
||||
self->_SendNotificationHandlers(*self, e);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the terminal only once the swapchainpanel is loaded - that
|
||||
// way, we'll be able to query the real pixel size it got on layout
|
||||
_layoutUpdatedRevoker = SwapChainPanel().LayoutUpdated(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
|
||||
@@ -194,6 +194,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(KeySent, IInspectable, Control::KeySentEventArgs);
|
||||
TYPED_EVENT(CharSent, IInspectable, Control::CharSentEventArgs);
|
||||
TYPED_EVENT(StringSent, IInspectable, Control::StringSentEventArgs);
|
||||
TYPED_EVENT(SendNotification, IInspectable, Control::SendNotificationArgs);
|
||||
// clang-format on
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, BackgroundBrush, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ReadOnlyChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FocusFollowMouseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SendNotificationArgs> SendNotification;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, CompletionsChangedEventArgs> CompletionsChanged;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Microsoft.Terminal.Core
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> StartingTabColor;
|
||||
|
||||
Boolean AutoMarkPrompts;
|
||||
Boolean AllowNotifications;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||
_startingTitle = settings.StartingTitle();
|
||||
_trimBlockSelection = settings.TrimBlockSelection();
|
||||
_autoMarkPrompts = settings.AutoMarkPrompts();
|
||||
_allowNotifications = settings.AllowNotifications();
|
||||
|
||||
_getTerminalInput().ForceDisableWin32InputMode(settings.ForceVTInput());
|
||||
|
||||
@@ -1160,6 +1161,11 @@ void Terminal::SetPlayMidiNoteCallback(std::function<void(const int, const int,
|
||||
_pfnPlayMidiNote.swap(pfn);
|
||||
}
|
||||
|
||||
void Terminal::SetSendNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept
|
||||
{
|
||||
_pfnSendNotification.swap(pfn);
|
||||
}
|
||||
|
||||
void Terminal::BlinkCursor() noexcept
|
||||
{
|
||||
if (_selectionMode != SelectionInteractionMode::Mark)
|
||||
|
||||
@@ -163,6 +163,7 @@ public:
|
||||
|
||||
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
|
||||
|
||||
void SendNotification(const std::wstring_view title, const std::wstring_view body) override;
|
||||
#pragma endregion
|
||||
|
||||
void ClearMark();
|
||||
@@ -237,6 +238,7 @@ public:
|
||||
void SetShowWindowCallback(std::function<void(bool)> pfn) noexcept;
|
||||
void SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept;
|
||||
void CompletionsChangedCallback(std::function<void(std::wstring_view, unsigned int)> pfn) noexcept;
|
||||
void SetSendNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept;
|
||||
|
||||
void BlinkCursor() noexcept;
|
||||
void SetCursorOn(const bool isOn) noexcept;
|
||||
@@ -345,6 +347,7 @@ private:
|
||||
std::function<void(bool)> _pfnShowWindowChanged;
|
||||
std::function<void(const int, const int, const std::chrono::microseconds)> _pfnPlayMidiNote;
|
||||
std::function<void(std::wstring_view, unsigned int)> _pfnCompletionsChanged;
|
||||
std::function<void(std::wstring_view, std::wstring_view)> _pfnSendNotification;
|
||||
|
||||
RenderSettings _renderSettings;
|
||||
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
|
||||
@@ -363,6 +366,7 @@ private:
|
||||
bool _suppressApplicationTitle = false;
|
||||
bool _trimBlockSelection = false;
|
||||
bool _autoMarkPrompts = false;
|
||||
bool _allowNotifications = true;
|
||||
|
||||
size_t _taskbarState = 0;
|
||||
size_t _taskbarProgress = 0;
|
||||
|
||||
@@ -511,3 +511,13 @@ void Terminal::NotifyBufferRotation(const int delta)
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::SendNotification(const std::wstring_view title,
|
||||
const std::wstring_view body)
|
||||
{
|
||||
// Only send notifications if enabled in the settings
|
||||
if (_pfnSendNotification && _allowNotifications)
|
||||
{
|
||||
_pfnSendNotification(title, body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,8 @@ Author(s):
|
||||
X(bool, AutoMarkPrompts, "experimental.autoMarkPrompts", false) \
|
||||
X(bool, ShowMarks, "experimental.showMarksOnScrollbar", false) \
|
||||
X(bool, RepositionCursorWithMouse, "experimental.repositionCursorWithMouse", false) \
|
||||
X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true)
|
||||
X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true) \
|
||||
X(bool, AllowNotifications, "allowNotifications", true)
|
||||
|
||||
// Intentionally omitted Profile settings:
|
||||
// * Name
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, RightClickContextMenu);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, RepositionCursorWithMouse);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowNotifications);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, ReloadEnvironmentVariables);
|
||||
|
||||
|
||||
@@ -339,6 +339,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
_RightClickContextMenu = profile.RightClickContextMenu();
|
||||
|
||||
_RepositionCursorWithMouse = profile.RepositionCursorWithMouse();
|
||||
_AllowNotifications = profile.AllowNotifications();
|
||||
|
||||
_ReloadEnvironmentVariables = profile.ReloadEnvironmentVariables();
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, ShowMarks, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, RightClickContextMenu, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, RepositionCursorWithMouse, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, AllowNotifications, true);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, ReloadEnvironmentVariables, true);
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace ::Microsoft::Console::Types;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
using namespace winrt::Windows::UI::Notifications;
|
||||
|
||||
// This magic flag is "documented" at https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx
|
||||
// "If the high-order bit is 1, the key is down; otherwise, it is up."
|
||||
|
||||
@@ -71,6 +71,8 @@ private:
|
||||
void _HandleCommandlineArgs(const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
|
||||
void _HandleSessionRestore(const bool startedForContent);
|
||||
|
||||
// bool _HandleLaunchArgs();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::LaunchPosition _GetWindowLaunchPosition();
|
||||
|
||||
void _HandleCreateWindow(const HWND hwnd, const til::rect& proposedRect);
|
||||
|
||||
@@ -14,6 +14,8 @@ using namespace winrt;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
using namespace winrt::Windows::UI::Notifications;
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace std::chrono_literals;
|
||||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
@@ -58,8 +60,89 @@ void _buildArgsFromCommandline(std::vector<winrt::hstring>& args)
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to handle activated event args, which are a kind of "modern"
|
||||
// activation, which we use for supporting toast notifications.
|
||||
// - If we do find we were activated from a toast notification, we'll unpack the
|
||||
// arguments from the toast. Then, we'll try to open up a connection to the
|
||||
// monarch and ask the monarch to activate the right window.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool WindowEmperor::_handleLaunchArgs()
|
||||
try
|
||||
{
|
||||
// AppInstance::GetActivatedEventArgs will throw when unpackaged.
|
||||
if (!IsPackaged())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// If someone clicks on a notification, then a fresh instance of
|
||||
// windowsterminal.exe will spawn. We certainly don't want to create a new
|
||||
// window for that - we only want to activate the window that created the
|
||||
// actual notification. In the toast arg's payload will be the window id
|
||||
// that sent the notification. We'll ask the window manager to try and
|
||||
// activate that window ID, without even bothering to register as the
|
||||
// monarch ourselves (if we can't find a monarch, then there are no windows
|
||||
// running, so whoever sent it must have died.)
|
||||
|
||||
const auto activatedArgs = AppInstance::GetActivatedEventArgs();
|
||||
if (activatedArgs != nullptr &&
|
||||
activatedArgs.Kind() == Activation::ActivationKind::ToastNotification)
|
||||
{
|
||||
if (const auto& toastArgs{ activatedArgs.try_as<Activation::ToastNotificationActivatedEventArgs>() })
|
||||
{
|
||||
// Obtain the arguments from the notification
|
||||
const auto args = toastArgs.Argument();
|
||||
|
||||
// Args is gonna look like
|
||||
//
|
||||
// "window=id&foo=bar&..."
|
||||
//
|
||||
// We need to first split on &, then split those pairs on =
|
||||
|
||||
// tabIndex code here is left as reference for parsing multiple
|
||||
// arguments, despite it not being used currently.
|
||||
uint32_t window;
|
||||
// uint32_t tabIndex = 0;
|
||||
|
||||
const std::wstring_view argsView{ args };
|
||||
const auto pairs = Utils::SplitString(argsView, L'&');
|
||||
for (const auto& pair : pairs)
|
||||
{
|
||||
const auto pairParts = Utils::SplitString(pair, L'=');
|
||||
if (pairParts.size() == 2)
|
||||
{
|
||||
if (til::at(pairParts, 0) == L"window")
|
||||
{
|
||||
window = std::wcstoul(pairParts[1].data(), nullptr, 10);
|
||||
}
|
||||
// else if (pairParts[0] == L"tabIndex")
|
||||
// {
|
||||
// // convert a wide string to a uint
|
||||
// tabIndex = std::wcstoul(pairParts[1].data(), nullptr, 10);
|
||||
// }
|
||||
}
|
||||
}
|
||||
return winrt::Microsoft::Terminal::Remoting::WindowManager::SummonForNotification(window);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
CATCH_LOG_RETURN_HR(false)
|
||||
|
||||
void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
{
|
||||
// Before handling any commandline arguments, check if this was a toast
|
||||
// invocation. If it was, we can go ahead and totally ignore everything
|
||||
// else.
|
||||
if (_handleLaunchArgs())
|
||||
{
|
||||
TerminateProcess(GetCurrentProcess(), 0u);
|
||||
}
|
||||
|
||||
std::vector<winrt::hstring> args;
|
||||
_buildArgsFromCommandline(args);
|
||||
const auto cwd{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
void HandleCommandlineArgs(int nCmdShow);
|
||||
|
||||
private:
|
||||
bool _handleLaunchArgs();
|
||||
void _createNewWindowThread(const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
|
||||
|
||||
[[nodiscard]] static LRESULT __stdcall _wndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept;
|
||||
|
||||
@@ -59,7 +59,14 @@ Abstract:
|
||||
// * Media for ScaleTransform
|
||||
// * ApplicationModel for finding the path to wt.exe
|
||||
// * Primitives for Popup (used by GetOpenPopupsForXamlRoot)
|
||||
// * XML, Notifications, Activation: for notification activations
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
|
||||
#include <winrt/Windows.ApplicationModel.Activation.h>
|
||||
#include <winrt/Windows.Data.Xml.Dom.h>
|
||||
#include <winrt/Windows.UI.Composition.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
#include <winrt/Windows.UI.Notifications.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.UI.Xaml.Data.h>
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
X(bool, DetectURLs, true) \
|
||||
X(bool, VtPassthrough, false) \
|
||||
X(bool, AutoMarkPrompts) \
|
||||
X(bool, RepositionCursorWithMouse, false)
|
||||
X(bool, RepositionCursorWithMouse, false) \
|
||||
X(bool, AllowNotifications, true)
|
||||
|
||||
// --------------------------- Control Settings ---------------------------
|
||||
// All of these settings are defined in IControlSettings.
|
||||
|
||||
@@ -187,4 +187,15 @@
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_Notifications</name>
|
||||
<description>Enables OSC777 notifications</description>
|
||||
<id>16654</id>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
<brandingToken>Canary</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
</featureStaging>
|
||||
|
||||
@@ -76,6 +76,8 @@ public:
|
||||
|
||||
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
|
||||
|
||||
void SendNotification(const std::wstring_view /*title*/, const std::wstring_view /*body*/) noexcept override{};
|
||||
|
||||
private:
|
||||
Microsoft::Console::IIoProvider& _io;
|
||||
};
|
||||
|
||||
@@ -137,6 +137,7 @@ public:
|
||||
virtual bool DoITerm2Action(const std::wstring_view string) = 0;
|
||||
|
||||
virtual bool DoFinalTermAction(const std::wstring_view string) = 0;
|
||||
virtual bool DoUrxvtAction(const std::wstring_view string) = 0;
|
||||
|
||||
virtual bool DoVsCodeAction(const std::wstring_view string) = 0;
|
||||
|
||||
|
||||
@@ -87,5 +87,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
virtual void MarkCommandFinish(std::optional<unsigned int> error) = 0;
|
||||
|
||||
virtual void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) = 0;
|
||||
|
||||
virtual void SendNotification(const std::wstring_view title, const std::wstring_view body) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3863,6 +3863,41 @@ bool AdaptDispatch::DoVsCodeAction(const std::wstring_view string)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdaptDispatch::DoUrxvtAction(const std::wstring_view string)
|
||||
{
|
||||
// This is not implemented in conhost.
|
||||
if (_api.IsConsolePty())
|
||||
{
|
||||
// Flush the frame manually, to make sure marks end up on the right line, like the alt buffer sequence.
|
||||
_renderer.TriggerFlush(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (!Feature_Notifications::IsEnabled())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto parts = Utils::SplitString(string, L';');
|
||||
|
||||
if (parts.size() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto action = til::at(parts, 0);
|
||||
|
||||
if (action == L"notify")
|
||||
{
|
||||
const std::wstring_view title = parts.size() > 1 ? til::at(parts, 1) : L"";
|
||||
const std::wstring_view body = parts.size() > 2 ? til::at(parts, 2) : L"";
|
||||
_api.SendNotification(title, body);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - DECDLD - Downloads one or more characters of a dynamically redefinable
|
||||
// character set (DRCS) with a specified pixel pattern. The pixel array is
|
||||
|
||||
@@ -139,6 +139,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
bool DoITerm2Action(const std::wstring_view string) override;
|
||||
|
||||
bool DoFinalTermAction(const std::wstring_view string) override;
|
||||
bool DoUrxvtAction(const std::wstring_view string) override;
|
||||
|
||||
bool DoVsCodeAction(const std::wstring_view string) override;
|
||||
|
||||
|
||||
@@ -133,6 +133,8 @@ public:
|
||||
|
||||
bool DoVsCodeAction(const std::wstring_view /*string*/) override { return false; }
|
||||
|
||||
bool DoUrxvtAction(const std::wstring_view /*string*/) override { return false; }
|
||||
|
||||
StringHandler DownloadDRCS(const VTInt /*fontNumber*/,
|
||||
const VTParameter /*startChar*/,
|
||||
const DispatchTypes::DrcsEraseControl /*eraseControl*/,
|
||||
|
||||
@@ -238,6 +238,11 @@ public:
|
||||
VERIFY_ARE_EQUAL(_expectedReplaceLength, replaceLength);
|
||||
}
|
||||
|
||||
void SendNotification(const std::wstring_view /*title*/, const std::wstring_view /*body*/) override
|
||||
{
|
||||
Log::Comment(L"SendNotification MOCK called...");
|
||||
}
|
||||
|
||||
void PrepData()
|
||||
{
|
||||
PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter.
|
||||
|
||||
@@ -883,6 +883,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
|
||||
success = _dispatch->DoVsCodeAction(string);
|
||||
break;
|
||||
}
|
||||
case OscActionCodes::UrxvtAction:
|
||||
{
|
||||
success = _dispatch->DoUrxvtAction(string);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// If no functions to call, overall dispatch was a failure.
|
||||
success = false;
|
||||
|
||||
@@ -218,6 +218,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
ResetCursorColor = 112,
|
||||
FinalTermAction = 133,
|
||||
VsCodeAction = 633,
|
||||
UrxvtAction = 777,
|
||||
ITerm2Action = 1337,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user