mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-18 01:39:55 +00:00
Compare commits
5 Commits
dev/cazamo
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
821cd97610 | ||
|
|
16099f42bf | ||
|
|
4aff331374 | ||
|
|
c268521309 | ||
|
|
7d02839be2 |
@@ -10,6 +10,7 @@ namespace winrt::TerminalApp::implementation
|
||||
til::typed_event<> ConnectionStateChanged;
|
||||
til::typed_event<IPaneContent> CloseRequested;
|
||||
til::typed_event<IPaneContent, winrt::TerminalApp::BellEventArgs> BellRequested;
|
||||
til::typed_event<IPaneContent, winrt::TerminalApp::NotificationEventArgs> NotificationRequested;
|
||||
til::typed_event<IPaneContent> TitleChanged;
|
||||
til::typed_event<IPaneContent> TabColorChanged;
|
||||
til::typed_event<IPaneContent> TaskbarProgressChanged;
|
||||
|
||||
104
src/cascadia/TerminalApp/DesktopNotification.cpp
Normal file
104
src/cascadia/TerminalApp/DesktopNotification.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "DesktopNotification.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Notifications;
|
||||
using namespace winrt::Windows::Data::Xml::Dom;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
std::atomic<int64_t> DesktopNotification::_lastNotificationTime{ 0 };
|
||||
|
||||
bool DesktopNotification::ShouldSendNotification()
|
||||
{
|
||||
FILETIME ft{};
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
const auto now = (static_cast<int64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
auto last = _lastNotificationTime.load(std::memory_order_relaxed);
|
||||
|
||||
if (now - last < MinNotificationIntervalTicks)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to update; if another thread beat us, that's fine — we'll skip this one.
|
||||
_lastNotificationTime.compare_exchange_strong(last, now, std::memory_order_relaxed);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DesktopNotification::SendNotification(
|
||||
const DesktopNotificationArgs& args,
|
||||
std::function<void(uint32_t tabIndex)> activated)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ShouldSendNotification())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the toast XML. We use a simple template with a title and body text.
|
||||
//
|
||||
// <toast launch="__fromToast">
|
||||
// <visual>
|
||||
// <binding template="ToastGeneric">
|
||||
// <text>Title</text>
|
||||
// <text>Message</text>
|
||||
// </binding>
|
||||
// </visual>
|
||||
// </toast>
|
||||
auto toastXml = ToastNotificationManager::GetTemplateContent(ToastTemplateType::ToastText02);
|
||||
auto textNodes = toastXml.GetElementsByTagName(L"text");
|
||||
|
||||
// First <text> is the title
|
||||
textNodes.Item(0).InnerText(args.Title);
|
||||
// Second <text> is the body
|
||||
textNodes.Item(1).InnerText(args.Message);
|
||||
|
||||
auto toastElement = toastXml.DocumentElement();
|
||||
|
||||
// When a toast is clicked, Windows launches a new instance of the app
|
||||
// with the "launch" attribute as command-line arguments. We handle
|
||||
// toast activation in-process via the Activated event below, so the
|
||||
// new instance should do nothing. "__fromToast" is recognized by
|
||||
// AppCommandlineArgs::ParseArgs as a no-op sentinel.
|
||||
toastElement.SetAttribute(L"launch", L"__fromToast");
|
||||
|
||||
// Set the scenario to "reminder" to ensure the toast shows even in DND,
|
||||
// and the group/tag to allow replacement of repeated notifications.
|
||||
toastElement.SetAttribute(L"scenario", L"default");
|
||||
|
||||
auto toast = ToastNotification{ toastXml };
|
||||
|
||||
// Set the tag and group to enable notification replacement.
|
||||
// Using the tab index as a tag means repeated output from the same tab
|
||||
// replaces the previous notification rather than stacking.
|
||||
toast.Tag(fmt::format(FMT_COMPILE(L"wt-tab-{}"), args.TabIndex));
|
||||
toast.Group(L"WindowsTerminal");
|
||||
|
||||
// When the user activates (clicks) the toast, fire the callback.
|
||||
if (activated)
|
||||
{
|
||||
const auto tabIndex = args.TabIndex;
|
||||
toast.Activated([activated, tabIndex](const auto& /*sender*/, const auto& /*eventArgs*/) {
|
||||
activated(tabIndex);
|
||||
});
|
||||
}
|
||||
|
||||
// For packaged apps, CreateToastNotifier() uses the package identity automatically.
|
||||
// For unpackaged apps, we need to provide an AUMID, but that case is less common
|
||||
// and toast notifications may not be supported without additional setup.
|
||||
auto notifier = ToastNotificationManager::CreateToastNotifier();
|
||||
notifier.Show(toast);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Toast notification is a best-effort feature. If it fails (e.g., notifications
|
||||
// are disabled, or the app is unpackaged without proper AUMID setup), we silently
|
||||
// ignore the error.
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/cascadia/TerminalApp/DesktopNotification.h
Normal file
52
src/cascadia/TerminalApp/DesktopNotification.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- DesktopNotification.h
|
||||
|
||||
Module Description:
|
||||
- Helper for sending Windows desktop toast notifications. Used by the
|
||||
`OutputNotificationStyle::Notification` flag to surface activity
|
||||
and prompt-return events to the user via the Windows notification center.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct DesktopNotificationArgs
|
||||
{
|
||||
winrt::hstring Title;
|
||||
winrt::hstring Message;
|
||||
uint32_t TabIndex{ 0 };
|
||||
};
|
||||
|
||||
class DesktopNotification
|
||||
{
|
||||
public:
|
||||
// Sends a toast notification with the given title and message.
|
||||
// When the user clicks the toast, the `Activated` callback fires
|
||||
// with the tabIndex that was passed in, so the caller can switch
|
||||
// to the correct tab and summon the window.
|
||||
//
|
||||
// activated: A callback invoked on the background thread when the
|
||||
// toast is clicked. The uint32_t parameter is the tab index.
|
||||
static void SendNotification(
|
||||
const DesktopNotificationArgs& args,
|
||||
std::function<void(uint32_t tabIndex)> activated);
|
||||
|
||||
// Rate-limits toast notifications so we don't spam the user.
|
||||
// Returns true if a notification is allowed, false if too recent.
|
||||
static bool ShouldSendNotification();
|
||||
|
||||
private:
|
||||
static std::atomic<int64_t> _lastNotificationTime;
|
||||
|
||||
// Minimum interval between notifications, in 100ns ticks (FILETIME units).
|
||||
// 5 seconds = 5 * 10,000,000
|
||||
static constexpr int64_t MinNotificationIntervalTicks = 50'000'000LL;
|
||||
};
|
||||
}
|
||||
@@ -16,6 +16,23 @@ namespace TerminalApp
|
||||
Boolean FlashTaskbar { get; };
|
||||
};
|
||||
|
||||
[flags]
|
||||
enum OutputNotificationStyle
|
||||
{
|
||||
Taskbar = 0x1,
|
||||
Audible = 0x2,
|
||||
Tab = 0x4,
|
||||
Notification = 0x8,
|
||||
All = 0xffffffff
|
||||
};
|
||||
|
||||
runtimeclass NotificationEventArgs
|
||||
{
|
||||
OutputNotificationStyle Style { get; };
|
||||
String Title { get; };
|
||||
String Body { get; };
|
||||
};
|
||||
|
||||
interface IPaneContent
|
||||
{
|
||||
Windows.UI.Xaml.FrameworkElement GetRoot();
|
||||
@@ -40,6 +57,7 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> CloseRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
|
||||
event Windows.Foundation.TypedEventHandler<IPaneContent, NotificationEventArgs> NotificationRequested;
|
||||
event Windows.Foundation.TypedEventHandler<IPaneContent, BellEventArgs> BellRequested;
|
||||
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> TabColorChanged;
|
||||
|
||||
@@ -923,4 +923,16 @@
|
||||
<data name="InvalidRegex" xml:space="preserve">
|
||||
<value>An invalid regular expression was found.</value>
|
||||
</data>
|
||||
<data name="NotificationTitle" xml:space="preserve">
|
||||
<value>Windows Terminal</value>
|
||||
<comment>Title shown in desktop toast notifications for tab activity.</comment>
|
||||
</data>
|
||||
<data name="NotificationMessage_TabActivity" xml:space="preserve">
|
||||
<value>Tab "{0}" has new activity</value>
|
||||
<comment>{Locked="{0}"}Message shown in a desktop toast notification when a tab produces output. {0} is the tab title.</comment>
|
||||
</data>
|
||||
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
|
||||
<value>Tab "{0}" in {1} has new activity</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}Message shown in a desktop toast notification when a tab produces output. {0} is the tab title. {1} is the window name.</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1161,6 +1161,38 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
events.NotificationRequested = content.NotificationRequested(
|
||||
winrt::auto_revoke,
|
||||
[dispatcher, weakThis](TerminalApp::IPaneContent sender, auto notifArgs) -> safe_void_coroutine {
|
||||
const auto weakThisCopy = weakThis;
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
if (const auto tab{ weakThisCopy.get() })
|
||||
{
|
||||
// Other notification styles may be added in the future,
|
||||
// (see GH#7955 for more details)
|
||||
//
|
||||
// Currently the only style is to request a toast
|
||||
// notification. We'll just check for that flag for now.
|
||||
const auto style = notifArgs.Style();
|
||||
if (WI_IsFlagSet(style, winrt::TerminalApp::OutputNotificationStyle::Notification))
|
||||
{
|
||||
// Request a desktop toast notification.
|
||||
// TerminalPage subscribes to this event and handles sending the toast
|
||||
// and processing its activation (summoning the window + switching tabs).
|
||||
const auto notifTitle = notifArgs.Title();
|
||||
const auto notifBody = notifArgs.Body();
|
||||
if (!notifTitle.empty())
|
||||
{
|
||||
tab->TabToastNotificationRequested.raise(notifTitle, notifBody, tab->TabViewIndex());
|
||||
}
|
||||
else
|
||||
{
|
||||
tab->TabToastNotificationRequested.raise(tab->Title(), L"", tab->TabViewIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (const auto& terminal{ content.try_as<TerminalApp::TerminalPaneContent>() })
|
||||
{
|
||||
events.RestartTerminalRequested = terminal.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &Tab::_bubbleRestartTerminalRequested });
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
til::typed_event<TerminalApp::Tab, IInspectable> ActivePaneChanged;
|
||||
til::event<winrt::delegate<>> TabRaiseVisualBell;
|
||||
til::event<winrt::delegate<winrt::hstring /*title*/, winrt::hstring /*body*/, uint32_t /*tabIndex*/>> TabToastNotificationRequested;
|
||||
til::typed_event<IInspectable, IInspectable> TaskbarProgressChanged;
|
||||
|
||||
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
|
||||
@@ -176,6 +177,7 @@ namespace winrt::TerminalApp::implementation
|
||||
struct ContentEventTokens
|
||||
{
|
||||
winrt::TerminalApp::IPaneContent::BellRequested_revoker BellRequested;
|
||||
winrt::TerminalApp::IPaneContent::NotificationRequested_revoker NotificationRequested;
|
||||
winrt::TerminalApp::IPaneContent::TitleChanged_revoker TitleChanged;
|
||||
winrt::TerminalApp::IPaneContent::TabColorChanged_revoker TabColorChanged;
|
||||
winrt::TerminalApp::IPaneContent::TaskbarProgressChanged_revoker TaskbarProgressChanged;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "DebugTapConnection.h"
|
||||
#include "..\TerminalSettingsModel\FileUtils.h"
|
||||
#include "../TerminalSettingsAppAdapterLib/TerminalSettings.h"
|
||||
#include "DesktopNotification.h"
|
||||
|
||||
#include <shlobj.h>
|
||||
|
||||
@@ -150,6 +151,15 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
// When a tab requests a desktop toast notification (OutputNotificationStyle::Notification),
|
||||
// send the toast and handle activation by summoning this window and switching to the tab.
|
||||
newTabImpl->TabToastNotificationRequested([weakThis{ get_weak() }](const winrt::hstring& title, const winrt::hstring& body, uint32_t tabIndex) {
|
||||
if (const auto page{ weakThis.get() })
|
||||
{
|
||||
page->_SendDesktopNotification(title, body, tabIndex);
|
||||
}
|
||||
});
|
||||
|
||||
auto tabViewItem = newTabImpl->TabViewItem();
|
||||
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
|
||||
|
||||
@@ -1185,4 +1195,68 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
return _tabs.Size() > 1;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sends a Windows desktop toast notification for a tab. When the user clicks
|
||||
// the toast, summon this window and switch to the specified tab.
|
||||
// Arguments:
|
||||
// - tabTitle: The title of the tab to display in the notification.
|
||||
// - tabIndex: The index of the tab to switch to when the toast is activated.
|
||||
void TerminalPage::_SendDesktopNotification(const winrt::hstring& tabTitle, const winrt::hstring& body, uint32_t tabIndex)
|
||||
{
|
||||
// Build the notification message.
|
||||
// If a custom body is provided (e.g. from OSC 777), use the title/body directly.
|
||||
// Otherwise, build the standard tab-activity notification message.
|
||||
winrt::hstring notifTitle;
|
||||
winrt::hstring message;
|
||||
if (!body.empty())
|
||||
{
|
||||
notifTitle = tabTitle;
|
||||
message = body;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the window name if available for context, otherwise just use the tab title.
|
||||
// Use the raw WindowName (not WindowNameForDisplay) so we don't include
|
||||
// the "<unnamed window>" placeholder in the notification body.
|
||||
const auto windowName = _WindowProperties ? _WindowProperties.WindowName() : winrt::hstring{};
|
||||
if (!windowName.empty())
|
||||
{
|
||||
message = RS_fmt(L"NotificationMessage_TabActivityInWindow", std::wstring_view{ tabTitle }, std::wstring_view{ windowName });
|
||||
}
|
||||
else
|
||||
{
|
||||
message = RS_fmt(L"NotificationMessage_TabActivity", std::wstring_view{ tabTitle });
|
||||
}
|
||||
notifTitle = RS_(L"NotificationTitle");
|
||||
}
|
||||
|
||||
implementation::DesktopNotificationArgs args;
|
||||
args.Title = notifTitle;
|
||||
args.Message = message;
|
||||
args.TabIndex = tabIndex;
|
||||
|
||||
// Capture a weak ref and the dispatcher so we can marshal back to the UI thread
|
||||
// when the toast is activated.
|
||||
auto weakThis = get_weak();
|
||||
auto dispatcher = Dispatcher();
|
||||
|
||||
implementation::DesktopNotification::SendNotification(
|
||||
args,
|
||||
[weakThis, dispatcher, tabIndex](uint32_t /*activatedTabIndex*/) -> void {
|
||||
// The toast Activated callback fires on a background thread.
|
||||
// We need to dispatch to the UI thread to summon the window and switch tabs.
|
||||
[](auto weakThis, auto dispatcher, auto tabIndex) -> safe_void_coroutine {
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
if (const auto page{ weakThis.get() })
|
||||
{
|
||||
// Summon this window (bring to foreground)
|
||||
page->SummonWindowRequested.raise(nullptr, nullptr);
|
||||
|
||||
// Switch to the tab that triggered the notification
|
||||
page->_SelectTab(tabIndex);
|
||||
}
|
||||
}(weakThis, dispatcher, tabIndex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +173,7 @@
|
||||
<ClInclude Include="SettingsPaneContent.h">
|
||||
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DesktopNotification.h" />
|
||||
<ClInclude Include="Toast.h" />
|
||||
<ClInclude Include="TerminalSettingsCache.h" />
|
||||
<ClInclude Include="SuggestionsControl.h">
|
||||
@@ -286,6 +287,7 @@
|
||||
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
<ClCompile Include="DesktopNotification.cpp" />
|
||||
<ClCompile Include="Toast.cpp" />
|
||||
<ClCompile Include="TerminalSettingsCache.cpp" />
|
||||
<ClCompile Include="SuggestionsControl.cpp">
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<ClCompile Include="fzf/fzf.cpp">
|
||||
<Filter>fzf</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DesktopNotification.cpp" />
|
||||
<ClCompile Include="Toast.cpp" />
|
||||
<ClCompile Include="LanguageProfileNotifier.cpp" />
|
||||
<ClCompile Include="TerminalSettingsCache.cpp" />
|
||||
@@ -58,6 +59,7 @@
|
||||
<ClInclude Include="fzf/fzf.h">
|
||||
<Filter>fzf</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DesktopNotification.h" />
|
||||
<ClInclude Include="Toast.h" />
|
||||
<ClInclude Include="LanguageProfileNotifier.h" />
|
||||
<ClInclude Include="WindowsPackageManagerFactory.h" />
|
||||
|
||||
@@ -570,6 +570,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void _activePaneChanged(winrt::TerminalApp::Tab tab, Windows::Foundation::IInspectable args);
|
||||
safe_void_coroutine _doHandleSuggestions(Microsoft::Terminal::Settings::Model::SuggestionsArgs realArgs);
|
||||
|
||||
void _SendDesktopNotification(const winrt::hstring& tabTitle, const winrt::hstring& body, uint32_t tabIndex);
|
||||
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_controlEvents._SetTaskbarProgress = _control.SetTaskbarProgress(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlSetTaskbarProgress });
|
||||
_controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlReadOnlyChanged });
|
||||
_controlEvents._FocusFollowMouseRequested = _control.FocusFollowMouseRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlFocusFollowMouseRequested });
|
||||
_controlEvents._ShowNotification = _control.ShowNotification(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlShowNotification });
|
||||
}
|
||||
void TerminalPaneContent::_removeControlEvents()
|
||||
{
|
||||
@@ -182,6 +183,15 @@ namespace winrt::TerminalApp::implementation
|
||||
FocusRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void TerminalPaneContent::_controlShowNotification(const IInspectable& /*sender*/, const ShowNotificationEventArgs& args)
|
||||
{
|
||||
auto notifArgs = winrt::make<implementation::NotificationEventArgs>(
|
||||
OutputNotificationStyle::Notification,
|
||||
args.Title(),
|
||||
args.Body());
|
||||
NotificationRequested.raise(*this, notifArgs);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when our attached control is closed. Triggers listeners to our close
|
||||
// event, if we're a leaf pane.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "TerminalPaneContent.g.h"
|
||||
#include "BellEventArgs.g.h"
|
||||
#include "BasicPaneEvents.h"
|
||||
#include "NotificationEventArgs.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
@@ -19,6 +20,20 @@ namespace winrt::TerminalApp::implementation
|
||||
til::property<bool> FlashTaskbar;
|
||||
};
|
||||
|
||||
struct NotificationEventArgs : public NotificationEventArgsT<NotificationEventArgs>
|
||||
{
|
||||
public:
|
||||
NotificationEventArgs(
|
||||
winrt::TerminalApp::OutputNotificationStyle style,
|
||||
const winrt::hstring& title = {},
|
||||
const winrt::hstring& body = {}) :
|
||||
Style(style), Title(title), Body(body) {}
|
||||
|
||||
til::property<winrt::TerminalApp::OutputNotificationStyle> Style;
|
||||
til::property<winrt::hstring> Title;
|
||||
til::property<winrt::hstring> Body;
|
||||
};
|
||||
|
||||
struct TerminalPaneContent : TerminalPaneContentT<TerminalPaneContent>, BasicPaneEvents
|
||||
{
|
||||
TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
@@ -79,6 +94,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Control::TermControl::SetTaskbarProgress_revoker _SetTaskbarProgress;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ReadOnlyChanged_revoker _ReadOnlyChanged;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::FocusFollowMouseRequested_revoker _FocusFollowMouseRequested;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ShowNotification_revoker _ShowNotification;
|
||||
|
||||
} _controlEvents;
|
||||
void _setupControlEvents();
|
||||
@@ -96,6 +112,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _controlSetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _controlReadOnlyChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _controlFocusFollowMouseRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _controlShowNotification(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Microsoft::Terminal::Control::ShowNotificationEventArgs& args);
|
||||
|
||||
void _closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _restartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
#include <winrt/Windows.Media.Playback.h>
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
|
||||
#include <winrt/Windows.UI.Notifications.h>
|
||||
#include <winrt/Windows.Data.Xml.Dom.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
|
||||
|
||||
@@ -139,6 +139,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto pfnSearchMissingCommand = [this](auto&& PH1, auto&& PH2) { _terminalSearchMissingCommand(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
|
||||
_terminal->SetSearchMissingCommandCallback(pfnSearchMissingCommand);
|
||||
|
||||
auto pfnShowNotification = [this](auto&& PH1, auto&& PH2) { _terminalShowNotification(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
|
||||
_terminal->SetShowNotificationCallback(pfnShowNotification);
|
||||
|
||||
auto pfnClearQuickFix = [this] { ClearQuickFix(); };
|
||||
_terminal->SetClearQuickFixCallback(pfnClearQuickFix);
|
||||
|
||||
@@ -1685,6 +1688,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
SearchMissingCommand.raise(*this, make<implementation::SearchMissingCommandEventArgs>(hstring{ missingCommand }, bufferRow));
|
||||
}
|
||||
|
||||
void ControlCore::_terminalShowNotification(std::wstring_view title, std::wstring_view body)
|
||||
{
|
||||
ShowNotification.raise(*this, make<implementation::ShowNotificationEventArgs>(hstring{ title }, hstring{ body }));
|
||||
}
|
||||
|
||||
void ControlCore::OpenCWD()
|
||||
{
|
||||
const auto workingDirectory = WorkingDirectory();
|
||||
|
||||
@@ -293,6 +293,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
til::typed_event<IInspectable, Control::OpenHyperlinkEventArgs> OpenHyperlink;
|
||||
til::typed_event<IInspectable, Control::CompletionsChangedEventArgs> CompletionsChanged;
|
||||
til::typed_event<IInspectable, Control::SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
til::typed_event<IInspectable, Control::ShowNotificationEventArgs> ShowNotification;
|
||||
til::typed_event<> RefreshQuickFixUI;
|
||||
til::typed_event<IInspectable, Control::WindowSizeChangedEventArgs> WindowSizeChanged;
|
||||
|
||||
@@ -334,6 +335,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const int velocity,
|
||||
const std::chrono::microseconds duration);
|
||||
void _terminalSearchMissingCommand(std::wstring_view missingCommand, const til::CoordType& bufferRow);
|
||||
void _terminalShowNotification(std::wstring_view title, std::wstring_view body);
|
||||
void _terminalWindowSizeChanged(int32_t width, int32_t height);
|
||||
|
||||
void _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
|
||||
|
||||
@@ -197,6 +197,7 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ShowNotificationEventArgs> ShowNotification;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RefreshQuickFixUI;
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowSizeChangedEventArgs> WindowSizeChanged;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "CharSentEventArgs.g.h"
|
||||
#include "StringSentEventArgs.g.h"
|
||||
#include "SearchMissingCommandEventArgs.g.h"
|
||||
#include "ShowNotificationEventArgs.g.h"
|
||||
#include "WindowSizeChangedEventArgs.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
@@ -252,6 +253,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
til::property<til::CoordType> BufferRow;
|
||||
};
|
||||
|
||||
struct ShowNotificationEventArgs : public ShowNotificationEventArgsT<ShowNotificationEventArgs>
|
||||
{
|
||||
public:
|
||||
ShowNotificationEventArgs(const winrt::hstring& title, const winrt::hstring& body) :
|
||||
Title(title),
|
||||
Body(body) {}
|
||||
|
||||
til::property<winrt::hstring> Title;
|
||||
til::property<winrt::hstring> Body;
|
||||
};
|
||||
|
||||
struct WindowSizeChangedEventArgs : public WindowSizeChangedEventArgsT<WindowSizeChangedEventArgs>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -160,6 +160,12 @@ namespace Microsoft.Terminal.Control
|
||||
Int32 BufferRow { get; };
|
||||
}
|
||||
|
||||
runtimeclass ShowNotificationEventArgs
|
||||
{
|
||||
String Title { get; };
|
||||
String Body { get; };
|
||||
}
|
||||
|
||||
runtimeclass WindowSizeChangedEventArgs
|
||||
{
|
||||
Int32 Width;
|
||||
|
||||
@@ -328,6 +328,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_revokers.CompletionsChanged = _core.CompletionsChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCompletionsChanged });
|
||||
_revokers.RestartTerminalRequested = _core.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleRestartTerminalRequested });
|
||||
_revokers.SearchMissingCommand = _core.SearchMissingCommand(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSearchMissingCommand });
|
||||
_revokers.ShowNotification = _core.ShowNotification(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleShowNotification });
|
||||
_revokers.WindowSizeChanged = _core.WindowSizeChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWindowSizeChanged });
|
||||
_revokers.WriteToClipboard = _core.WriteToClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWriteToClipboard });
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
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(ShowNotification, IInspectable, Control::ShowNotificationEventArgs);
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -469,6 +470,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Control::ControlCore::CompletionsChanged_revoker CompletionsChanged;
|
||||
Control::ControlCore::RestartTerminalRequested_revoker RestartTerminalRequested;
|
||||
Control::ControlCore::SearchMissingCommand_revoker SearchMissingCommand;
|
||||
Control::ControlCore::ShowNotification_revoker ShowNotification;
|
||||
Control::ControlCore::RefreshQuickFixUI_revoker RefreshQuickFixUI;
|
||||
Control::ControlCore::WindowSizeChanged_revoker WindowSizeChanged;
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, CharSentEventArgs> CharSent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, StringSentEventArgs> StringSent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ShowNotificationEventArgs> ShowNotification;
|
||||
|
||||
|
||||
Microsoft.UI.Xaml.Controls.CommandBarFlyout ContextMenu { get; };
|
||||
|
||||
@@ -124,6 +124,7 @@ namespace Microsoft.Terminal.Core
|
||||
Boolean AllowKittyKeyboardMode { get; };
|
||||
Boolean AllowVtChecksumReport { get; };
|
||||
Boolean AllowVtClipboardWrite { get; };
|
||||
Boolean AllowOscNotifications { get; };
|
||||
Boolean TrimBlockSelection { get; };
|
||||
Boolean DetectURLs { get; };
|
||||
|
||||
|
||||
@@ -251,6 +251,7 @@ void Terminal::SetOptionalFeatures(winrt::Microsoft::Terminal::Core::ICoreSettin
|
||||
auto features = til::enumset<ITermDispatch::OptionalFeature>{};
|
||||
features.set(ITermDispatch::OptionalFeature::ChecksumReport, settings.AllowVtChecksumReport());
|
||||
features.set(ITermDispatch::OptionalFeature::ClipboardWrite, settings.AllowVtClipboardWrite());
|
||||
features.set(ITermDispatch::OptionalFeature::DesktopNotification, settings.AllowOscNotifications());
|
||||
engine.Dispatch().SetOptionalFeatures(features);
|
||||
}
|
||||
|
||||
@@ -1260,6 +1261,11 @@ void Microsoft::Terminal::Core::Terminal::SetSearchMissingCommandCallback(std::f
|
||||
_pfnSearchMissingCommand.swap(pfn);
|
||||
}
|
||||
|
||||
void Microsoft::Terminal::Core::Terminal::SetShowNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept
|
||||
{
|
||||
_pfnShowNotification.swap(pfn);
|
||||
}
|
||||
|
||||
void Microsoft::Terminal::Core::Terminal::SetClearQuickFixCallback(std::function<void()> pfn) noexcept
|
||||
{
|
||||
_pfnClearQuickFix.swap(pfn);
|
||||
|
||||
@@ -162,6 +162,8 @@ public:
|
||||
|
||||
void SearchMissingCommand(const std::wstring_view command) override;
|
||||
|
||||
void ShowNotification(const std::wstring_view title, const std::wstring_view body) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void ClearMark();
|
||||
@@ -230,6 +232,7 @@ public:
|
||||
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 SetSearchMissingCommandCallback(std::function<void(std::wstring_view, const til::CoordType)> pfn) noexcept;
|
||||
void SetShowNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept;
|
||||
void SetClearQuickFixCallback(std::function<void()> pfn) noexcept;
|
||||
void SetWindowSizeChangedCallback(std::function<void(int32_t, int32_t)> pfn) noexcept;
|
||||
void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept;
|
||||
@@ -338,6 +341,7 @@ private:
|
||||
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, const til::CoordType)> _pfnSearchMissingCommand;
|
||||
std::function<void(std::wstring_view, std::wstring_view)> _pfnShowNotification;
|
||||
std::function<void()> _pfnClearQuickFix;
|
||||
std::function<void(int32_t, int32_t)> _pfnWindowSizeChanged;
|
||||
|
||||
|
||||
@@ -364,6 +364,14 @@ void Terminal::SearchMissingCommand(const std::wstring_view command)
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::ShowNotification(const std::wstring_view title, const std::wstring_view body)
|
||||
{
|
||||
if (_pfnShowNotification)
|
||||
{
|
||||
_pfnShowNotification(title, body);
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::NotifyBufferRotation(const int delta)
|
||||
{
|
||||
// Update our selection, so it doesn't move as the buffer is cycled
|
||||
|
||||
@@ -352,6 +352,7 @@ namespace winrt::Microsoft::Terminal::Settings
|
||||
_AllowKittyKeyboardMode = profile.AllowKittyKeyboardMode();
|
||||
_AllowVtChecksumReport = profile.AllowVtChecksumReport();
|
||||
_AllowVtClipboardWrite = profile.AllowVtClipboardWrite();
|
||||
_AllowOscNotifications = profile.AllowOscNotifications();
|
||||
_PathTranslationStyle = profile.PathTranslationStyle();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowKittyKeyboardMode);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowVtChecksumReport);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowVtClipboardWrite);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowOscNotifications);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AnswerbackMessage);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, RainbowSuggestions);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, PathTranslationStyle);
|
||||
|
||||
@@ -140,5 +140,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RainbowSuggestions);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowOscNotifications);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,16 @@
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Allow OSC 777 Desktop Notifications -->
|
||||
<local:SettingContainer x:Name="AllowOscNotifications"
|
||||
x:Uid="Profile_AllowOscNotifications"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAllowOscNotifications}"
|
||||
HasSettingValue="{x:Bind Profile.HasAllowOscNotifications, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AllowOscNotificationsOverrideSource, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.AllowOscNotifications, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Answerback Message -->
|
||||
<local:SettingContainer x:Name="AnswerbackMessage"
|
||||
x:Uid="Profile_AnswerbackMessage"
|
||||
|
||||
@@ -573,6 +573,14 @@
|
||||
<value>Allow OSC 52 (Manipulate Selection Data) to write to the clipboard</value>
|
||||
<comment>{Locked="OSC 52"}{Locked="Manipulate Selection Data"}Header for a control to toggle support for applications to change the contents of the Windows system clipboard.</comment>
|
||||
</data>
|
||||
<data name="Profile_AllowOscNotifications.Header" xml:space="preserve">
|
||||
<value>Allow OSC 777 (Desktop Notification) to show toast notifications</value>
|
||||
<comment>{Locked="OSC 777"}{Locked="Desktop Notification"}Header for a control to toggle support for applications to display desktop toast notifications via the OSC 777 escape sequence.</comment>
|
||||
</data>
|
||||
<data name="Profile_AllowOscNotifications.HelpText" xml:space="preserve">
|
||||
<value>When enabled, applications can send the OSC 777 escape sequence to trigger a desktop notification with a custom title and body.</value>
|
||||
<comment>{Locked="OSC 777"}Help text for the OSC 777 desktop notification toggle.</comment>
|
||||
</data>
|
||||
<data name="Globals_AllowHeadless.Header" xml:space="preserve">
|
||||
<value>Allow Windows Terminal to run in the background</value>
|
||||
<comment>Header for a control to toggle support for Windows Terminal to run in the background.</comment>
|
||||
|
||||
@@ -107,6 +107,7 @@ Author(s):
|
||||
X(bool, AllowKittyKeyboardMode, "compatibility.kittyKeyboardMode", true) \
|
||||
X(bool, AllowVtChecksumReport, "compatibility.allowDECRQCRA", false) \
|
||||
X(bool, AllowVtClipboardWrite, "compatibility.allowOSC52", true) \
|
||||
X(bool, AllowOscNotifications, "compatibility.allowOSC777", true) \
|
||||
X(bool, AllowKeypadMode, "compatibility.allowDECNKM", false) \
|
||||
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None)
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowVtChecksumReport);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowKeypadMode);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowOscNotifications);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
|
||||
}
|
||||
|
||||
@@ -353,6 +353,23 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Toast notification activations launch a new unelevated instance of the
|
||||
// app with "__fromToast" as the sole command-line argument. It will always
|
||||
// start a new instance of our exe.
|
||||
//
|
||||
// However, we're also able to just handle the .Activated event on the toast
|
||||
// itself, so we don't care about this process we're spawning. So before we
|
||||
// do _anything_ else, if we were created for a toast, just immediately
|
||||
// bail.
|
||||
const auto args = commandlineToArgArray(GetCommandLineW());
|
||||
{
|
||||
if (args.size() == 2 && args[1] == L"__fromToast")
|
||||
{
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
__assume(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Windows Terminal is a single-instance application. Either acquire ownership
|
||||
// over the mutex, or hand off the command line to the existing instance.
|
||||
const auto mutex = acquireMutexOrAttemptHandoff(windowClassName.c_str(), nCmdShow);
|
||||
@@ -406,8 +423,6 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
}
|
||||
}
|
||||
|
||||
const auto args = commandlineToArgArray(GetCommandLineW());
|
||||
|
||||
if (args.size() == 2 && args[1] == L"-Embedding")
|
||||
{
|
||||
// We were launched for ConPTY handoff. We have no windows and also don't want to exit.
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
X(bool, RepositionCursorWithMouse, false) \
|
||||
X(bool, RainbowSuggestions) \
|
||||
X(bool, AllowVtChecksumReport) \
|
||||
X(bool, AllowVtClipboardWrite, true)
|
||||
X(bool, AllowVtClipboardWrite, true) \
|
||||
X(bool, AllowOscNotifications)
|
||||
|
||||
// --------------------------- Control Settings ---------------------------
|
||||
// All of these settings are defined in IControlSettings.
|
||||
|
||||
@@ -437,3 +437,7 @@ void ConhostInternalGetSet::SearchMissingCommand(std::wstring_view /*missingComm
|
||||
{
|
||||
// Not implemented for conhost.
|
||||
}
|
||||
void ConhostInternalGetSet::ShowNotification(std::wstring_view /*title*/, std::wstring_view /*body*/)
|
||||
{
|
||||
// Not implemented for conhost.
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ public:
|
||||
|
||||
void SearchMissingCommand(std::wstring_view missingCommand) override;
|
||||
|
||||
void ShowNotification(std::wstring_view title, std::wstring_view body) override;
|
||||
|
||||
private:
|
||||
Microsoft::Console::IIoProvider& _io;
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
{
|
||||
ChecksumReport,
|
||||
ClipboardWrite,
|
||||
DesktopNotification,
|
||||
};
|
||||
|
||||
#pragma warning(push)
|
||||
@@ -164,6 +165,8 @@ public:
|
||||
|
||||
virtual void DoWTAction(const std::wstring_view string) = 0;
|
||||
|
||||
virtual void DoDesktopNotification(const std::wstring_view string) = 0;
|
||||
|
||||
virtual StringHandler DefineSixelImage(const VTInt macroParameter,
|
||||
const DispatchTypes::SixelBackground backgroundSelect,
|
||||
const VTParameter backgroundColor) = 0; // SIXEL
|
||||
|
||||
@@ -90,5 +90,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
virtual void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) = 0;
|
||||
|
||||
virtual void SearchMissingCommand(const std::wstring_view command) = 0;
|
||||
|
||||
virtual void ShowNotification(const std::wstring_view title, const std::wstring_view body) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3800,6 +3800,36 @@ void AdaptDispatch::DoWTAction(const std::wstring_view string)
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - OSC 777 - Handles desktop notification requests.
|
||||
// The format is: OSC 777;notify;title;body ST
|
||||
// - Not actually used in conhost
|
||||
// Arguments:
|
||||
// - string: contains the parameters that define the notification
|
||||
void AdaptDispatch::DoDesktopNotification(const std::wstring_view string)
|
||||
{
|
||||
if (!_optionalFeatures.test(OptionalFeature::DesktopNotification))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto parts = Utils::SplitString(string, L';');
|
||||
|
||||
if (parts.size() < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto action = til::at(parts, 0);
|
||||
|
||||
if (action == L"notify")
|
||||
{
|
||||
const auto title = parts.size() >= 2 ? til::at(parts, 1) : std::wstring_view{};
|
||||
const auto body = parts.size() >= 3 ? til::at(parts, 2) : std::wstring_view{};
|
||||
_api.ShowNotification(title, body);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - SIXEL - Defines an image transmitted in sixel format via the returned
|
||||
// StringHandler function.
|
||||
|
||||
@@ -161,6 +161,8 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
void DoWTAction(const std::wstring_view string) override;
|
||||
|
||||
void DoDesktopNotification(const std::wstring_view string) override;
|
||||
|
||||
StringHandler DefineSixelImage(const VTInt macroParameter,
|
||||
const DispatchTypes::SixelBackground backgroundSelect,
|
||||
const VTParameter backgroundColor) override; // SIXEL
|
||||
|
||||
@@ -151,6 +151,8 @@ public:
|
||||
|
||||
void DoWTAction(const std::wstring_view /*string*/) override {}
|
||||
|
||||
void DoDesktopNotification(const std::wstring_view /*string*/) override {}
|
||||
|
||||
StringHandler DefineSixelImage(const VTInt /*macroParameter*/,
|
||||
const DispatchTypes::SixelBackground /*backgroundSelect*/,
|
||||
const VTParameter /*backgroundColor*/) override { return nullptr; }; // SIXEL
|
||||
|
||||
@@ -224,6 +224,11 @@ public:
|
||||
Log::Comment(L"SearchMissingCommand MOCK called...");
|
||||
}
|
||||
|
||||
void ShowNotification(const std::wstring_view /*title*/, const std::wstring_view /*body*/) override
|
||||
{
|
||||
Log::Comment(L"ShowNotification MOCK called...");
|
||||
}
|
||||
|
||||
void PrepData()
|
||||
{
|
||||
PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter.
|
||||
|
||||
@@ -900,6 +900,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const size_t parameter, const s
|
||||
_dispatch->DoWTAction(string);
|
||||
break;
|
||||
}
|
||||
case OscActionCodes::DesktopNotification:
|
||||
{
|
||||
_dispatch->DoDesktopNotification(string);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -225,6 +225,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
ResetHighlightColor = 117,
|
||||
FinalTermAction = 133,
|
||||
VsCodeAction = 633,
|
||||
DesktopNotification = 777,
|
||||
ITerm2Action = 1337,
|
||||
WTAction = 9001,
|
||||
};
|
||||
|
||||
@@ -417,8 +417,15 @@ function Invoke-CodeFormat() {
|
||||
)
|
||||
|
||||
$clangFormatPath = & 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -find "**\x64\bin\clang-format.exe"
|
||||
If ([String]::IsNullOrEmpty($clangFormatPath)) {
|
||||
# try again with prerelease versions of Visual Studio,
|
||||
# and just take the first
|
||||
$clangFormatPath = & 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -prerelease -find "**\clang-format.exe" | Select-Object -First 1
|
||||
}
|
||||
|
||||
If ([String]::IsNullOrEmpty($clangFormatPath)) {
|
||||
Write-Error "No Visual Studio-supplied version of clang-format could be found."
|
||||
return -1
|
||||
}
|
||||
|
||||
$root = Find-OpenConsoleRoot
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
rem run clang-format on c++ files
|
||||
|
||||
powershell -noprofile "import-module %OPENCON_TOOLS%\openconsole.psm1; Invoke-CodeFormat"
|
||||
pwsh -noprofile "import-module %OPENCON_TOOLS%\openconsole.psm1; Invoke-CodeFormat"
|
||||
|
||||
Reference in New Issue
Block a user