From 03ea0f49ad18fe919b9856b09310219e3b3b93d9 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 30 Mar 2021 11:08:03 -0500 Subject: [PATCH] Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited --- src/cascadia/Remoting/Monarch.cpp | 60 ++++ src/cascadia/Remoting/Monarch.h | 5 + src/cascadia/Remoting/Peasant.cpp | 47 +++ src/cascadia/Remoting/Peasant.h | 4 + src/cascadia/Remoting/Peasant.idl | 4 + .../TerminalApp/AppActionHandlers.cpp | 37 ++- src/cascadia/TerminalApp/AppLogic.cpp | 30 ++ src/cascadia/TerminalApp/AppLogic.h | 7 + src/cascadia/TerminalApp/AppLogic.idl | 5 + .../Resources/en-US/Resources.resw | 8 + .../TerminalApp/ShortcutActionDispatch.cpp | 280 ++++-------------- .../TerminalApp/ShortcutActionDispatch.h | 94 +++--- .../TerminalApp/ShortcutActionDispatch.idl | 95 +++--- .../TerminalApp/TerminalAppLib.vcxproj | 3 + src/cascadia/TerminalApp/TerminalPage.cpp | 200 ++++++++++--- src/cascadia/TerminalApp/TerminalPage.h | 119 +++++--- src/cascadia/TerminalApp/TerminalPage.idl | 9 +- src/cascadia/TerminalApp/TerminalPage.xaml | 11 + src/cascadia/TerminalApp/Toast.cpp | 40 +++ src/cascadia/TerminalApp/Toast.h | 38 +++ .../TerminalSettingsModel/ActionAndArgs.cpp | 6 + .../TerminalSettingsModel/KeyMapping.idl | 4 +- .../Resources/en-US/Resources.resw | 6 + .../TerminalSettingsModel/defaults.json | 2 + .../UnitTests_Remoting/RemotingTests.cpp | 4 + src/cascadia/WindowsTerminal/AppHost.cpp | 40 +++ src/cascadia/WindowsTerminal/AppHost.h | 4 + tools/GenerateHeaderForJson.ps1 | 13 +- 28 files changed, 755 insertions(+), 420 deletions(-) create mode 100644 src/cascadia/TerminalApp/Toast.cpp create mode 100644 src/cascadia/TerminalApp/Toast.h diff --git a/src/cascadia/Remoting/Monarch.cpp b/src/cascadia/Remoting/Monarch.cpp index f7aa8bee8..5fd86a251 100644 --- a/src/cascadia/Remoting/Monarch.cpp +++ b/src/cascadia/Remoting/Monarch.cpp @@ -75,6 +75,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation auto newPeasantsId = peasant.GetID(); // Add an event listener to the peasant's WindowActivated event. peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated }); + peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows }); _peasants[newPeasantsId] = peasant; @@ -571,4 +572,63 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation result->WindowName(targetWindowName); return *result; } + + // Method Description: + // - Helper for doing something on each and every peasant, with no regard + // for if the peasant is living or dead. + // - We'll try calling callback on every peasant. + // - If any single peasant is dead, then we'll call errorCallback, and move on. + // - We're taking an errorCallback here, because the thing we usually want + // to do is TraceLog a message, but TraceLoggingWrite is actually a macro + // that _requires_ the second arg to be a string literal. It can't just be + // a variable. + // Arguments: + // - callback: The function to call on each peasant + // - errorCallback: The function to call if a peasant is dead. + // Return Value: + // - + void Monarch::_forAllPeasantsIgnoringTheDead(std::function callback, + std::function errorCallback) + { + for (const auto& [id, p] : _peasants) + { + try + { + callback(p, id); + } + catch (...) + { + LOG_CAUGHT_EXCEPTION(); + // If this fails, we don't _really_ care. Just move on to the + // next one. Someone else will clean up the dead peasant. + errorCallback(id); + } + } + } + + // Method Description: + // - This is an event handler for the IdentifyWindowsRequested event. A + // Peasant may raise that event if they want _all_ windows to identify + // themselves. + // - This will tell each and every peasant to identify themselves. This will + // eventually propagate down to TerminalPage::IdentifyWindow. + // Arguments: + // - + // Return Value: + // - + void Monarch::_identifyWindows(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) + { + // Notify all the peasants to display their ID. + auto callback = [](auto&& p, auto&& /*id*/) { + p.DisplayWindowId(); + }; + auto onError = [](auto&& id) { + TraceLoggingWrite(g_hRemotingProvider, + "Monarch_identifyWindows_Failed", + TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not identify"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + }; + _forAllPeasantsIgnoringTheDead(callback, onError); + } } diff --git a/src/cascadia/Remoting/Monarch.h b/src/cascadia/Remoting/Monarch.h index 8b9ddfa6e..796c6aa07 100644 --- a/src/cascadia/Remoting/Monarch.h +++ b/src/cascadia/Remoting/Monarch.h @@ -74,6 +74,11 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation void _doHandleActivatePeasant(const winrt::com_ptr& args); void _clearOldMruEntries(const uint64_t peasantID); + void _identifyWindows(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); + + void _forAllPeasantsIgnoringTheDead(std::function callback, + std::function errorCallback); friend class RemotingUnitTests::RemotingTests; }; } diff --git a/src/cascadia/Remoting/Peasant.cpp b/src/cascadia/Remoting/Peasant.cpp index ee34887c2..8eb9ffe52 100644 --- a/src/cascadia/Remoting/Peasant.cpp +++ b/src/cascadia/Remoting/Peasant.cpp @@ -117,4 +117,51 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation return _lastActivatedArgs; } + // Method Description: + // - Tell this window to display it's window ID. We'll raise a + // DisplayWindowIdRequested event, which will get handled in the AppHost, + // and used to tell the app to display the ID toast. + // Arguments: + // - + // Return Value: + // - + void Peasant::DisplayWindowId() + { + // Not worried about try/catching this. The handler is in AppHost, which + // is in-proc for us. + _DisplayWindowIdRequestedHandlers(*this, nullptr); + } + + // Method Description: + // - Raises an event to ask that all windows be identified. This will come + // back to us when the Monarch handles the event and calls our + // DisplayWindowId method. + // Arguments: + // - + // Return Value: + // - + void Peasant::RequestIdentifyWindows() + { + bool successfullyNotified = false; + + try + { + // Try/catch this, because the other side of this event is handled + // by the monarch. The monarch might have died. If they have, this + // will throw an exception. Just eat it, the election thread will + // handle hooking up the new one. + _IdentifyWindowsRequestedHandlers(*this, nullptr); + successfullyNotified = true; + } + catch (...) + { + LOG_CAUGHT_EXCEPTION(); + } + TraceLoggingWrite(g_hRemotingProvider, + "Peasant_RequestIdentifyWindows", + TraceLoggingUInt64(GetID(), "peasantID", "Our ID"), + TraceLoggingBoolean(successfullyNotified, "successfullyNotified", "true if we successfully notified the monarch"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + } + } diff --git a/src/cascadia/Remoting/Peasant.h b/src/cascadia/Remoting/Peasant.h index c1f730374..5b402e616 100644 --- a/src/cascadia/Remoting/Peasant.h +++ b/src/cascadia/Remoting/Peasant.h @@ -22,6 +22,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args); void ActivateWindow(const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args); + void RequestIdentifyWindows(); + void DisplayWindowId(); winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs(); @@ -30,6 +32,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs); TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs); + TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); private: Peasant(const uint64_t testPID); diff --git a/src/cascadia/Remoting/Peasant.idl b/src/cascadia/Remoting/Peasant.idl index 2ef4cb890..1c3ff9123 100644 --- a/src/cascadia/Remoting/Peasant.idl +++ b/src/cascadia/Remoting/Peasant.idl @@ -34,9 +34,13 @@ namespace Microsoft.Terminal.Remoting void ActivateWindow(WindowActivatedArgs args); WindowActivatedArgs GetLastActivatedArgs(); String WindowName { get; }; + void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested + void DisplayWindowId(); // Tells us to display its own ID (which causes a DisplayWindowIdRequested to be raised) event Windows.Foundation.TypedEventHandler WindowActivated; event Windows.Foundation.TypedEventHandler ExecuteCommandlineRequested; + event Windows.Foundation.TypedEventHandler IdentifyWindowsRequested; + event Windows.Foundation.TypedEventHandler DisplayWindowIdRequested; }; [default_interface] runtimeclass Peasant : IPeasant diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 8780f8a94..46c9d1a27 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -552,8 +552,8 @@ namespace winrt::TerminalApp::implementation } } - void TerminalPage::_HandleOpenTabSearch(const IInspectable& /*sender*/, - const ActionEventArgs& args) + void TerminalPage::_HandleTabSearch(const IInspectable& /*sender*/, + const ActionEventArgs& args) { CommandPalette().SetTabs(_tabs, _mruTabs); CommandPalette().EnableTabSearchMode(); @@ -675,4 +675,37 @@ namespace winrt::TerminalApp::implementation actionArgs.Handled(true); } + // Method Description: + // - Raise a IdentifyWindowsRequested event. This will bubble up to the + // AppLogic, to the AppHost, to the Peasant, to the Monarch, then get + // distributed down to _all_ the Peasants, as to display info about the + // window in _every_ Peasant window. + // - This action is also buggy right now, because TeachingTips behave + // weird in XAML Islands. See microsoft-ui-xaml#4382 + // Arguments: + // - + // Return Value: + // - + void TerminalPage::_HandleIdentifyWindows(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + _IdentifyWindowsRequestedHandlers(*this, nullptr); + args.Handled(true); + } + + // Method Description: + // - Display the "Toast" with the name and ID of this window. + // - Unlike _HandleIdentifyWindow**s**, this event just displays the window + // ID and name in the current window. It does not involve any bubbling + // up/down the page/logic/host/manager/peasant/monarch. + // Arguments: + // - + // Return Value: + // - + void TerminalPage::_HandleIdentifyWindow(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + IdentifyWindow(); + args.Handled(true); + } } diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index fecccc750..c8acf24ba 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -1380,4 +1380,34 @@ namespace winrt::TerminalApp::implementation return _root ? _root->AlwaysOnTop() : false; } + void AppLogic::IdentifyWindow() + { + if (_root) + { + _root->IdentifyWindow(); + } + } + + winrt::hstring AppLogic::WindowName() + { + return _root ? _root->WindowName() : L""; + } + void AppLogic::WindowName(const winrt::hstring& name) + { + if (_root) + { + _root->WindowName(name); + } + } + uint64_t AppLogic::WindowId() + { + return _root ? _root->WindowId() : 0; + } + void AppLogic::WindowId(const uint64_t& id) + { + if (_root) + { + _root->WindowId(id); + } + } } diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index a7cc39573..0438061bc 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -60,6 +60,12 @@ namespace winrt::TerminalApp::implementation bool Fullscreen() const; bool AlwaysOnTop() const; + void IdentifyWindow(); + winrt::hstring WindowName(); + void WindowName(const winrt::hstring& name); + uint64_t WindowId(); + void WindowId(const uint64_t& id); + Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi); bool CenterOnLaunch(); TerminalApp::InitialPosition GetInitialPosition(int64_t defaultInitialX, int64_t defaultInitialY); @@ -149,6 +155,7 @@ namespace winrt::TerminalApp::implementation FORWARDED_TYPED_EVENT(AlwaysOnTopChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, AlwaysOnTopChanged); FORWARDED_TYPED_EVENT(RaiseVisualBell, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, RaiseVisualBell); FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress); + FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested); #ifdef UNIT_TESTING friend class TerminalAppLocalTests::CommandlineTest; diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index bc2d45464..35fa8f713 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -48,6 +48,10 @@ namespace TerminalApp Boolean Fullscreen { get; }; Boolean AlwaysOnTop { get; }; + void IdentifyWindow(); + String WindowName; + UInt64 WindowId; + Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi); Boolean CenterOnLaunch { get; }; @@ -78,5 +82,6 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler AlwaysOnTopChanged; event Windows.Foundation.TypedEventHandler RaiseVisualBell; event Windows.Foundation.TypedEventHandler SetTaskbarProgress; + event Windows.Foundation.TypedEventHandler IdentifyWindowsRequested; } } diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 7942b2df6..6c32fbe39 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -595,6 +595,14 @@ More options + + Window + This is displayed as a label for a number, like "Window: 10" + + + unnamed window + text used to identify when a window hasn't been assigned a name by the user + Maximize diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp index c8ae4ed44..3bb2d75bc 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp @@ -10,6 +10,13 @@ using namespace winrt::Microsoft::Terminal; using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::TerminalApp; +#define ACTION_CASE(action) \ + case ShortcutAction::action: \ + { \ + _##action##Handlers(*this, eventArgs); \ + break; \ + } + namespace winrt::TerminalApp::implementation { // Method Description: @@ -34,99 +41,24 @@ namespace winrt::TerminalApp::implementation switch (action) { - case ShortcutAction::CopyText: - { - _CopyTextHandlers(*this, eventArgs); - break; - } - case ShortcutAction::PasteText: - { - _PasteTextHandlers(*this, eventArgs); - break; - } - case ShortcutAction::OpenNewTabDropdown: - { - _OpenNewTabDropdownHandlers(*this, eventArgs); - break; - } - case ShortcutAction::DuplicateTab: - { - _DuplicateTabHandlers(*this, eventArgs); - break; - } - case ShortcutAction::OpenSettings: - { - _OpenSettingsHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::NewTab: - { - _NewTabHandlers(*this, eventArgs); - break; - } - case ShortcutAction::CloseWindow: - { - _CloseWindowHandlers(*this, eventArgs); - break; - } - case ShortcutAction::CloseTab: - { - _CloseTabHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ClosePane: - { - _ClosePaneHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::ScrollUp: - { - _ScrollUpHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ScrollDown: - { - _ScrollDownHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ScrollUpPage: - { - _ScrollUpPageHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ScrollDownPage: - { - _ScrollDownPageHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ScrollToTop: - { - _ScrollToTopHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ScrollToBottom: - { - _ScrollToBottomHandlers(*this, eventArgs); - break; - } - case ShortcutAction::NextTab: - { - _NextTabHandlers(*this, eventArgs); - break; - } - case ShortcutAction::PrevTab: - { - _PrevTabHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::SendInput: - { - _SendInputHandlers(*this, eventArgs); - break; - } + ACTION_CASE(CopyText); + ACTION_CASE(PasteText); + ACTION_CASE(OpenNewTabDropdown); + ACTION_CASE(DuplicateTab); + ACTION_CASE(OpenSettings); + ACTION_CASE(NewTab); + ACTION_CASE(CloseWindow); + ACTION_CASE(CloseTab); + ACTION_CASE(ClosePane); + ACTION_CASE(ScrollUp); + ACTION_CASE(ScrollDown); + ACTION_CASE(ScrollUpPage); + ACTION_CASE(ScrollDownPage); + ACTION_CASE(ScrollToTop); + ACTION_CASE(ScrollToBottom); + ACTION_CASE(NextTab); + ACTION_CASE(PrevTab); + ACTION_CASE(SendInput); case ShortcutAction::SplitVertical: case ShortcutAction::SplitHorizontal: @@ -136,140 +68,34 @@ namespace winrt::TerminalApp::implementation break; } - case ShortcutAction::TogglePaneZoom: - { - _TogglePaneZoomHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::SwitchToTab: - { - _SwitchToTabHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::ResizePane: - { - _ResizePaneHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::MoveFocus: - { - _MoveFocusHandlers(*this, eventArgs); - break; - } - - case ShortcutAction::AdjustFontSize: - { - _AdjustFontSizeHandlers(*this, eventArgs); - break; - } - case ShortcutAction::Find: - { - _FindHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ResetFontSize: - { - _ResetFontSizeHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ToggleShaderEffects: - { - _ToggleShaderEffectsHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ToggleFocusMode: - { - _ToggleFocusModeHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ToggleFullscreen: - { - _ToggleFullscreenHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ToggleAlwaysOnTop: - { - _ToggleAlwaysOnTopHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ToggleCommandPalette: - { - _ToggleCommandPaletteHandlers(*this, eventArgs); - break; - } - case ShortcutAction::SetColorScheme: - { - _SetColorSchemeHandlers(*this, eventArgs); - break; - } - case ShortcutAction::SetTabColor: - { - _SetTabColorHandlers(*this, eventArgs); - break; - } - case ShortcutAction::OpenTabColorPicker: - { - _OpenTabColorPickerHandlers(*this, eventArgs); - break; - } - case ShortcutAction::RenameTab: - { - _RenameTabHandlers(*this, eventArgs); - break; - } - case ShortcutAction::OpenTabRenamer: - { - _OpenTabRenamerHandlers(*this, eventArgs); - break; - } - case ShortcutAction::ExecuteCommandline: - { - _ExecuteCommandlineHandlers(*this, eventArgs); - break; - } - case ShortcutAction::CloseOtherTabs: - { - _CloseOtherTabsHandlers(*this, eventArgs); - break; - } - case ShortcutAction::CloseTabsAfter: - { - _CloseTabsAfterHandlers(*this, eventArgs); - break; - } - case ShortcutAction::MoveTab: - { - _MoveTabHandlers(*this, eventArgs); - break; - } - case ShortcutAction::TabSearch: - { - _TabSearchHandlers(*this, eventArgs); - break; - } - case ShortcutAction::BreakIntoDebugger: - { - _BreakIntoDebuggerHandlers(*this, eventArgs); - break; - } - case ShortcutAction::FindMatch: - { - _FindMatchHandlers(*this, eventArgs); - break; - } - case ShortcutAction::TogglePaneReadOnly: - { - _TogglePaneReadOnlyHandlers(*this, eventArgs); - break; - } - case ShortcutAction::NewWindow: - { - _NewWindowHandlers(*this, eventArgs); - break; - } + ACTION_CASE(TogglePaneZoom); + ACTION_CASE(SwitchToTab); + ACTION_CASE(ResizePane); + ACTION_CASE(MoveFocus); + ACTION_CASE(AdjustFontSize); + ACTION_CASE(Find); + ACTION_CASE(ResetFontSize); + ACTION_CASE(ToggleShaderEffects); + ACTION_CASE(ToggleFocusMode); + ACTION_CASE(ToggleFullscreen); + ACTION_CASE(ToggleAlwaysOnTop); + ACTION_CASE(ToggleCommandPalette); + ACTION_CASE(SetColorScheme); + ACTION_CASE(SetTabColor); + ACTION_CASE(OpenTabColorPicker); + ACTION_CASE(RenameTab); + ACTION_CASE(OpenTabRenamer); + ACTION_CASE(ExecuteCommandline); + ACTION_CASE(CloseOtherTabs); + ACTION_CASE(CloseTabsAfter); + ACTION_CASE(MoveTab); + ACTION_CASE(TabSearch); + ACTION_CASE(BreakIntoDebugger); + ACTION_CASE(FindMatch); + ACTION_CASE(TogglePaneReadOnly); + ACTION_CASE(NewWindow); + ACTION_CASE(IdentifyWindow); + ACTION_CASE(IdentifyWindows); default: return false; } diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.h b/src/cascadia/TerminalApp/ShortcutActionDispatch.h index bdcf59e7a..f4494e2c3 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.h +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.h @@ -13,6 +13,8 @@ namespace TerminalAppLocalTests class KeyBindingsTests; } +#define DECLARE_ACTION(action) TYPED_EVENT(action, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + namespace winrt::TerminalApp::implementation { struct ShortcutActionDispatch : ShortcutActionDispatchT @@ -22,51 +24,53 @@ namespace winrt::TerminalApp::implementation bool DoAction(const Microsoft::Terminal::Settings::Model::ActionAndArgs& actionAndArgs); // clang-format off - TYPED_EVENT(CopyText, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(PasteText, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(OpenNewTabDropdown, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(DuplicateTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(NewTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(CloseWindow, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(CloseTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ClosePane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(SwitchToTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(NextTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(PrevTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(SendInput, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(SplitPane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(TogglePaneZoom, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(AdjustFontSize, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ResetFontSize, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ScrollUp, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ScrollDown, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ScrollUpPage, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ScrollToTop, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ScrollToBottom, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ToggleShaderEffects, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ToggleFocusMode, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ToggleAlwaysOnTop, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ToggleCommandPalette, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(SetColorScheme, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(OpenTabColorPicker, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(RenameTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(OpenTabRenamer, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(ExecuteCommandline, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(CloseOtherTabs, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(CloseTabsAfter, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(TabSearch, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(MoveTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(BreakIntoDebugger, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(FindMatch, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(TogglePaneReadOnly, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); - TYPED_EVENT(NewWindow, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + DECLARE_ACTION(CopyText); + DECLARE_ACTION(PasteText); + DECLARE_ACTION(OpenNewTabDropdown); + DECLARE_ACTION(DuplicateTab); + DECLARE_ACTION(NewTab); + DECLARE_ACTION(CloseWindow); + DECLARE_ACTION(CloseTab); + DECLARE_ACTION(ClosePane); + DECLARE_ACTION(SwitchToTab); + DECLARE_ACTION(NextTab); + DECLARE_ACTION(PrevTab); + DECLARE_ACTION(SendInput); + DECLARE_ACTION(SplitPane); + DECLARE_ACTION(TogglePaneZoom); + DECLARE_ACTION(AdjustFontSize); + DECLARE_ACTION(ResetFontSize); + DECLARE_ACTION(ScrollUp); + DECLARE_ACTION(ScrollDown); + DECLARE_ACTION(ScrollUpPage); + DECLARE_ACTION(ScrollDownPage); + DECLARE_ACTION(ScrollToTop); + DECLARE_ACTION(ScrollToBottom); + DECLARE_ACTION(OpenSettings); + DECLARE_ACTION(ResizePane); + DECLARE_ACTION(Find); + DECLARE_ACTION(MoveFocus); + DECLARE_ACTION(ToggleShaderEffects); + DECLARE_ACTION(ToggleFocusMode); + DECLARE_ACTION(ToggleFullscreen); + DECLARE_ACTION(ToggleAlwaysOnTop); + DECLARE_ACTION(ToggleCommandPalette); + DECLARE_ACTION(SetColorScheme); + DECLARE_ACTION(SetTabColor); + DECLARE_ACTION(OpenTabColorPicker); + DECLARE_ACTION(RenameTab); + DECLARE_ACTION(OpenTabRenamer); + DECLARE_ACTION(ExecuteCommandline); + DECLARE_ACTION(CloseOtherTabs); + DECLARE_ACTION(CloseTabsAfter); + DECLARE_ACTION(TabSearch); + DECLARE_ACTION(MoveTab); + DECLARE_ACTION(BreakIntoDebugger); + DECLARE_ACTION(FindMatch); + DECLARE_ACTION(TogglePaneReadOnly); + DECLARE_ACTION(NewWindow); + DECLARE_ACTION(IdentifyWindow); + DECLARE_ACTION(IdentifyWindows); // clang-format on private: diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl index 4a8b366b9..577c7097e 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +#define ACTION_EVENT(name) event Windows.Foundation.TypedEventHandler name + namespace TerminalApp { [default_interface] runtimeclass ShortcutActionDispatch { @@ -8,50 +10,53 @@ namespace TerminalApp Boolean DoAction(Microsoft.Terminal.Settings.Model.ActionAndArgs actionAndArgs); - event Windows.Foundation.TypedEventHandler CopyText; - event Windows.Foundation.TypedEventHandler PasteText; - event Windows.Foundation.TypedEventHandler NewTab; - event Windows.Foundation.TypedEventHandler OpenNewTabDropdown; - event Windows.Foundation.TypedEventHandler DuplicateTab; - event Windows.Foundation.TypedEventHandler CloseWindow; - event Windows.Foundation.TypedEventHandler CloseTab; - event Windows.Foundation.TypedEventHandler ClosePane; - event Windows.Foundation.TypedEventHandler SwitchToTab; - event Windows.Foundation.TypedEventHandler NextTab; - event Windows.Foundation.TypedEventHandler PrevTab; - event Windows.Foundation.TypedEventHandler SendInput; - event Windows.Foundation.TypedEventHandler SplitPane; - event Windows.Foundation.TypedEventHandler TogglePaneZoom; - event Windows.Foundation.TypedEventHandler AdjustFontSize; - event Windows.Foundation.TypedEventHandler ResetFontSize; - event Windows.Foundation.TypedEventHandler ScrollUp; - event Windows.Foundation.TypedEventHandler ScrollDown; - event Windows.Foundation.TypedEventHandler ScrollUpPage; - event Windows.Foundation.TypedEventHandler ScrollDownPage; - event Windows.Foundation.TypedEventHandler ScrollToTop; - event Windows.Foundation.TypedEventHandler ScrollToBottom; - event Windows.Foundation.TypedEventHandler OpenSettings; - event Windows.Foundation.TypedEventHandler ResizePane; - event Windows.Foundation.TypedEventHandler Find; - event Windows.Foundation.TypedEventHandler MoveFocus; - event Windows.Foundation.TypedEventHandler ToggleShaderEffects; - event Windows.Foundation.TypedEventHandler ToggleFocusMode; - event Windows.Foundation.TypedEventHandler ToggleFullscreen; - event Windows.Foundation.TypedEventHandler ToggleAlwaysOnTop; - event Windows.Foundation.TypedEventHandler ToggleCommandPalette; - event Windows.Foundation.TypedEventHandler SetColorScheme; - event Windows.Foundation.TypedEventHandler SetTabColor; - event Windows.Foundation.TypedEventHandler OpenTabColorPicker; - event Windows.Foundation.TypedEventHandler RenameTab; - event Windows.Foundation.TypedEventHandler OpenTabRenamer; - event Windows.Foundation.TypedEventHandler ExecuteCommandline; - event Windows.Foundation.TypedEventHandler CloseOtherTabs; - event Windows.Foundation.TypedEventHandler CloseTabsAfter; - event Windows.Foundation.TypedEventHandler TabSearch; - event Windows.Foundation.TypedEventHandler MoveTab; - event Windows.Foundation.TypedEventHandler BreakIntoDebugger; - event Windows.Foundation.TypedEventHandler FindMatch; - event Windows.Foundation.TypedEventHandler TogglePaneReadOnly; - event Windows.Foundation.TypedEventHandler NewWindow; + ACTION_EVENT(CopyText); + ACTION_EVENT(PasteText); + ACTION_EVENT(NewTab); + ACTION_EVENT(OpenNewTabDropdown); + ACTION_EVENT(DuplicateTab); + ACTION_EVENT(CloseWindow); + ACTION_EVENT(CloseTab); + ACTION_EVENT(ClosePane); + ACTION_EVENT(SwitchToTab); + ACTION_EVENT(NextTab); + ACTION_EVENT(PrevTab); + ACTION_EVENT(SendInput); + ACTION_EVENT(SplitPane); + ACTION_EVENT(TogglePaneZoom); + ACTION_EVENT(AdjustFontSize); + ACTION_EVENT(ResetFontSize); + ACTION_EVENT(ScrollUp); + ACTION_EVENT(ScrollDown); + ACTION_EVENT(ScrollUpPage); + ACTION_EVENT(ScrollDownPage); + ACTION_EVENT(ScrollToTop); + ACTION_EVENT(ScrollToBottom); + ACTION_EVENT(OpenSettings); + ACTION_EVENT(ResizePane); + ACTION_EVENT(Find); + ACTION_EVENT(MoveFocus); + ACTION_EVENT(ToggleShaderEffects); + ACTION_EVENT(ToggleFocusMode); + ACTION_EVENT(ToggleFullscreen); + ACTION_EVENT(ToggleAlwaysOnTop); + ACTION_EVENT(ToggleCommandPalette); + ACTION_EVENT(SetColorScheme); + ACTION_EVENT(SetTabColor); + ACTION_EVENT(OpenTabColorPicker); + ACTION_EVENT(RenameTab); + ACTION_EVENT(OpenTabRenamer); + ACTION_EVENT(ExecuteCommandline); + ACTION_EVENT(CloseOtherTabs); + ACTION_EVENT(CloseTabsAfter); + ACTION_EVENT(TabSearch); + ACTION_EVENT(MoveTab); + ACTION_EVENT(BreakIntoDebugger); + ACTION_EVENT(FindMatch); + ACTION_EVENT(TogglePaneReadOnly); + ACTION_EVENT(NewWindow); + ACTION_EVENT(IdentifyWindow); + ACTION_EVENT(IdentifyWindows); + } } diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 3afff5cd2..b185d9d84 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -140,6 +140,7 @@ AppLogic.idl + @@ -225,6 +226,8 @@ AppLogic.idl + + diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 31aaf09a3..7afd30ce9 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -30,6 +30,9 @@ using namespace winrt::Microsoft::Terminal::TerminalConnection; using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace ::TerminalApp; using namespace ::Microsoft::Console; +using namespace std::chrono_literals; + +#define HOOKUP_ACTION(action) _actionDispatch->action({ this, &TerminalPage::_Handle##action }); namespace winrt { @@ -225,7 +228,7 @@ namespace winrt::TerminalApp::implementation CommandPalette().RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) { if (CommandPalette().Visibility() == Visibility::Collapsed) { - _CommandPaletteClosed(nullptr, nullptr); + _FocusActiveControl(nullptr, nullptr); } }); CommandPalette().DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested }); @@ -246,6 +249,10 @@ namespace winrt::TerminalApp::implementation _isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop(); + // DON'T set up Toasts/TeachingTips here. They should be loaded and + // initialized the first time they're opened, in whatever method opens + // them. + // Setup mouse vanish attributes SystemParametersInfoW(SPI_GETMOUSEVANISH, 0, &_shouldMouseVanish, false); @@ -942,51 +949,53 @@ namespace winrt::TerminalApp::implementation // Hook up the ShortcutActionDispatch object's events to our handlers. // They should all be hooked up here, regardless of whether or not // there's an actual keychord for them. - _actionDispatch->OpenNewTabDropdown({ this, &TerminalPage::_HandleOpenNewTabDropdown }); - _actionDispatch->DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab }); - _actionDispatch->CloseTab({ this, &TerminalPage::_HandleCloseTab }); - _actionDispatch->ClosePane({ this, &TerminalPage::_HandleClosePane }); - _actionDispatch->CloseWindow({ this, &TerminalPage::_HandleCloseWindow }); - _actionDispatch->ScrollUp({ this, &TerminalPage::_HandleScrollUp }); - _actionDispatch->ScrollDown({ this, &TerminalPage::_HandleScrollDown }); - _actionDispatch->NextTab({ this, &TerminalPage::_HandleNextTab }); - _actionDispatch->PrevTab({ this, &TerminalPage::_HandlePrevTab }); - _actionDispatch->SendInput({ this, &TerminalPage::_HandleSendInput }); - _actionDispatch->SplitPane({ this, &TerminalPage::_HandleSplitPane }); - _actionDispatch->TogglePaneZoom({ this, &TerminalPage::_HandleTogglePaneZoom }); - _actionDispatch->ScrollUpPage({ this, &TerminalPage::_HandleScrollUpPage }); - _actionDispatch->ScrollDownPage({ this, &TerminalPage::_HandleScrollDownPage }); - _actionDispatch->ScrollToTop({ this, &TerminalPage::_HandleScrollToTop }); - _actionDispatch->ScrollToBottom({ this, &TerminalPage::_HandleScrollToBottom }); - _actionDispatch->OpenSettings({ this, &TerminalPage::_HandleOpenSettings }); - _actionDispatch->PasteText({ this, &TerminalPage::_HandlePasteText }); - _actionDispatch->NewTab({ this, &TerminalPage::_HandleNewTab }); - _actionDispatch->SwitchToTab({ this, &TerminalPage::_HandleSwitchToTab }); - _actionDispatch->ResizePane({ this, &TerminalPage::_HandleResizePane }); - _actionDispatch->MoveFocus({ this, &TerminalPage::_HandleMoveFocus }); - _actionDispatch->CopyText({ this, &TerminalPage::_HandleCopyText }); - _actionDispatch->AdjustFontSize({ this, &TerminalPage::_HandleAdjustFontSize }); - _actionDispatch->Find({ this, &TerminalPage::_HandleFind }); - _actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize }); - _actionDispatch->ToggleShaderEffects({ this, &TerminalPage::_HandleToggleShaderEffects }); - _actionDispatch->ToggleFocusMode({ this, &TerminalPage::_HandleToggleFocusMode }); - _actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen }); - _actionDispatch->ToggleAlwaysOnTop({ this, &TerminalPage::_HandleToggleAlwaysOnTop }); - _actionDispatch->ToggleCommandPalette({ this, &TerminalPage::_HandleToggleCommandPalette }); - _actionDispatch->SetColorScheme({ this, &TerminalPage::_HandleSetColorScheme }); - _actionDispatch->SetTabColor({ this, &TerminalPage::_HandleSetTabColor }); - _actionDispatch->OpenTabColorPicker({ this, &TerminalPage::_HandleOpenTabColorPicker }); - _actionDispatch->RenameTab({ this, &TerminalPage::_HandleRenameTab }); - _actionDispatch->OpenTabRenamer({ this, &TerminalPage::_HandleOpenTabRenamer }); - _actionDispatch->ExecuteCommandline({ this, &TerminalPage::_HandleExecuteCommandline }); - _actionDispatch->CloseOtherTabs({ this, &TerminalPage::_HandleCloseOtherTabs }); - _actionDispatch->CloseTabsAfter({ this, &TerminalPage::_HandleCloseTabsAfter }); - _actionDispatch->TabSearch({ this, &TerminalPage::_HandleOpenTabSearch }); - _actionDispatch->MoveTab({ this, &TerminalPage::_HandleMoveTab }); - _actionDispatch->BreakIntoDebugger({ this, &TerminalPage::_HandleBreakIntoDebugger }); - _actionDispatch->FindMatch({ this, &TerminalPage::_HandleFindMatch }); - _actionDispatch->TogglePaneReadOnly({ this, &TerminalPage::_HandleTogglePaneReadOnly }); - _actionDispatch->NewWindow({ this, &TerminalPage::_HandleNewWindow }); + HOOKUP_ACTION(OpenNewTabDropdown); + HOOKUP_ACTION(DuplicateTab); + HOOKUP_ACTION(CloseTab); + HOOKUP_ACTION(ClosePane); + HOOKUP_ACTION(CloseWindow); + HOOKUP_ACTION(ScrollUp); + HOOKUP_ACTION(ScrollDown); + HOOKUP_ACTION(NextTab); + HOOKUP_ACTION(PrevTab); + HOOKUP_ACTION(SendInput); + HOOKUP_ACTION(SplitPane); + HOOKUP_ACTION(TogglePaneZoom); + HOOKUP_ACTION(ScrollUpPage); + HOOKUP_ACTION(ScrollDownPage); + HOOKUP_ACTION(ScrollToTop); + HOOKUP_ACTION(ScrollToBottom); + HOOKUP_ACTION(OpenSettings); + HOOKUP_ACTION(PasteText); + HOOKUP_ACTION(NewTab); + HOOKUP_ACTION(SwitchToTab); + HOOKUP_ACTION(ResizePane); + HOOKUP_ACTION(MoveFocus); + HOOKUP_ACTION(CopyText); + HOOKUP_ACTION(AdjustFontSize); + HOOKUP_ACTION(Find); + HOOKUP_ACTION(ResetFontSize); + HOOKUP_ACTION(ToggleShaderEffects); + HOOKUP_ACTION(ToggleFocusMode); + HOOKUP_ACTION(ToggleFullscreen); + HOOKUP_ACTION(ToggleAlwaysOnTop); + HOOKUP_ACTION(ToggleCommandPalette); + HOOKUP_ACTION(SetColorScheme); + HOOKUP_ACTION(SetTabColor); + HOOKUP_ACTION(OpenTabColorPicker); + HOOKUP_ACTION(RenameTab); + HOOKUP_ACTION(OpenTabRenamer); + HOOKUP_ACTION(ExecuteCommandline); + HOOKUP_ACTION(CloseOtherTabs); + HOOKUP_ACTION(CloseTabsAfter); + HOOKUP_ACTION(TabSearch); + HOOKUP_ACTION(MoveTab); + HOOKUP_ACTION(BreakIntoDebugger); + HOOKUP_ACTION(FindMatch); + HOOKUP_ACTION(TogglePaneReadOnly); + HOOKUP_ACTION(NewWindow); + HOOKUP_ACTION(IdentifyWindow); + HOOKUP_ACTION(IdentifyWindows); } // Method Description: @@ -2275,8 +2284,8 @@ namespace winrt::TerminalApp::implementation return {}; } - void TerminalPage::_CommandPaletteClosed(const IInspectable& /*sender*/, - const RoutedEventArgs& /*eventArgs*/) + void TerminalPage::_FocusActiveControl(IInspectable /*sender*/, + IInspectable /*eventArgs*/) { _FocusCurrentTab(false); } @@ -2553,4 +2562,99 @@ namespace winrt::TerminalApp::implementation } } } + + // Method Description: + // - Display the name and ID of this window in a TeachingTip. If the window + // has no name, the name will be presented as "". + // - This can be invoked by either: + // * An identifyWindow action, that displays the info only for the current + // window + // * An identifyWindows action, that displays the info for all windows. + // Arguments: + // - + // Return Value: + // - + winrt::fire_and_forget TerminalPage::IdentifyWindow() + { + auto weakThis{ get_weak() }; + co_await winrt::resume_foreground(Dispatcher()); + if (auto page{ weakThis.get() }) + { + // If we haven't ever loaded the TeachingTip, then do so now and + // create the toast for it. + if (page->_windowIdToast == nullptr) + { + if (MUX::Controls::TeachingTip tip{ page->FindName(L"WindowIdToast").try_as() }) + { + page->_windowIdToast = std::make_shared(tip); + // Make sure to use the weak ref when setting up this + // callback. + tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl }); + } + } + + if (page->_windowIdToast != nullptr) + { + page->_windowIdToast->Open(); + } + } + } + + // WindowName is a otherwise generic WINRT_OBSERVABLE_PROPERTY, but it needs + // to raise a PropertyChanged for WindowNameForDisplay, instead of + // WindowName. + winrt::hstring TerminalPage::WindowName() const noexcept + { + return _WindowName; + } + void TerminalPage::WindowName(const winrt::hstring& value) + { + if (_WindowName != value) + { + _WindowName = value; + _PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" }); + } + } + + // WindowId is a otherwise generic WINRT_OBSERVABLE_PROPERTY, but it needs + // to raise a PropertyChanged for WindowIdForDisplay, instead of + // WindowId. + uint64_t TerminalPage::WindowId() const noexcept + { + return _WindowId; + } + void TerminalPage::WindowId(const uint64_t& value) + { + if (_WindowId != value) + { + _WindowId = value; + _PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowIdForDisplay" }); + } + } + + // Method Description: + // - Returns a label like "Window: 1234" for the ID of this window + // Arguments: + // - + // Return Value: + // - a string for displaying the name of the window. + winrt::hstring TerminalPage::WindowIdForDisplay() const noexcept + { + return winrt::hstring{ fmt::format(L"{}: {}", + std::wstring_view(RS_(L"WindowIdLabel")), + _WindowId) }; + } + + // Method Description: + // - Returns a label like "" when the window has no name, or the name of the window. + // Arguments: + // - + // Return Value: + // - a string for displaying the name of the window. + winrt::hstring TerminalPage::WindowNameForDisplay() const noexcept + { + return _WindowName.empty() ? + winrt::hstring{ fmt::format(L"<{}>", RS_(L"UnnamedWindowName")) } : + _WindowName; + } } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 13befdbf6..70814088b 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -7,6 +7,9 @@ #include "TerminalTab.h" #include "AppKeyBindings.h" #include "AppCommandlineArgs.h" +#include "Toast.h" + +#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); static constexpr uint32_t DefaultRowsToScroll{ 3 }; static constexpr std::wstring_view TabletInputServiceKey{ L"TabletInputService" }; @@ -78,10 +81,24 @@ namespace winrt::TerminalApp::implementation void ShowKeyboardServiceWarning(); winrt::hstring KeyboardServiceDisabledText(); + winrt::fire_and_forget IdentifyWindow(); + winrt::fire_and_forget ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial, const winrt::hstring cwd = L""); + // Normally, WindowName and WindowId would be + // WINRT_OBSERVABLE_PROPERTY's, but we want them to raise + // WindowNameForDisplay and WindowIdForDisplay instead + winrt::hstring WindowName() const noexcept; + void WindowName(const winrt::hstring& value); + uint64_t WindowId() const noexcept; + void WindowId(const uint64_t& value); + winrt::hstring WindowIdForDisplay() const noexcept; + winrt::hstring WindowNameForDisplay() const noexcept; + + WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); + // -------------------------------- WinRT Events --------------------------------- TYPED_EVENT(TitleChanged, IInspectable, winrt::hstring); TYPED_EVENT(LastTabClosed, IInspectable, winrt::TerminalApp::LastTabClosedEventArgs); @@ -92,6 +109,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(RaiseVisualBell, IInspectable, IInspectable); TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable); TYPED_EVENT(Initialized, IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs); + TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable); private: friend struct TerminalPageT; // for Xaml to bind events @@ -121,6 +139,8 @@ namespace winrt::TerminalApp::implementation bool _isInFocusMode{ false }; bool _isFullscreen{ false }; bool _isAlwaysOnTop{ false }; + winrt::hstring _WindowName{}; + uint64_t _WindowId{ 0 }; bool _rearranging; std::optional _rearrangeFrom; @@ -141,6 +161,8 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::Collections::IVector _startupActions; bool _shouldStartInboundListener{ false }; + std::shared_ptr _windowIdToast{ nullptr }; + void _ShowAboutDialog(); winrt::Windows::Foundation::IAsyncOperation _ShowCloseWarningDialog(); winrt::Windows::Foundation::IAsyncOperation _ShowCloseReadOnlyDialog(); @@ -267,7 +289,7 @@ namespace winrt::TerminalApp::implementation void _CompleteInitialization(); - void _CommandPaletteClosed(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs); + void _FocusActiveControl(IInspectable sender, IInspectable eventArgs); void _UnZoomIfNeeded(); @@ -287,56 +309,57 @@ namespace winrt::TerminalApp::implementation void _RestorePointerCursorHandler(const IInspectable& sender, const IInspectable& eventArgs); void _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection); + void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); #pragma region ActionHandlers // These are all defined in AppActionHandlers.cpp - void _HandleOpenNewTabDropdown(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleDuplicateTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleCloseTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleClosePane(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleScrollUp(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleScrollDown(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleNextTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandlePrevTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleSendInput(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleSplitPane(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleTogglePaneZoom(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleScrollUpPage(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleScrollDownPage(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleScrollToTop(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleScrollToBottom(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleOpenSettings(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandlePasteText(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleNewTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleSwitchToTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleResizePane(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleMoveFocus(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleCopyText(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleCloseWindow(const IInspectable&, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleAdjustFontSize(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleFind(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleResetFontSize(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleToggleShaderEffects(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleToggleFocusMode(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleToggleFullscreen(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleToggleAlwaysOnTop(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleSetColorScheme(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleSetTabColor(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleOpenTabColorPicker(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleRenameTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleOpenTabRenamer(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleExecuteCommandline(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleToggleCommandPalette(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleCloseOtherTabs(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleCloseTabsAfter(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleOpenTabSearch(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleMoveTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleBreakIntoDebugger(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleFindMatch(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleTogglePaneReadOnly(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleNewWindow(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); - + DECLARE_ACTION_HANDLER(OpenNewTabDropdown); + DECLARE_ACTION_HANDLER(DuplicateTab); + DECLARE_ACTION_HANDLER(CloseTab); + DECLARE_ACTION_HANDLER(ClosePane); + DECLARE_ACTION_HANDLER(ScrollUp); + DECLARE_ACTION_HANDLER(ScrollDown); + DECLARE_ACTION_HANDLER(NextTab); + DECLARE_ACTION_HANDLER(PrevTab); + DECLARE_ACTION_HANDLER(SendInput); + DECLARE_ACTION_HANDLER(SplitPane); + DECLARE_ACTION_HANDLER(TogglePaneZoom); + DECLARE_ACTION_HANDLER(ScrollUpPage); + DECLARE_ACTION_HANDLER(ScrollDownPage); + DECLARE_ACTION_HANDLER(ScrollToTop); + DECLARE_ACTION_HANDLER(ScrollToBottom); + DECLARE_ACTION_HANDLER(OpenSettings); + DECLARE_ACTION_HANDLER(PasteText); + DECLARE_ACTION_HANDLER(NewTab); + DECLARE_ACTION_HANDLER(SwitchToTab); + DECLARE_ACTION_HANDLER(ResizePane); + DECLARE_ACTION_HANDLER(MoveFocus); + DECLARE_ACTION_HANDLER(CopyText); + DECLARE_ACTION_HANDLER(CloseWindow); + DECLARE_ACTION_HANDLER(AdjustFontSize); + DECLARE_ACTION_HANDLER(Find); + DECLARE_ACTION_HANDLER(ResetFontSize); + DECLARE_ACTION_HANDLER(ToggleShaderEffects); + DECLARE_ACTION_HANDLER(ToggleFocusMode); + DECLARE_ACTION_HANDLER(ToggleFullscreen); + DECLARE_ACTION_HANDLER(ToggleAlwaysOnTop); + DECLARE_ACTION_HANDLER(SetColorScheme); + DECLARE_ACTION_HANDLER(SetTabColor); + DECLARE_ACTION_HANDLER(OpenTabColorPicker); + DECLARE_ACTION_HANDLER(RenameTab); + DECLARE_ACTION_HANDLER(OpenTabRenamer); + DECLARE_ACTION_HANDLER(ExecuteCommandline); + DECLARE_ACTION_HANDLER(ToggleCommandPalette); + DECLARE_ACTION_HANDLER(CloseOtherTabs); + DECLARE_ACTION_HANDLER(CloseTabsAfter); + DECLARE_ACTION_HANDLER(TabSearch); + DECLARE_ACTION_HANDLER(MoveTab); + DECLARE_ACTION_HANDLER(BreakIntoDebugger); + DECLARE_ACTION_HANDLER(FindMatch); + DECLARE_ACTION_HANDLER(TogglePaneReadOnly); + DECLARE_ACTION_HANDLER(NewWindow); + DECLARE_ACTION_HANDLER(IdentifyWindow); + DECLARE_ACTION_HANDLER(IdentifyWindows); // Make sure to hook new actions up in _RegisterActionCallbacks! #pragma endregion diff --git a/src/cascadia/TerminalApp/TerminalPage.idl b/src/cascadia/TerminalApp/TerminalPage.idl index b2580d158..d725d67ca 100644 --- a/src/cascadia/TerminalApp/TerminalPage.idl +++ b/src/cascadia/TerminalApp/TerminalPage.idl @@ -10,7 +10,7 @@ namespace TerminalApp Windows.Foundation.IAsyncOperation ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog); }; - [default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page + [default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged { TerminalPage(); @@ -22,6 +22,12 @@ namespace TerminalApp Boolean Fullscreen { get; }; Boolean AlwaysOnTop { get; }; + void IdentifyWindow(); + String WindowName; + UInt64 WindowId; + String WindowNameForDisplay { get; }; + String WindowIdForDisplay { get; }; + // We cannot use the default XAML APIs because we want to make sure // that there's only one application-global dialog visible at a time, // and because of GH#5224. @@ -40,5 +46,6 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler AlwaysOnTopChanged; event Windows.Foundation.TypedEventHandler Initialized; event Windows.Foundation.TypedEventHandler SetTaskbarProgress; + event Windows.Foundation.TypedEventHandler IdentifyWindowsRequested; } } diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index f234b8b1b..20bed6717 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -116,5 +116,16 @@ IsOpen="False" Message="{x:Bind KeyboardServiceDisabledText, Mode=OneWay}" Severity="Warning" /> + + + diff --git a/src/cascadia/TerminalApp/Toast.cpp b/src/cascadia/TerminalApp/Toast.cpp new file mode 100644 index 000000000..d9ea845ca --- /dev/null +++ b/src/cascadia/TerminalApp/Toast.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" + +#include "Toast.h" + +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::UI::Core; +using namespace winrt::Windows::UI::Xaml; + +constexpr const auto ToastDuration = std::chrono::milliseconds(3000); + +Toast::Toast(const winrt::Microsoft::UI::Xaml::Controls::TeachingTip& tip) : + _tip{ tip } +{ + _timer.Interval(ToastDuration); +} + +// Method Description: +// - Open() the TeachingTip, and start our timer. When the timer expires, the +// tip will be closed. +// Arguments: +// - +// Return Value: +// - +void Toast::Open() +{ + _tip.IsOpen(true); + + std::weak_ptr weakThis{ shared_from_this() }; + _timer.Tick([weakThis](auto&&...) { + if (auto self{ weakThis.lock() }) + { + self->_timer.Stop(); + self->_tip.IsOpen(false); + } + }); + _timer.Start(); +} diff --git a/src/cascadia/TerminalApp/Toast.h b/src/cascadia/TerminalApp/Toast.h new file mode 100644 index 000000000..40d3df7cf --- /dev/null +++ b/src/cascadia/TerminalApp/Toast.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- Toast.h + +Module Description: +- This is a helper class for wrapping a TeachingTip with a timer to + automatically dismiss it. Callers should add the TeachingTip wherever they'd + like in the UI tree, then wrap that TeachingTip in a toast like so: + +``` +std::unique_ptr myToast = std::make_unique(MyTeachingTip()); +``` +- Then, you can show the TeachingTip with + +``` +myToast->Open(); +``` + + which will open the tip and close it after a brief timeout. + +--*/ + +#pragma once +#include "pch.h" + +class Toast : public std::enable_shared_from_this +{ +public: + Toast(const winrt::Microsoft::UI::Xaml::Controls::TeachingTip& tip); + void Open(); + +private: + winrt::Microsoft::UI::Xaml::Controls::TeachingTip _tip; + winrt::Windows::UI::Xaml::DispatcherTimer _timer; +}; diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index e1c5fa6de..de6e65453 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -53,6 +53,8 @@ static constexpr std::string_view BreakIntoDebuggerKey{ "breakIntoDebugger" }; static constexpr std::string_view FindMatchKey{ "findMatch" }; static constexpr std::string_view TogglePaneReadOnlyKey{ "toggleReadOnlyMode" }; static constexpr std::string_view NewWindowKey{ "newWindow" }; +static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" }; +static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" }; static constexpr std::string_view ActionKey{ "action" }; @@ -119,6 +121,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { FindMatchKey, ShortcutAction::FindMatch }, { TogglePaneReadOnlyKey, ShortcutAction::TogglePaneReadOnly }, { NewWindowKey, ShortcutAction::NewWindow }, + { IdentifyWindowKey, ShortcutAction::IdentifyWindow }, + { IdentifyWindowsKey, ShortcutAction::IdentifyWindows }, }; using ParseResult = std::tuple>; @@ -324,6 +328,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::FindMatch, L"" }, // Intentionally omitted, must be generated by GenerateName { ShortcutAction::TogglePaneReadOnly, RS_(L"TogglePaneReadOnlyCommandKey") }, { ShortcutAction::NewWindow, RS_(L"NewWindowCommandKey") }, + { ShortcutAction::IdentifyWindow, RS_(L"IdentifyWindowCommandKey") }, + { ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") }, }; }(); diff --git a/src/cascadia/TerminalSettingsModel/KeyMapping.idl b/src/cascadia/TerminalSettingsModel/KeyMapping.idl index 41fb1e4e3..a6669c6b5 100644 --- a/src/cascadia/TerminalSettingsModel/KeyMapping.idl +++ b/src/cascadia/TerminalSettingsModel/KeyMapping.idl @@ -54,7 +54,9 @@ namespace Microsoft.Terminal.Settings.Model BreakIntoDebugger, TogglePaneReadOnly, FindMatch, - NewWindow + NewWindow, + IdentifyWindow, + IdentifyWindows }; [default_interface] runtimeclass ActionAndArgs { diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index f8a588553..65ca12e9d 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -244,6 +244,12 @@ New window + + Identify window + + + Identify windows + Next tab diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 3bc56c560..be855b333 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -296,6 +296,8 @@ { "command": "openTabRenamer" }, { "command": "commandPalette", "keys":"ctrl+shift+p" }, + { "command": "identifyWindow" }, + // Tab Management // "command": "closeTab" is unbound by default. // The closeTab command closes a tab without confirmation, even if it has multiple panes. diff --git a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp index 5523d64b1..d8ea2921b 100644 --- a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp +++ b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp @@ -55,10 +55,14 @@ namespace RemotingUnitTests uint64_t GetPID() { throw winrt::hresult_error{}; }; bool ExecuteCommandline(const Remoting::CommandlineArgs& /*args*/) { throw winrt::hresult_error{}; } void ActivateWindow(const Remoting::WindowActivatedArgs& /*args*/) { throw winrt::hresult_error{}; } + void RequestIdentifyWindows() { throw winrt::hresult_error{}; }; + void DisplayWindowId() { throw winrt::hresult_error{}; }; Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; } Remoting::WindowActivatedArgs GetLastActivatedArgs() { throw winrt::hresult_error{}; } TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs); TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs); + TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); }; class RemotingTests diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 93283c70c..a39a0ad66 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -194,6 +194,11 @@ void AppHost::_HandleCommandlineArgs() // commandline (in the future), it'll trigger this callback, that we'll // use to send the actions to the app. peasant.ExecuteCommandlineRequested({ this, &AppHost::_DispatchCommandline }); + + peasant.DisplayWindowIdRequested({ this, &AppHost::_DisplayWindowId }); + + _logic.WindowName(peasant.WindowName()); + _logic.WindowId(peasant.GetID()); } } @@ -244,6 +249,7 @@ void AppHost::Initialize() _logic.TitleChanged({ this, &AppHost::AppTitleChanged }); _logic.LastTabClosed({ this, &AppHost::LastTabClosed }); _logic.SetTaskbarProgress({ this, &AppHost::SetTaskbarProgress }); + _logic.IdentifyWindowsRequested({ this, &AppHost::_IdentifyWindowsRequested }); _window->UpdateTitle(_logic.Title()); @@ -603,3 +609,37 @@ GUID AppHost::_CurrentDesktopGuid() CATCH_LOG(); return currentDesktopGuid; } + +// Method Description: +// - Called when this window wants _all_ windows to display their +// identification. We'll hop to the BG thread, and raise an event (eventually +// handled by the monarch) to bubble this request to all the Terminal windows. +// Arguments: +// - +// Return Value: +// - +winrt::fire_and_forget AppHost::_IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) +{ + // We'll be raising an event that may result in a RPC call to the monarch - + // make sure we're on the background thread, or this will silently fail + co_await winrt::resume_background(); + + if (auto peasant{ _windowManager.CurrentWindow() }) + { + peasant.RequestIdentifyWindows(); + } +} + +// Method Description: +// - Called when the monarch wants us to display our window ID. We'll call down +// to the app layer to display the toast. +// Arguments: +// - +// Return Value: +// - +void AppHost::_DisplayWindowId(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) +{ + _logic.IdentifyWindow(); +} diff --git a/src/cascadia/WindowsTerminal/AppHost.h b/src/cascadia/WindowsTerminal/AppHost.h index c8782d61e..723a46048 100644 --- a/src/cascadia/WindowsTerminal/AppHost.h +++ b/src/cascadia/WindowsTerminal/AppHost.h @@ -51,5 +51,9 @@ private: void _FindTargetWindow(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args); + winrt::fire_and_forget _IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); + void _DisplayWindowId(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); GUID _CurrentDesktopGuid(); }; diff --git a/tools/GenerateHeaderForJson.ps1 b/tools/GenerateHeaderForJson.ps1 index 2510951f1..1116275e0 100644 --- a/tools/GenerateHeaderForJson.ps1 +++ b/tools/GenerateHeaderForJson.ps1 @@ -22,7 +22,14 @@ Write-Output "// THIS IS AN AUTO-GENERATED FILE" | Out-File -FilePath $OutPath - Write-Output "// Generated from " | Out-File -FilePath $OutPath -Encoding ASCII -Append -NoNewline $fullPath = Resolve-Path -Path $JsonFile Write-Output $fullPath.Path | Out-File -FilePath $OutPath -Encoding ASCII -Append -Write-Output "constexpr std::string_view $($VariableName){ R`"(" | Out-File -FilePath $OutPath -Encoding ASCII -Append -NoNewline -Write-Output $jsonData | Out-File -FilePath $OutPath -Encoding ASCII -Append -Write-Output ")`" };" | Out-File -FilePath $OutPath -Encoding ASCII -Append +Write-Output "constexpr std::string_view $($VariableName){ " | Out-File -FilePath $OutPath -Encoding ASCII -Append + +# Write each line escaped on its own, as it's own literal. This file is _very +# big_, so big that it cannot fit in a single string literal :O The compiler is, +# however, smart enough to just concatenate all these literals into one big +# string. +$jsonData | foreach { + Write-Output "R`"($_`n)`"" | Out-File -FilePath $OutPath -Encoding ASCII -Append +} +Write-Output "};" | Out-File -FilePath $OutPath -Encoding ASCII -Append