diff --git a/doc/cascadia/SettingsSchema.md b/doc/cascadia/SettingsSchema.md index dee8307d..a7c8731c 100644 --- a/doc/cascadia/SettingsSchema.md +++ b/doc/cascadia/SettingsSchema.md @@ -137,7 +137,8 @@ Commands listed below are per the implementation in [`src/cascadia/TerminalApp/A - moveFocusRight - moveFocusUp - moveFocusDown -- toggleFullscreen +- toggleFullscreen +- find ## Example Keys - ctrl+1 diff --git a/src/buffer/out/search.cpp b/src/buffer/out/search.cpp index 67f85540..2b662fef 100644 --- a/src/buffer/out/search.cpp +++ b/src/buffer/out/search.cpp @@ -97,11 +97,7 @@ bool Search::FindNext() // - Takes the found word and selects it in the screen buffer void Search::Select() const { - // Only select if we've found something. - if (_coordSelStart != _coordSelEnd) - { - _uiaData.SelectNewRegion(_coordSelStart, _coordSelEnd); - } + _uiaData.SelectNewRegion(_coordSelStart, _coordSelEnd); } // Routine Description: @@ -142,6 +138,7 @@ std::pair Search::GetFoundLocation() const noexcept COORD Search::s_GetInitialAnchor(IUiaData& uiaData, const Direction direction) { const auto& textBuffer = uiaData.GetTextBuffer(); + const COORD textBufferEndPosition = uiaData.GetTextBufferEndPosition(); if (uiaData.IsSelectionActive()) { auto anchor = uiaData.GetSelectionAnchor(); @@ -152,6 +149,10 @@ COORD Search::s_GetInitialAnchor(IUiaData& uiaData, const Direction direction) else { textBuffer.GetSize().DecrementInBoundsCircular(anchor); + // If the selection starts at (0, 0), we need to make sure + // it does not exceed the text buffer end position + anchor.X = std::min(textBufferEndPosition.X, anchor.X); + anchor.Y = std::min(textBufferEndPosition.Y, anchor.Y); } return anchor; } @@ -163,8 +164,7 @@ COORD Search::s_GetInitialAnchor(IUiaData& uiaData, const Direction direction) } else { - const auto bufferSize = textBuffer.GetSize().Dimensions(); - return { bufferSize.X - 1, bufferSize.Y - 1 }; + return textBufferEndPosition; } } } @@ -293,6 +293,26 @@ void Search::_UpdateNextPosition() { THROW_HR(E_NOTIMPL); } + + // To reduce wrap-around time, if the next position is larger than + // the end position of the written text + // We put the next position to: + // Forward: (0, 0) + // Backward: the position of the end of the text buffer + const COORD bufferEndPosition = _uiaData.GetTextBufferEndPosition(); + + if (_coordNext.Y > bufferEndPosition.Y || + (_coordNext.Y == bufferEndPosition.Y && _coordNext.X > bufferEndPosition.X)) + { + if (_direction == Direction::Forward) + { + _coordNext = { 0 }; + } + else + { + _coordNext = bufferEndPosition; + } + } } // Routine Description: diff --git a/src/buffer/out/search.h b/src/buffer/out/search.h index 928111c0..3822e3ff 100644 --- a/src/buffer/out/search.h +++ b/src/buffer/out/search.h @@ -59,7 +59,7 @@ class Search final private: wchar_t _ApplySensitivity(const wchar_t wch) const noexcept; - bool Search::_FindNeedleInHaystackAt(const COORD pos, COORD& start, COORD& end) const; + bool _FindNeedleInHaystackAt(const COORD pos, COORD& start, COORD& end) const; bool _CompareChars(const std::wstring_view one, const std::wstring_view two) const noexcept; void _UpdateNextPosition(); diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 68a29622..2c4b132d 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -214,6 +214,13 @@ namespace winrt::TerminalApp::implementation } } + void TerminalPage::_HandleFind(const IInspectable& /*sender*/, + const TerminalApp::ActionEventArgs& args) + { + _Find(); + args.Handled(true); + } + void TerminalPage::_HandleResetFontSize(const IInspectable& /*sender*/, const TerminalApp::ActionEventArgs& args) { @@ -228,5 +235,4 @@ namespace winrt::TerminalApp::implementation _ToggleFullscreen(); args.Handled(true); } - } diff --git a/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp b/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp index 26dc7f27..8cec9a55 100644 --- a/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp +++ b/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp @@ -77,6 +77,7 @@ static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" }; // Legacy static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" }; // Legacy static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" }; // Legacy static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" }; // Legacy +static constexpr std::string_view FindKey{ "find" }; static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" }; // Specifically use a map here over an unordered_map. We want to be able to @@ -142,6 +143,7 @@ static const std::map> commandName { ToggleFullscreenKey, ShortcutAction::ToggleFullscreen }, { SplitPaneKey, ShortcutAction::SplitPane }, { UnboundKey, ShortcutAction::Invalid }, + { FindKey, ShortcutAction::Find }, }; // Function Description: diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp index cf845c2c..bac26872 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp @@ -180,6 +180,11 @@ namespace winrt::TerminalApp::implementation _AdjustFontSizeHandlers(*this, *eventArgs); break; } + case ShortcutAction::Find: + { + _FindHandlers(*this, *eventArgs); + break; + } case ShortcutAction::ResetFontSize: { _ResetFontSizeHandlers(*this, *eventArgs); diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.h b/src/cascadia/TerminalApp/ShortcutActionDispatch.h index bb2b72e5..f7e7ce05 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.h +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.h @@ -44,6 +44,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); + TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); // clang-format on diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl index 01a065e6..6df2d58b 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl @@ -61,6 +61,7 @@ namespace TerminalApp MoveFocusRight, // Legacy MoveFocusUp, // Legacy MoveFocusDown, // Legacy + Find, ToggleFullscreen, OpenSettings }; @@ -97,6 +98,7 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler ScrollDownPage; event Windows.Foundation.TypedEventHandler OpenSettings; event Windows.Foundation.TypedEventHandler ResizePane; + event Windows.Foundation.TypedEventHandler Find; event Windows.Foundation.TypedEventHandler MoveFocus; event Windows.Foundation.TypedEventHandler ToggleFullscreen; } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index dbc15059..52fe18f3 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -630,7 +630,6 @@ 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 }); @@ -651,6 +650,7 @@ namespace winrt::TerminalApp::implementation _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->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen }); } @@ -1417,6 +1417,20 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - Called when the user tries to do a search using keybindings. + // This will tell the current focused terminal control to create + // a search box and enable find process. + // Arguments: + // - + // Return Value: + // - + void TerminalPage::_Find() + { + const auto termControl = _GetActiveControl(); + termControl.CreateSearchBoxControl(); + } + // Method Description: // - Toggles fullscreen mode. Hides the tab row, and raises our // ToggleFullscreen event. diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 11467e9f..56beac28 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -122,6 +122,8 @@ namespace winrt::TerminalApp::implementation void _OnContentSizeChanged(const IInspectable& /*sender*/, Windows::UI::Xaml::SizeChangedEventArgs const& e); void _OnTabCloseRequested(const IInspectable& sender, const Microsoft::UI::Xaml::Controls::TabViewTabCloseRequestedEventArgs& eventArgs); + void _Find(); + void _RefreshUIForSettingsReload(); void _ToggleFullscreen(); @@ -148,6 +150,7 @@ namespace winrt::TerminalApp::implementation void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleCloseWindow(const IInspectable&, const TerminalApp::ActionEventArgs& args); void _HandleAdjustFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); + void _HandleFind(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleResetFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleToggleFullscreen(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); #pragma endregion diff --git a/src/cascadia/TerminalApp/defaults.json b/src/cascadia/TerminalApp/defaults.json index c3a311c0..569bcd23 100644 --- a/src/cascadia/TerminalApp/defaults.json +++ b/src/cascadia/TerminalApp/defaults.json @@ -245,6 +245,7 @@ { "command": { "action": "switchToTab", "index": 6 }, "keys": ["ctrl+alt+7"] }, { "command": { "action": "switchToTab", "index": 7 }, "keys": ["ctrl+alt+8"] }, { "command": { "action": "switchToTab", "index": 8 }, "keys": ["ctrl+alt+9"] }, + { "command": "find", "keys": [ "ctrl+shift+f" ] }, { "command": "toggleFullscreen", "keys": [ "alt+enter" ] }, { "command": "toggleFullscreen", "keys": [ "f11" ] } ] diff --git a/src/cascadia/TerminalControl/SearchBoxControl.cpp b/src/cascadia/TerminalControl/SearchBoxControl.cpp new file mode 100644 index 00000000..7f5e7a0c --- /dev/null +++ b/src/cascadia/TerminalControl/SearchBoxControl.cpp @@ -0,0 +1,186 @@ +// Copyright (c) Microsoft Corporation +// Licensed under the MIT license. + +#include "pch.h" +#include "SearchBoxControl.h" +#include "SearchBoxControl.g.cpp" + +using namespace winrt; +using namespace winrt::Windows::UI::Xaml; +using namespace winrt::Windows::UI::Core; + +namespace winrt::Microsoft::Terminal::TerminalControl::implementation +{ + // Constructor + SearchBoxControl::SearchBoxControl() : + _goForward(false) + { + InitializeComponent(); + + this->CharacterReceived({ this, &SearchBoxControl::_CharacterHandler }); + + _textBox = TextBox(); + + if (_textBox) + _focusableElements.insert(_textBox); + _focusableElements.insert(CloseButton()); + _focusableElements.insert(CaseSensitivityButton()); + _focusableElements.insert(GoForwardButton()); + _focusableElements.insert(GoBackwardButton()); + } + + // Method Description: + // - Getter for _goForward + // Arguments: + // - + // Return Value: + // - bool: the value of _goForward + bool SearchBoxControl::GoForward() + { + return _goForward; + } + + // Method Description: + // - Get the current state of the case button + // Arguments: + // - + // Return Value: + // - bool: whether the case button is checked (sensitive) + // or not + bool SearchBoxControl::IsCaseSensitive() + { + return _caseButton.IsChecked().GetBoolean(); + } + + // Method Description: + // - Handler for pressing Enter on TextBox, trigger + // text search + // Arguments: + // - sender: not used + // - e: event data + // Return Value: + // - + void SearchBoxControl::TextBoxKeyDown(winrt::Windows::Foundation::IInspectable const& /*sender*/, Input::KeyRoutedEventArgs const& e) + { + if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Enter) + { + auto const state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift); + if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down)) + { + // We do not want the direction flag to change permanately + _goForward = !_goForward; + _SearchHandlers(*this, _textBox.Text()); + _goForward = !_goForward; + } + else + { + _SearchHandlers(*this, _textBox.Text()); + } + e.Handled(true); + } + } + + // Method Description: + // - Handler for pressing Enter on TextBox, trigger + // text search + // Arguments: + // - + // Return Value: + // - + void SearchBoxControl::SetFocusOnTextbox() + { + if (_textBox) + { + Input::FocusManager::TryFocusAsync(_textBox, FocusState::Keyboard); + _textBox.SelectAll(); + } + } + + // Method Description: + // - Check if the current focus is on any element within the + // search box + // Arguments: + // - + // Return Value: + // - bool: whether the current focus is on the search box + bool SearchBoxControl::ContainsFocus() + { + auto focusedElement = Input::FocusManager::GetFocusedElement(this->XamlRoot()); + if (_focusableElements.count(focusedElement) > 0) + { + return true; + } + + return false; + } + + // Method Description: + // - Handler for clicking the GoBackward button. This change the value of _goForward, + // mark GoBackward button as checked and ensure GoForward button + // is not checked + // Arguments: + // - sender: not used + // - e: not used + // Return Value: + // - + void SearchBoxControl::GoBackwardClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/) + { + _goForward = false; + GoBackwardButton().IsChecked(true); + if (GoForwardButton().IsChecked()) + { + GoForwardButton().IsChecked(false); + } + + // kick off search + _SearchHandlers(*this, _textBox.Text()); + } + + // Method Description: + // - Handler for clicking the GoForward button. This change the value of _goForward, + // mark GoForward button as checked and ensure GoBackward button + // is not checked + // Arguments: + // - sender: not used + // - e: not used + // Return Value: + // - + void SearchBoxControl::GoForwardClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/) + { + _goForward = true; + GoForwardButton().IsChecked(true); + if (GoBackwardButton().IsChecked()) + { + GoBackwardButton().IsChecked(false); + } + + // kick off search + _SearchHandlers(*this, _textBox.Text()); + } + + // Method Description: + // - Handler for clicking the close button. This destructs the + // search box object in TermControl + // Arguments: + // - sender: not used + // - e: event data + // Return Value: + // - + void SearchBoxControl::CloseClick(winrt::Windows::Foundation::IInspectable const& /*sender*/, RoutedEventArgs const& e) + { + _ClosedHandlers(*this, e); + } + + // Method Description: + // - To avoid Characters input bubbling up to terminal, we implement this handler here, + // simply mark the key input as handled + // Arguments: + // - sender: not used + // - e: event data + // Return Value: + // - + void SearchBoxControl::_CharacterHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/, Input::CharacterReceivedRoutedEventArgs const& e) + { + e.Handled(true); + } +} diff --git a/src/cascadia/TerminalControl/SearchBoxControl.h b/src/cascadia/TerminalControl/SearchBoxControl.h new file mode 100644 index 00000000..cb1aeb17 --- /dev/null +++ b/src/cascadia/TerminalControl/SearchBoxControl.h @@ -0,0 +1,63 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- SearchBoxControl.cpp + +Abstract: +- the search dialog component used in Terminal Search + +Author(s): +- Kaiyu Wang (kawa) 11-27-2019 + +--*/ + +#pragma once +#include "winrt/Windows.UI.Xaml.h" +#include "winrt/Windows.UI.Xaml.Controls.h" +#include "../../cascadia/inc/cppwinrt_utils.h" + +#include "SearchBoxControl.g.h" + +namespace winrt::Microsoft::Terminal::TerminalControl::implementation +{ + struct SearchBoxControl : SearchBoxControlT + { + SearchBoxControl(); + + void TextBoxKeyDown(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e); + + bool GoForward(); + bool IsCaseSensitive(); + + void SetFocusOnTextbox(); + bool ContainsFocus(); + + void GoBackwardClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/); + void GoForwardClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/); + void CloseClick(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); + + TYPED_EVENT(Search, TerminalControl::SearchBoxControl, winrt::hstring); + TYPED_EVENT(Closed, TerminalControl::SearchBoxControl, Windows::UI::Xaml::RoutedEventArgs); + + private: + bool _goForward; // The direction of the search, controlled by the buttons with arrows + + winrt::Windows::UI::Xaml::Controls::Primitives::ToggleButton _goForwardButton; + winrt::Windows::UI::Xaml::Controls::Primitives::ToggleButton _goBackwardButton; + winrt::Windows::UI::Xaml::Controls::Primitives::ToggleButton _caseButton; + winrt::Windows::UI::Xaml::Controls::TextBox _textBox; + + std::unordered_set _focusableElements; + + void _CharacterHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Input::CharacterReceivedRoutedEventArgs const& e); + }; +} + +namespace winrt::Microsoft::Terminal::TerminalControl::factory_implementation +{ + struct SearchBoxControl : SearchBoxControlT + { + }; +} diff --git a/src/cascadia/TerminalControl/SearchBoxControl.idl b/src/cascadia/TerminalControl/SearchBoxControl.idl new file mode 100644 index 00000000..dfe517ad --- /dev/null +++ b/src/cascadia/TerminalControl/SearchBoxControl.idl @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +namespace Microsoft.Terminal.TerminalControl +{ + [default_interface] runtimeclass SearchBoxControl : Windows.UI.Xaml.Controls.UserControl + { + SearchBoxControl(); + Boolean GoForward { get; }; + Boolean IsCaseSensitive { get; }; + void SetFocusOnTextbox(); + Boolean ContainsFocus(); + + event Windows.Foundation.TypedEventHandler Search; + event Windows.Foundation.TypedEventHandler Closed; + } +} diff --git a/src/cascadia/TerminalControl/SearchBoxControl.xaml b/src/cascadia/TerminalControl/SearchBoxControl.xaml new file mode 100644 index 00000000..1981759e --- /dev/null +++ b/src/cascadia/TerminalControl/SearchBoxControl.xaml @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index a8692593..3e9d5486 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -66,6 +66,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation _cursorTimer{}, _lastMouseClick{}, _lastMouseClickPos{}, + _searchBox{ nullptr }, _tsfInputControl{ nullptr } { _EnsureStaticInitialization(); @@ -163,6 +164,101 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation }); } + // Method Description: + // - Create the SearchBoxControl object, and attach it + // to the Terminal Control root + // Arguments: + // - + // Return Value: + // - + void TermControl::CreateSearchBoxControl() + { + if (!_searchBox) + { + _searchBox = winrt::make_self(); + _searchBox->HorizontalAlignment(HorizontalAlignment::Right); + _searchBox->VerticalAlignment(VerticalAlignment::Top); + // We need to make sure the searchbox does not overlap + // with the scroll bar + Thickness searchBoxPadding = { 0, 0, _scrollBar.ActualWidth(), 0 }; + _searchBox->Margin(searchBoxPadding); + + _root.Children().Append(*_searchBox); + + // Event handlers + _searchBox->Search({ get_weak(), &TermControl::_Search }); + _searchBox->Closed({ get_weak(), &TermControl::_CloseSearchBoxControl }); + } + + _searchBox->SetFocusOnTextbox(); + } + + // Method Description: + // - Search text in text buffer. This is triggered if the user click + // search button or press enter. + // Arguments: + // - IInspectable: not used + // - text: the text to search + // Return Value: + // - + void TermControl::_Search(const winrt::Windows::Foundation::IInspectable&, const winrt::hstring& text) + { + if (text.size() == 0) + { + return; + } + + const Search::Direction direction = _searchBox->GoForward() ? + Search::Direction::Forward : + Search::Direction::Backward; + + const Search::Sensitivity sensitivity = _searchBox->IsCaseSensitive() ? + Search::Sensitivity::CaseSensitive : + Search::Sensitivity::CaseInsensitive; + + Search search(*GetUiaData(), text.c_str(), direction, sensitivity); + auto lock = _terminal->LockForWriting(); + if (search.FindNext()) + { + _terminal->SetBoxSelection(false); + search.Select(); + _renderer->TriggerSelection(); + } + } + + // Method Description: + // - The handler for the close button in the search box. + // This is a wrapper method that calls _CloseSearchBoxControlHelper(). + // Arguments: + // - IInspectable: not used + // - RoutedEventArgs: not used + // Return Value: + // - + void TermControl::_CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& /*sender*/, RoutedEventArgs const& /*args*/) + { + _CloseSearchBoxControlHelper(); + } + + // Method Description: + // - The helper method that removes the SearchBoxControl + // object from the XAML tree, reset smart pointer and + // set focus back to Terminal + // Arguments: + // - + // Return Value: + // - + void TermControl::_CloseSearchBoxControlHelper() + { + unsigned int idx; + _root.Children().IndexOf(*_searchBox, idx); + _root.Children().RemoveAt(idx); + + _searchBox = nullptr; + + // Set focus back to terminal control + this->Focus(FocusState::Programmatic); + } + // Method Description: // - Given new settings for this profile, applies the settings to the current terminal. // Arguments: @@ -683,6 +779,20 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void TermControl::_KeyDownHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/, Input::KeyRoutedEventArgs const& e) { + // If Esc is pressed and the search box is opened, we close the search box + if (_searchBox && e.OriginalKey() == winrt::Windows::System::VirtualKey::Escape) + { + _CloseSearchBoxControlHelper(); + return; + } + + // If the current focused element is a child element of searchbox, + // we do not send this event up to terminal + if (_searchBox && _searchBox->ContainsFocus()) + { + return; + } + // mark event as handled and do nothing if... // - closing // - key modifier is pressed diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 68c8a1ab..ae24b103 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -12,7 +12,9 @@ #include "../../renderer/dx/DxRenderer.hpp" #include "../../renderer/uia/UiaRenderer.hpp" #include "../../cascadia/TerminalCore/Terminal.hpp" +#include "../buffer/out/search.h" #include "cppwinrt_utils.h" +#include "SearchBoxControl.h" namespace winrt::Microsoft::Terminal::TerminalControl::implementation { @@ -75,6 +77,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void ResetFontSize(); void SwapChainChanged(); + + void CreateSearchBoxControl(); + ~TermControl(); Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer(); @@ -105,6 +110,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation Windows::UI::Xaml::Controls::Image _bgImageLayer; Windows::UI::Xaml::Controls::SwapChainPanel _swapChainPanel; Windows::UI::Xaml::Controls::Primitives::ScrollBar _scrollBar; + + winrt::com_ptr _searchBox; + TSFInputControl _tsfInputControl; event_token _connectionOutputEventToken; @@ -164,8 +172,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void _BackgroundColorChanged(const uint32_t color); bool _InitializeTerminal(); void _UpdateFont(); - void _SetFontSize(int fontSize); void _KeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e); + void _SetFontSize(int fontSize); void _CharacterHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::CharacterReceivedRoutedEventArgs const& e); void _PointerPressedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e); void _PointerMovedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e); @@ -206,10 +214,14 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation const unsigned int _NumberOfClicks(winrt::Windows::Foundation::Point clickPos, Timestamp clickTime); double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const; + void _Search(const winrt::Windows::Foundation::IInspectable& sender, const winrt::hstring& text); + void _CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void _CloseSearchBoxControlHelper(); + // TSFInputControl Handlers void _CompositionCompleted(winrt::hstring text); - void _CurrentCursorPositionHandler(const IInspectable& /*sender*/, const CursorPositionEventArgs& eventArgs); - void _FontInfoHandler(const IInspectable& /*sender*/, const FontInfoEventArgs& eventArgs); + void _CurrentCursorPositionHandler(const IInspectable& sender, const CursorPositionEventArgs& eventArgs); + void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs); }; } diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl index bfa3bdab..10790149 100644 --- a/src/cascadia/TerminalControl/TermControl.idl +++ b/src/cascadia/TerminalControl/TermControl.idl @@ -50,6 +50,8 @@ namespace Microsoft.Terminal.TerminalControl Int32 GetViewHeight(); event ScrollPositionChangedEventArgs ScrollPositionChanged; + void CreateSearchBoxControl(); + void AdjustFontSize(Int32 fontSizeDelta); void ResetFontSize(); } diff --git a/src/cascadia/TerminalControl/TerminalControl.vcxproj b/src/cascadia/TerminalControl/TerminalControl.vcxproj index 5ec8cd42..3d1d029a 100644 --- a/src/cascadia/TerminalControl/TerminalControl.vcxproj +++ b/src/cascadia/TerminalControl/TerminalControl.vcxproj @@ -10,6 +10,15 @@ Console true + + 3