diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 5b9dacdba67..27202a114e0 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1316,12 +1316,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation ::Search search(*GetUiaData(), text.c_str(), direction, sensitivity); auto lock = _terminal->LockForWriting(); - if (search.FindNext()) + const bool foundMatch{ search.FindNext() }; + if (foundMatch) { _terminal->SetBlockSelection(false); search.Select(); _renderer->TriggerSelection(); } + + // Raise a FoundMatch event, which the control will use to notify + // narrator if there was any results in the buffer + auto foundResults = winrt::make_self(foundMatch); + _FoundMatchHandlers(*this, *foundResults); } // Method Description: diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 4b4b5b2d5a7..2a86c2585cd 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -191,6 +191,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs); TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs); TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable); + TYPED_EVENT(FoundMatch, IInspectable, Control::FoundResultsArgs); // clang-format on private: diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl index ee270096c4e..a8b3e14234d 100644 --- a/src/cascadia/TerminalControl/ControlCore.idl +++ b/src/cascadia/TerminalControl/ControlCore.idl @@ -119,6 +119,7 @@ namespace Microsoft.Terminal.Control event Windows.Foundation.TypedEventHandler RaiseNotice; event Windows.Foundation.TypedEventHandler TransparencyChanged; event Windows.Foundation.TypedEventHandler ReceivedOutput; + event Windows.Foundation.TypedEventHandler FoundMatch; }; } diff --git a/src/cascadia/TerminalControl/EventArgs.cpp b/src/cascadia/TerminalControl/EventArgs.cpp index f4b4d9bc786..28417c4eb33 100644 --- a/src/cascadia/TerminalControl/EventArgs.cpp +++ b/src/cascadia/TerminalControl/EventArgs.cpp @@ -11,3 +11,4 @@ #include "ScrollPositionChangedArgs.g.cpp" #include "RendererWarningArgs.g.cpp" #include "TransparencyChangedEventArgs.g.cpp" +#include "FoundResultsArgs.g.cpp" diff --git a/src/cascadia/TerminalControl/EventArgs.h b/src/cascadia/TerminalControl/EventArgs.h index 9f76c061cb3..0b9e80b0882 100644 --- a/src/cascadia/TerminalControl/EventArgs.h +++ b/src/cascadia/TerminalControl/EventArgs.h @@ -11,6 +11,7 @@ #include "ScrollPositionChangedArgs.g.h" #include "RendererWarningArgs.g.h" #include "TransparencyChangedEventArgs.g.h" +#include "FoundResultsArgs.g.h" namespace winrt::Microsoft::Terminal::Control::implementation { @@ -133,4 +134,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation WINRT_PROPERTY(double, Opacity); }; + + struct FoundResultsArgs : public FoundResultsArgsT + { + public: + FoundResultsArgs(const bool foundMatch) : + _FoundMatch(foundMatch) + { + } + + WINRT_PROPERTY(bool, FoundMatch); + }; } diff --git a/src/cascadia/TerminalControl/EventArgs.idl b/src/cascadia/TerminalControl/EventArgs.idl index f81a4153ba5..377c6535cf4 100644 --- a/src/cascadia/TerminalControl/EventArgs.idl +++ b/src/cascadia/TerminalControl/EventArgs.idl @@ -68,4 +68,10 @@ namespace Microsoft.Terminal.Control { Double Opacity { get; }; } + + + runtimeclass FoundResultsArgs + { + Boolean FoundMatch { get; }; + } } diff --git a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw index f2fde4b9dc5..4c17742c1ce 100644 --- a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw @@ -200,4 +200,12 @@ Please either install the missing font or choose another one. Read-only mode is enabled. + + Results found + Announced to a screen reader when the user searches for some text and there are matches for that text in the terminal. + + + No results found + Announced to a screen reader when the user searches for some text and there are no matches for that text in the terminal. + diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 0d934394c82..cf415b000c9 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -82,6 +82,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged }); _core.RaiseNotice({ this, &TermControl::_coreRaisedNotice }); _core.HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged }); + _core.FoundMatch({ this, &TermControl::_coreFoundMatch }); _interactivity.OpenHyperlink({ this, &TermControl::_HyperlinkHandler }); _interactivity.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged }); @@ -2747,4 +2748,28 @@ namespace winrt::Microsoft::Terminal::Control::implementation { return _core.Opacity(); } + + // Method Description: + // - Called when the core raises a FoundMatch event. That's done in response + // to us starting a search query with ControlCore::Search. + // - The args will tell us if there were or were not any results for that + // particular search. We'll use that to control what to announce to + // Narrator. When we have more elaborate search information to report, we + // may want to report that here. (see GH #3920) + // Arguments: + // - args: contains information about the results that were or were not found. + // Return Value: + // - + void TermControl::_coreFoundMatch(const IInspectable& /*sender*/, const Control::FoundResultsArgs& args) + { + if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this) }) + { + automationPeer.RaiseNotificationEvent( + Automation::Peers::AutomationNotificationKind::ActionCompleted, + Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent, + args.FoundMatch() ? RS_(L"SearchBox_MatchesAvailable") : RS_(L"SearchBox_NoMatches"), // what to announce if results were found + L"SearchBoxResultAnnouncement" /* unique name for this group of notifications */); + } + } + } diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 89d31889a5d..95aa82cdb92 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -275,6 +275,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args); void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args); void _coreWarningBell(const IInspectable& sender, const IInspectable& args); + void _coreFoundMatch(const IInspectable& sender, const Control::FoundResultsArgs& args); }; }