From ac4f4a11af1ab7e25db3a2ea15ad4e37dd4fb103 Mon Sep 17 00:00:00 2001 From: Zoey Riordan Date: Fri, 13 Dec 2019 15:06:46 -0800 Subject: [PATCH] hook up UIA tree to WPF control --- .../PublicTerminalCore/HwndTerminal.cpp | 131 +++++++++++++++++- .../PublicTerminalCore/HwndTerminal.hpp | 29 +++- src/cascadia/PublicTerminalCore/pch.h | 4 + .../TermControlAutomationPeer.cpp | 46 +++++- .../TermControlAutomationPeer.h | 18 ++- .../TerminalControl/TerminalControl.vcxproj | 4 - .../TerminalControl/XamlUiaTextRange.cpp | 2 +- .../TerminalControl/XamlUiaTextRange.h | 2 +- .../WpfTerminalControl/NativeMethods.cs | 3 + .../WpfTerminalControl/TerminalContainer.cs | 7 +- .../TerminalControl.xaml.cs | 2 +- src/interactivity/win32/uiaTextRange.cpp | 6 +- src/interactivity/win32/uiaTextRange.hpp | 6 +- src/types/IControlAccessibilityInfo.h | 43 ++++++ src/types/ScreenInfoUiaProviderBase.h | 8 +- .../TermControlUiaProvider.cpp | 71 ++++++---- .../TermControlUiaProvider.hpp | 28 ++-- .../TermControlUiaTextRange.cpp} | 73 +++++----- .../TermControlUiaTextRange.hpp} | 14 +- src/types/UiaTextRangeBase.hpp | 39 +++--- src/types/lib/types.vcxproj | 5 + src/types/lib/types.vcxproj.filters | 15 ++ src/types/sources.inc | 2 + 23 files changed, 419 insertions(+), 139 deletions(-) create mode 100644 src/types/IControlAccessibilityInfo.h rename src/{cascadia/TerminalControl => types}/TermControlUiaProvider.cpp (66%) rename src/{cascadia/TerminalControl => types}/TermControlUiaProvider.hpp (76%) rename src/{cascadia/TerminalControl/UiaTextRange.cpp => types/TermControlUiaTextRange.cpp} (52%) rename src/{cascadia/TerminalControl/UiaTextRange.hpp => types/TermControlUiaTextRange.hpp} (81%) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index 0499bb0896a..09d65c13fc1 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -3,6 +3,7 @@ #include "pch.h" #include "HwndTerminal.hpp" +#include "../../types/TermControlUiaProvider.hpp" #include #include "../../renderer/base/Renderer.hpp" #include "../../renderer/dx/DxRenderer.hpp" @@ -14,13 +15,27 @@ using namespace ::Microsoft::Terminal::Core; static LPCWSTR term_window_class = L"HwndTerminalClass"; -static LRESULT CALLBACK HwndTerminalWndProc( +LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) noexcept { - return DefWindowProcW(hwnd, uMsg, wParam, lParam); +#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast + HwndTerminal* terminal = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + + if (terminal) + { + switch (uMsg) + { + case WM_GETOBJECT: + if (lParam == UiaRootObjectId) + { + return UiaReturnRawElementProvider(hwnd, wParam, lParam, terminal->_GetUiaProvider()); + } + } + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); } static bool RegisterTermClass(HINSTANCE hInstance) noexcept @@ -32,7 +47,7 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept } wc.style = 0; - wc.lpfnWndProc = HwndTerminalWndProc; + wc.lpfnWndProc = HwndTerminal::HwndTerminalWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; @@ -47,7 +62,10 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept HwndTerminal::HwndTerminal(HWND parentHwnd) : _desiredFont{ DEFAULT_FONT_FACE, 0, 10, { 0, 14 }, CP_UTF8 }, - _actualFont{ DEFAULT_FONT_FACE, 0, 10, { 0, 14 }, CP_UTF8, false } + _actualFont{ DEFAULT_FONT_FACE, 0, 10, { 0, 14 }, CP_UTF8, false }, + _uiaProvider{ nullptr }, + _uiaProviderInitialized{ false }, + _currentDpi{ USER_DEFAULT_SCREEN_DPI } { HINSTANCE hInstance = wil::GetModuleInstanceHandle(); @@ -69,6 +87,9 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) : nullptr, hInstance, nullptr)); + +#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast + SetWindowLongPtr(_hwnd.get(), GWLP_USERDATA, reinterpret_cast(this)); } } @@ -141,8 +162,19 @@ void HwndTerminal::RegisterWriteCallback(const void _stdcall callback(wchar_t*)) }); } +::Microsoft::Console::Types::IUiaData* HwndTerminal::GetUiaData() const noexcept +{ + return _terminal.get(); +} + +HWND HwndTerminal::GetHwnd() const noexcept +{ + return _hwnd.get(); +} + void HwndTerminal::_UpdateFont(int newDpi) { + _currentDpi = newDpi; auto lock = _terminal->LockForWriting(); // TODO: MSFT:20895307 If the font doesn't exist, this doesn't @@ -150,6 +182,33 @@ void HwndTerminal::_UpdateFont(int newDpi) _renderer->TriggerFontChange(newDpi, _desiredFont, _actualFont); } +IRawElementProviderSimple* HwndTerminal::_GetUiaProvider() noexcept +{ + if (nullptr == _uiaProvider && !_uiaProviderInitialized) + { + std::unique_lock lock; + try + { +#pragma warning(suppress : 26441) // The lock is named, this appears to be a false positive + lock = _terminal->LockForWriting(); + if (_uiaProviderInitialized) + { + return _uiaProvider.Get(); + } + + LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, this->GetUiaData(), this)); + } + catch (...) + { + LOG_HR(wil::ResultFromCaughtException()); + _uiaProvider = nullptr; + } + _uiaProviderInitialized = true; + } + + return _uiaProvider.Get(); +} + HRESULT HwndTerminal::Refresh(const SIZE windowSize, _Out_ COORD* dimensions) { RETURN_HR_IF_NULL(E_INVALIDARG, dimensions); @@ -186,10 +245,29 @@ void HwndTerminal::SendOutput(std::wstring_view data) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal) { - auto _terminal = std::make_unique(parentHwnd); + // In order for UIA to hook up properly there needs to be a "static" window hosting the + // inner win32 control. If the static window is not present then WM_GETOBJECT messages + // will not reach the child control, and the uia element will not be present in the tree. + auto _hostWindow = CreateWindowEx( + 0, + L"static", + nullptr, + WS_CHILD | + WS_CLIPCHILDREN | + WS_CLIPSIBLINGS | + WS_VISIBLE, + 0, + 0, + 0, + 0, + parentHwnd, + nullptr, + nullptr, + 0); + auto _terminal = std::make_unique(_hostWindow); RETURN_IF_FAILED(_terminal->Initialize()); - *hwnd = _terminal->_hwnd.get(); + *hwnd = _hostWindow; *terminal = _terminal.release(); return S_OK; @@ -217,6 +295,15 @@ HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double heig { const auto publicTerminal = static_cast(terminal); + LOG_IF_WIN32_BOOL_FALSE(SetWindowPos( + publicTerminal->GetHwnd(), + nullptr, + 0, + 0, + static_cast(width), + static_cast(height), + 0)); + const SIZE windowSize{ static_cast(width), static_cast(height) }; return publicTerminal->Refresh(windowSize, dimensions); } @@ -413,3 +500,35 @@ void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible) const auto publicTerminal = static_cast(terminal); publicTerminal->_terminal->SetCursorVisible(visible); } + +COORD HwndTerminal::GetFontSize() const +{ + return _actualFont.GetSize(); +} + +RECT HwndTerminal::GetBounds() const noexcept +{ + RECT windowRect; + GetWindowRect(_hwnd.get(), &windowRect); + return windowRect; +} + +RECT HwndTerminal::GetPadding() const noexcept +{ + return { 0 }; +} + +double HwndTerminal::GetScaleFactor() const noexcept +{ + return static_cast(_currentDpi) / static_cast(USER_DEFAULT_SCREEN_DPI); +} + +void HwndTerminal::ChangeViewport(const SMALL_RECT NewWindow) +{ + _terminal->UserScrollViewport(NewWindow.Top); +} + +HRESULT HwndTerminal::GetHostUiaProvider(IRawElementProviderSimple** provider) noexcept +{ + return UiaHostProviderFromHwnd(_hwnd.get(), provider); +} diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.hpp b/src/cascadia/PublicTerminalCore/HwndTerminal.hpp index 29785524a56..c5e1e236782 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.hpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.hpp @@ -6,6 +6,9 @@ #include "../../renderer/base/Renderer.hpp" #include "../../renderer/dx/DxRenderer.hpp" #include "../../cascadia/TerminalCore/Terminal.hpp" +#include +#include "../../types/IControlAccessibilityInfo.h" +#include "../../types/TermControlUiaProvider.hpp" using namespace Microsoft::Console::VirtualTerminal; @@ -39,20 +42,35 @@ __declspec(dllexport) void _stdcall TerminalBlinkCursor(void* terminal); __declspec(dllexport) void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible); }; -struct HwndTerminal +struct HwndTerminal : ::Microsoft::Console::Types::IControlAccessibilityInfo { public: HwndTerminal(HWND hwnd); + + HwndTerminal(const HwndTerminal&) = default; + HwndTerminal(HwndTerminal&&) = default; + HwndTerminal& operator=(const HwndTerminal&) = default; + HwndTerminal& operator=(HwndTerminal&&) = default; + ~HwndTerminal() = default; + HRESULT Initialize(); void SendOutput(std::wstring_view data); HRESULT Refresh(const SIZE windowSize, _Out_ COORD* dimensions); void RegisterScrollCallback(std::function callback); void RegisterWriteCallback(const void _stdcall callback(wchar_t*)); + ::Microsoft::Console::Types::IUiaData* GetUiaData() const noexcept; + HWND GetHwnd() const noexcept; + + static LRESULT CALLBACK HwndTerminalWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) noexcept; private: wil::unique_hwnd _hwnd; FontInfoDesired _desiredFont; FontInfo _actualFont; + int _currentDpi; + bool _uiaProviderInitialized; + + ::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider; std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal; @@ -74,4 +92,13 @@ struct HwndTerminal friend void _stdcall TerminalBlinkCursor(void* terminal); friend void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible); void _UpdateFont(int newDpi); + IRawElementProviderSimple* _GetUiaProvider() noexcept; + + // Inherited via IControlAccessibilityInfo + COORD GetFontSize() const override; + RECT GetBounds() const noexcept override; + double GetScaleFactor() const noexcept override; + void ChangeViewport(const SMALL_RECT NewWindow) override; + HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) noexcept override; + RECT GetPadding() const noexcept override; }; diff --git a/src/cascadia/PublicTerminalCore/pch.h b/src/cascadia/PublicTerminalCore/pch.h index c788085d430..6a89c0d9c4a 100644 --- a/src/cascadia/PublicTerminalCore/pch.h +++ b/src/cascadia/PublicTerminalCore/pch.h @@ -1,4 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // If this is not defined, windows.h includes commdlg.h which defines FindText globally and conflicts with UIAutomation ITextRangeProvider. +#endif + #include diff --git a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp index 40ae55f4be4..5f99c9cab43 100644 --- a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp @@ -11,6 +11,7 @@ using namespace Microsoft::Console::Types; using namespace winrt::Windows::UI::Xaml::Automation::Peers; +using namespace winrt::Windows::Graphics::Display; namespace UIA { @@ -28,9 +29,10 @@ namespace XamlAutomation namespace winrt::Microsoft::Terminal::TerminalControl::implementation { TermControlAutomationPeer::TermControlAutomationPeer(winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* owner) : - TermControlAutomationPeerT(*owner) // pass owner to FrameworkElementAutomationPeer + TermControlAutomationPeerT(*owner), // pass owner to FrameworkElementAutomationPeer + _termControl{ owner } { - THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, owner, std::bind(&TermControlAutomationPeer::GetBoundingRectWrapped, this))); + THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, _termControl->GetUiaData(), this)); }; // Method Description: @@ -159,7 +161,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation #pragma endregion - RECT TermControlAutomationPeer::GetBoundingRectWrapped() +#pragma region IControlAccessibilityInfo + COORD TermControlAutomationPeer::GetFontSize() const + { + return _termControl->GetActualFont().GetSize(); + } + + RECT TermControlAutomationPeer::GetBounds() const { auto rect = GetBoundingRectangle(); return { @@ -170,6 +178,36 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation }; } + HRESULT TermControlAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider) + { + RETURN_HR_IF(E_INVALIDARG, provider == nullptr); + *provider = nullptr; + + return S_OK; + } + + RECT TermControlAutomationPeer::GetPadding() const + { + auto padding = _termControl->GetPadding(); + return { + gsl::narrow_cast(padding.Left), + gsl::narrow_cast(padding.Top), + gsl::narrow_cast(padding.Right), + gsl::narrow_cast(padding.Bottom) + }; + } + + double TermControlAutomationPeer::GetScaleFactor() const + { + return DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); + } + + void TermControlAutomationPeer::ChangeViewport(const SMALL_RECT NewWindow) + { + _termControl->ScrollViewport(NewWindow.Top); + } +#pragma endregion + // Method Description: // - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders // Arguments: @@ -179,7 +217,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation winrt::com_array TermControlAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges) { // transfer ownership of UiaTextRanges to this new vector - auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::UiaTextRange>(textRanges); + auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges); int count = gsl::narrow(providers.size()); std::vector vec; diff --git a/src/cascadia/TerminalControl/TermControlAutomationPeer.h b/src/cascadia/TerminalControl/TermControlAutomationPeer.h index d5bfc4b09d1..bf3a95b360c 100644 --- a/src/cascadia/TerminalControl/TermControlAutomationPeer.h +++ b/src/cascadia/TerminalControl/TermControlAutomationPeer.h @@ -27,14 +27,16 @@ Author(s): #include "TermControl.h" #include "TermControlAutomationPeer.g.h" #include -#include "TermControlUiaProvider.hpp" +#include "../types/TermControlUiaProvider.hpp" #include "../types/IUiaEventDispatcher.h" +#include "../types/IControlAccessibilityInfo.h" namespace winrt::Microsoft::Terminal::TerminalControl::implementation { struct TermControlAutomationPeer : public TermControlAutomationPeerT, - ::Microsoft::Console::Types::IUiaEventDispatcher + ::Microsoft::Console::Types::IUiaEventDispatcher, + ::Microsoft::Console::Types::IControlAccessibilityInfo { public: TermControlAutomationPeer(winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* owner); @@ -59,11 +61,21 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation Windows::UI::Xaml::Automation::Provider::ITextRangeProvider DocumentRange(); #pragma endregion +#pragma region IControlAccessibilityInfo Pattern + // Inherited via IControlAccessibilityInfo + virtual COORD GetFontSize() const override; + virtual RECT GetBounds() const override; + virtual RECT GetPadding() const override; + virtual double GetScaleFactor() const override; + virtual void ChangeViewport(SMALL_RECT NewWindow) override; + virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override; +#pragma endregion + RECT GetBoundingRectWrapped(); private: ::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider; - + winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* _termControl; winrt::com_array WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges); }; } diff --git a/src/cascadia/TerminalControl/TerminalControl.vcxproj b/src/cascadia/TerminalControl/TerminalControl.vcxproj index e4d03e98222..af6cbe4d98f 100644 --- a/src/cascadia/TerminalControl/TerminalControl.vcxproj +++ b/src/cascadia/TerminalControl/TerminalControl.vcxproj @@ -36,7 +36,6 @@ SearchBoxControl.xaml - TermControl.idl @@ -46,7 +45,6 @@ TSFInputControl.idl - @@ -57,7 +55,6 @@ SearchBoxControl.xaml - TermControl.idl @@ -68,7 +65,6 @@ TermControlAutomationPeer.idl - diff --git a/src/cascadia/TerminalControl/XamlUiaTextRange.cpp b/src/cascadia/TerminalControl/XamlUiaTextRange.cpp index c727df68ae9..8490177f9aa 100644 --- a/src/cascadia/TerminalControl/XamlUiaTextRange.cpp +++ b/src/cascadia/TerminalControl/XamlUiaTextRange.cpp @@ -3,7 +3,7 @@ #include "pch.h" #include "XamlUiaTextRange.h" -#include "UiaTextRange.hpp" +#include "../types/TermControlUiaTextRange.hpp" #include // the same as COR_E_NOTSUPPORTED diff --git a/src/cascadia/TerminalControl/XamlUiaTextRange.h b/src/cascadia/TerminalControl/XamlUiaTextRange.h index 57b4ac605c5..e2eb5af9e7a 100644 --- a/src/cascadia/TerminalControl/XamlUiaTextRange.h +++ b/src/cascadia/TerminalControl/XamlUiaTextRange.h @@ -22,7 +22,7 @@ Author(s): #include "TermControlAutomationPeer.h" #include -#include "UiaTextRange.hpp" +#include "../types/TermControlUiaTextRange.hpp" namespace winrt::Microsoft::Terminal::TerminalControl::implementation { diff --git a/src/cascadia/WpfTerminalControl/NativeMethods.cs b/src/cascadia/WpfTerminalControl/NativeMethods.cs index d56908575ce..9273ca03149 100644 --- a/src/cascadia/WpfTerminalControl/NativeMethods.cs +++ b/src/cascadia/WpfTerminalControl/NativeMethods.cs @@ -7,6 +7,7 @@ namespace Microsoft.Terminal.Wpf { using System; using System.Runtime.InteropServices; + using System.Windows.Automation.Provider; #pragma warning disable SA1600 // Elements should be documented internal static class NativeMethods @@ -36,6 +37,8 @@ public enum WindowMessage : int /// WM_MOUSEACTIVATE = 0x0021, + WM_GETOBJECT = 0x003D, + /// /// The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place in the Z order has changed as a result of a call to the SetWindowPos function or another window-management function. /// diff --git a/src/cascadia/WpfTerminalControl/TerminalContainer.cs b/src/cascadia/WpfTerminalControl/TerminalContainer.cs index ba21d1fa72b..b447108225c 100644 --- a/src/cascadia/WpfTerminalControl/TerminalContainer.cs +++ b/src/cascadia/WpfTerminalControl/TerminalContainer.cs @@ -26,7 +26,7 @@ public class TerminalContainer : HwndHost private DispatcherTimer blinkTimer; private NativeMethods.ScrollCallback scrollCallback; private NativeMethods.WriteCallback writeCallback; - + /// /// Initializes a new instance of the class. /// @@ -35,7 +35,7 @@ public TerminalContainer() this.MessageHook += this.TerminalContainer_MessageHook; this.GotFocus += this.TerminalContainer_GotFocus; this.Focusable = true; - + var blinkTime = NativeMethods.GetCaretBlinkTime(); if (blinkTime != uint.MaxValue) @@ -72,6 +72,8 @@ public TerminalContainer() /// internal int Columns { get; private set; } + internal IntPtr Hwnd => this.hwnd; + /// /// Sets the connection to the terminal backend. /// @@ -172,7 +174,6 @@ protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi) protected override HandleRef BuildWindowCore(HandleRef hwndParent) { var dpiScale = VisualTreeHelper.GetDpi(this); - NativeMethods.CreateTerminal(hwndParent.Handle, out this.hwnd, out this.terminal); this.scrollCallback = this.OnScroll; diff --git a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs index f068d0edfd3..edb01e2e9aa 100644 --- a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs +++ b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs @@ -9,7 +9,7 @@ namespace Microsoft.Terminal.Wpf using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; - + /// /// A basic terminal control. This control can receive and render standard VT100 sequences. /// diff --git a/src/interactivity/win32/uiaTextRange.cpp b/src/interactivity/win32/uiaTextRange.cpp index c65c2272a8b..eb99d6cfa22 100644 --- a/src/interactivity/win32/uiaTextRange.cpp +++ b/src/interactivity/win32/uiaTextRange.cpp @@ -13,7 +13,7 @@ using namespace Microsoft::WRL; using Microsoft::Console::Interactivity::ServiceLocator; // degenerate range constructor. -HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, _In_ const std::wstring_view wordDelimiters) +HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, _In_ const std::wstring_view wordDelimiters) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, wordDelimiters); } @@ -22,7 +22,7 @@ HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElem HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, const Cursor& cursor, - const std::wstring_view wordDelimiters) + const std::wstring_view wordDelimiters) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, cursor, wordDelimiters); } @@ -32,7 +32,7 @@ HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, const COORD start, const COORD end, - const std::wstring_view wordDelimiters) + const std::wstring_view wordDelimiters) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, start, end, wordDelimiters); } diff --git a/src/interactivity/win32/uiaTextRange.hpp b/src/interactivity/win32/uiaTextRange.hpp index 6939f407880..ae3414242e6 100644 --- a/src/interactivity/win32/uiaTextRange.hpp +++ b/src/interactivity/win32/uiaTextRange.hpp @@ -29,20 +29,20 @@ namespace Microsoft::Console::Interactivity::Win32 // degenerate range HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, - _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter); + _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override; // degenerate range at cursor position HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, const Cursor& cursor, - _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter); + _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override; // specific endpoint range HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, _In_ const COORD start, _In_ const COORD end, - _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter); + _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override; // range from a UiaPoint HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, diff --git a/src/types/IControlAccessibilityInfo.h b/src/types/IControlAccessibilityInfo.h new file mode 100644 index 00000000000..b20f965698f --- /dev/null +++ b/src/types/IControlAccessibilityInfo.h @@ -0,0 +1,43 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- IControlAccessibilityInfo.h + +Abstract: +- This serves as the interface defining all information known by the control + hosting the terminal renderer that is needed for the UI Automation Tree. + +Author(s): +- Zoey Riordan (zorio) Feb-2020 +--*/ + +#pragma once + +#include + +namespace Microsoft::Console::Types +{ + class IControlAccessibilityInfo + { + public: + virtual ~IControlAccessibilityInfo() = 0; + + virtual COORD GetFontSize() const = 0; + virtual RECT GetBounds() const = 0; + virtual RECT GetPadding() const = 0; + virtual double GetScaleFactor() const = 0; + virtual void ChangeViewport(const SMALL_RECT NewWindow) = 0; + virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) = 0; + + protected: + IControlAccessibilityInfo() = default; + IControlAccessibilityInfo(const IControlAccessibilityInfo&) = default; + IControlAccessibilityInfo(IControlAccessibilityInfo&&) = default; + IControlAccessibilityInfo& operator=(const IControlAccessibilityInfo&) = default; + IControlAccessibilityInfo& operator=(IControlAccessibilityInfo&&) = default; + }; + + inline IControlAccessibilityInfo::~IControlAccessibilityInfo() {} +} \ No newline at end of file diff --git a/src/types/ScreenInfoUiaProviderBase.h b/src/types/ScreenInfoUiaProviderBase.h index 7f4e315adce..1ec9d04a64d 100644 --- a/src/types/ScreenInfoUiaProviderBase.h +++ b/src/types/ScreenInfoUiaProviderBase.h @@ -38,7 +38,7 @@ namespace Microsoft::Console::Types public WRL::RuntimeClass, IRawElementProviderSimple, IRawElementProviderFragment, ITextProvider> { public: - HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, _In_ std::wstring_view wordDelimiters = UiaTextRangeBase::DefaultWordDelimiter) noexcept; + virtual HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, _In_ std::wstring_view wordDelimiters = UiaTextRangeBase::DefaultWordDelimiter) noexcept; ScreenInfoUiaProviderBase(const ScreenInfoUiaProviderBase&) = default; ScreenInfoUiaProviderBase(ScreenInfoUiaProviderBase&&) = default; @@ -104,9 +104,9 @@ namespace Microsoft::Console::Types _COM_Outptr_result_maybenull_ UiaTextRangeBase** ppUtr) = 0; // weak reference to IUiaData - IUiaData* _pData; + IUiaData* _pData{ nullptr }; - std::wstring _wordDelimiters; + std::wstring _wordDelimiters{}; private: // this is used to prevent the object from @@ -120,7 +120,7 @@ namespace Microsoft::Console::Types // eventually overflowing the stack. // We aren't using this as a cheap locking // mechanism for multi-threaded code. - std::map _signalFiringMapping; + std::map _signalFiringMapping{}; const COORD _getScreenBufferCoords() const; const TextBuffer& _getTextBuffer() const noexcept; diff --git a/src/cascadia/TerminalControl/TermControlUiaProvider.cpp b/src/types/TermControlUiaProvider.cpp similarity index 66% rename from src/cascadia/TerminalControl/TermControlUiaProvider.cpp rename to src/types/TermControlUiaProvider.cpp index 0f7edfb5cbd..752029f78de 100644 --- a/src/cascadia/TerminalControl/TermControlUiaProvider.cpp +++ b/src/types/TermControlUiaProvider.cpp @@ -1,22 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -#include "pch.h" +#include "precomp.h" #include "TermControlUiaProvider.hpp" -#include "TermControl.h" using namespace Microsoft::Terminal; using namespace Microsoft::Console::Types; using namespace Microsoft::WRL; -HRESULT TermControlUiaProvider::RuntimeClassInitialize(_In_ winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* termControl, - _In_ std::function GetBoundingRect) +#pragma warning(suppress : 26434) // WRL RuntimeClassInitialize base is a no-op and we need this for MakeAndInitialize +HRESULT TermControlUiaProvider::RuntimeClassInitialize(_In_ ::Microsoft::Console::Types::IUiaData* const uiaData, + _In_ ::Microsoft::Console::Types::IControlAccessibilityInfo* controlInfo) noexcept { - RETURN_HR_IF_NULL(E_INVALIDARG, termControl); - RETURN_IF_FAILED(ScreenInfoUiaProviderBase::RuntimeClassInitialize(termControl->GetUiaData())); + RETURN_HR_IF_NULL(E_INVALIDARG, uiaData); + RETURN_IF_FAILED(ScreenInfoUiaProviderBase::RuntimeClassInitialize(uiaData)); - _getBoundingRect = GetBoundingRect; - _termControl = termControl; + _controlInfo = controlInfo; // TODO GitHub #1914: Re-attach Tracing to UIA Tree //Tracing::s_TraceUia(nullptr, ApiCall::Constructor, nullptr); @@ -24,8 +23,10 @@ HRESULT TermControlUiaProvider::RuntimeClassInitialize(_In_ winrt::Microsoft::Te } IFACEMETHODIMP TermControlUiaProvider::Navigate(_In_ NavigateDirection direction, - _COM_Outptr_result_maybenull_ IRawElementProviderFragment** ppProvider) + _COM_Outptr_result_maybenull_ IRawElementProviderFragment** ppProvider) noexcept { + RETURN_HR_IF_NULL(E_INVALIDARG, ppProvider); + // TODO GitHub #1914: Re-attach Tracing to UIA Tree /*ApiMsgNavigate apiMsg; apiMsg.Direction = direction; @@ -56,18 +57,29 @@ IFACEMETHODIMP TermControlUiaProvider::get_BoundingRectangle(_Out_ UiaRect* pRec // TODO GitHub #1914: Re-attach Tracing to UIA Tree //Tracing::s_TraceUia(this, ApiCall::GetBoundingRectangle, nullptr); - RECT rc = _getBoundingRect(); + const RECT rc = _controlInfo->GetBounds(); pRect->left = rc.left; pRect->top = rc.top; - pRect->width = rc.right - rc.left; - pRect->height = rc.bottom - rc.top; + pRect->width = static_cast(rc.right) - static_cast(rc.left); + pRect->height = static_cast(rc.bottom) - static_cast(rc.top); return S_OK; } -IFACEMETHODIMP TermControlUiaProvider::get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider) +IFACEMETHODIMP TermControlUiaProvider::get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider) noexcept { + try + { + return _controlInfo->GetHostUiaProvider(ppProvider); + } + CATCH_RETURN(); +} + +IFACEMETHODIMP TermControlUiaProvider::get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider) noexcept +{ + RETURN_HR_IF_NULL(E_INVALIDARG, ppProvider); + // TODO GitHub #1914: Re-attach Tracing to UIA Tree //Tracing::s_TraceUia(this, ApiCall::GetFragmentRoot, nullptr); try @@ -87,17 +99,22 @@ IFACEMETHODIMP TermControlUiaProvider::get_FragmentRoot(_COM_Outptr_result_maybe const COORD TermControlUiaProvider::GetFontSize() const { - return _termControl->GetActualFont().GetSize(); + return _controlInfo->GetFontSize(); +} + +const RECT TermControlUiaProvider::GetPadding() const +{ + return _controlInfo->GetPadding(); } -const winrt::Windows::UI::Xaml::Thickness TermControlUiaProvider::GetPadding() const +const double TermControlUiaProvider::GetScaleFactor() const { - return _termControl->GetPadding(); + return _controlInfo->GetScaleFactor(); } void TermControlUiaProvider::ChangeViewport(const SMALL_RECT NewWindow) { - _termControl->ScrollViewport(NewWindow.Top); + _controlInfo->ChangeViewport(NewWindow); } HRESULT TermControlUiaProvider::GetSelectionRange(_In_ IRawElementProviderSimple* pProvider, const std::wstring_view wordDelimiters, _COM_Outptr_result_maybenull_ UiaTextRangeBase** ppUtr) @@ -112,8 +129,8 @@ HRESULT TermControlUiaProvider::GetSelectionRange(_In_ IRawElementProviderSimple _pData->GetTextBuffer().GetSize().IncrementInBounds(end, true); // TODO GH #4509: Box Selection is misrepresented here as a line selection. - UiaTextRange* result = nullptr; - RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, start, end, wordDelimiters)); + TermControlUiaTextRange* result = nullptr; + RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, start, end, wordDelimiters)); *ppUtr = result; return S_OK; } @@ -122,8 +139,8 @@ HRESULT TermControlUiaProvider::CreateTextRange(_In_ IRawElementProviderSimple* { RETURN_HR_IF_NULL(E_INVALIDARG, ppUtr); *ppUtr = nullptr; - UiaTextRange* result = nullptr; - RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, wordDelimiters)); + TermControlUiaTextRange* result = nullptr; + RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, wordDelimiters)); *ppUtr = result; return S_OK; } @@ -135,8 +152,8 @@ HRESULT TermControlUiaProvider::CreateTextRange(_In_ IRawElementProviderSimple* { RETURN_HR_IF_NULL(E_INVALIDARG, ppUtr); *ppUtr = nullptr; - UiaTextRange* result = nullptr; - RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, cursor, wordDelimiters)); + TermControlUiaTextRange* result = nullptr; + RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, cursor, wordDelimiters)); *ppUtr = result; return S_OK; } @@ -149,8 +166,8 @@ HRESULT TermControlUiaProvider::CreateTextRange(_In_ IRawElementProviderSimple* { RETURN_HR_IF_NULL(E_INVALIDARG, ppUtr); *ppUtr = nullptr; - UiaTextRange* result = nullptr; - RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, start, end, wordDelimiters)); + TermControlUiaTextRange* result = nullptr; + RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, start, end, wordDelimiters)); *ppUtr = result; return S_OK; } @@ -162,8 +179,8 @@ HRESULT TermControlUiaProvider::CreateTextRange(_In_ IRawElementProviderSimple* { RETURN_HR_IF_NULL(E_INVALIDARG, ppUtr); *ppUtr = nullptr; - UiaTextRange* result = nullptr; - RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, point, wordDelimiters)); + TermControlUiaTextRange* result = nullptr; + RETURN_IF_FAILED(MakeAndInitialize(&result, _pData, pProvider, point, wordDelimiters)); *ppUtr = result; return S_OK; } diff --git a/src/cascadia/TerminalControl/TermControlUiaProvider.hpp b/src/types/TermControlUiaProvider.hpp similarity index 76% rename from src/cascadia/TerminalControl/TermControlUiaProvider.hpp rename to src/types/TermControlUiaProvider.hpp index 599983b6389..a7629ea08c4 100644 --- a/src/cascadia/TerminalControl/TermControlUiaProvider.hpp +++ b/src/types/TermControlUiaProvider.hpp @@ -19,32 +19,29 @@ Author(s): #pragma once -#include "..\types\ScreenInfoUiaProviderBase.h" -#include "..\types\UiaTextRangeBase.hpp" -#include "UiaTextRange.hpp" - -namespace winrt::Microsoft::Terminal::TerminalControl::implementation -{ - struct TermControl; -} - +#include "ScreenInfoUiaProviderBase.h" +#include "UiaTextRangeBase.hpp" +#include "IControlAccessibilityInfo.h" +#include "TermControlUiaTextRange.hpp" namespace Microsoft::Terminal { class TermControlUiaProvider : public Microsoft::Console::Types::ScreenInfoUiaProviderBase { public: TermControlUiaProvider() = default; - HRESULT RuntimeClassInitialize(_In_ winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* termControl, - _In_ std::function GetBoundingRect); + HRESULT RuntimeClassInitialize(_In_ ::Microsoft::Console::Types::IUiaData* const uiaData, + _In_ ::Microsoft::Console::Types::IControlAccessibilityInfo* controlInfo) noexcept; // IRawElementProviderFragment methods IFACEMETHODIMP Navigate(_In_ NavigateDirection direction, - _COM_Outptr_result_maybenull_ IRawElementProviderFragment** ppProvider) override; + _COM_Outptr_result_maybenull_ IRawElementProviderFragment** ppProvider) noexcept override; + IFACEMETHODIMP get_HostRawElementProvider(IRawElementProviderSimple** ppProvider) noexcept override; IFACEMETHODIMP get_BoundingRectangle(_Out_ UiaRect* pRect) override; - IFACEMETHODIMP get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider) override; + IFACEMETHODIMP get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider) noexcept override; const COORD GetFontSize() const; - const winrt::Windows::UI::Xaml::Thickness GetPadding() const; + const RECT GetPadding() const; + const double GetScaleFactor() const; void ChangeViewport(const SMALL_RECT NewWindow) override; protected: @@ -73,7 +70,6 @@ namespace Microsoft::Terminal _COM_Outptr_result_maybenull_ Microsoft::Console::Types::UiaTextRangeBase** ppUtr) override; private: - std::function _getBoundingRect; - winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* _termControl; + ::Microsoft::Console::Types::IControlAccessibilityInfo* _controlInfo{ nullptr }; }; } diff --git a/src/cascadia/TerminalControl/UiaTextRange.cpp b/src/types/TermControlUiaTextRange.cpp similarity index 52% rename from src/cascadia/TerminalControl/UiaTextRange.cpp rename to src/types/TermControlUiaTextRange.cpp index e5647cea342..e4524873592 100644 --- a/src/cascadia/TerminalControl/UiaTextRange.cpp +++ b/src/types/TermControlUiaTextRange.cpp @@ -1,59 +1,60 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -#include "pch.h" -#include "UiaTextRange.hpp" +#include "precomp.h" +#include "TermControlUiaTextRange.hpp" #include "TermControlUiaProvider.hpp" using namespace Microsoft::Terminal; using namespace Microsoft::Console::Types; using namespace Microsoft::WRL; -using namespace winrt::Windows::Graphics::Display; // degenerate range constructor. -HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, _In_ const std::wstring_view wordDelimiters) +HRESULT TermControlUiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, _In_ const std::wstring_view wordDelimiters) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, wordDelimiters); } -HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, - _In_ IRawElementProviderSimple* const pProvider, - const Cursor& cursor, - const std::wstring_view wordDelimiters) +HRESULT TermControlUiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, + _In_ IRawElementProviderSimple* const pProvider, + const Cursor& cursor, + const std::wstring_view wordDelimiters) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, cursor, wordDelimiters); } -HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, - _In_ IRawElementProviderSimple* const pProvider, - const COORD start, - const COORD end, - const std::wstring_view wordDelimiters) +HRESULT TermControlUiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, + _In_ IRawElementProviderSimple* const pProvider, + const COORD start, + const COORD end, + const std::wstring_view wordDelimiters) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, start, end, wordDelimiters); } // returns a degenerate text range of the start of the row closest to the y value of point -HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, - _In_ IRawElementProviderSimple* const pProvider, - const UiaPoint point, - const std::wstring_view wordDelimiters) +#pragma warning(suppress : 26434) // WRL RuntimeClassInitialize base is a no-op and we need this for MakeAndInitialize +HRESULT TermControlUiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData, + _In_ IRawElementProviderSimple* const pProvider, + const UiaPoint point, + const std::wstring_view wordDelimiters) { RETURN_IF_FAILED(UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, wordDelimiters)); Initialize(point); return S_OK; } -HRESULT UiaTextRange::RuntimeClassInitialize(const UiaTextRange& a) +#pragma warning(suppress : 26434) // WRL RuntimeClassInitialize base is a no-op and we need this for MakeAndInitialize +HRESULT TermControlUiaTextRange::RuntimeClassInitialize(const TermControlUiaTextRange& a) noexcept { return UiaTextRangeBase::RuntimeClassInitialize(a); } -IFACEMETHODIMP UiaTextRange::Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) +IFACEMETHODIMP TermControlUiaTextRange::Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) { RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr); *ppRetVal = nullptr; - auto hr = MakeAndInitialize(ppRetVal, *this); + const auto hr = MakeAndInitialize(ppRetVal, *this); if (hr != S_OK) { @@ -78,9 +79,9 @@ IFACEMETHODIMP UiaTextRange::Clone(_Outptr_result_maybenull_ ITextRangeProvider* return S_OK; } -void UiaTextRange::_ChangeViewport(const SMALL_RECT NewWindow) +void TermControlUiaTextRange::_ChangeViewport(const SMALL_RECT NewWindow) { - auto provider = static_cast(_pProvider); + const gsl::not_null provider = static_cast(_pProvider); provider->ChangeViewport(NewWindow); } @@ -91,11 +92,11 @@ void UiaTextRange::_ChangeViewport(const SMALL_RECT NewWindow) // (0,0) is the top-left of the app window // Return Value: // - -void UiaTextRange::_TranslatePointToScreen(LPPOINT clientPoint) const +void TermControlUiaTextRange::_TranslatePointToScreen(LPPOINT clientPoint) const { - auto provider = static_cast(_pProvider); + const gsl::not_null provider = static_cast(_pProvider); - auto includeOffsets = [](long clientPos, double termControlPos, double padding, double scaleFactor) { + const auto includeOffsets = [](long clientPos, double termControlPos, double padding, double scaleFactor) { auto result = base::ClampedNumeric(clientPos); result += padding; result *= scaleFactor; @@ -111,10 +112,10 @@ void UiaTextRange::_TranslatePointToScreen(LPPOINT clientPoint) const const auto padding = provider->GetPadding(); // Get scale factor for display - const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); + const auto scaleFactor = provider->GetScaleFactor(); - clientPoint->x = includeOffsets(clientPoint->x, boundingRect.left, padding.Left, scaleFactor); - clientPoint->y = includeOffsets(clientPoint->y, boundingRect.top, padding.Top, scaleFactor); + clientPoint->x = includeOffsets(clientPoint->x, boundingRect.left, padding.left, scaleFactor); + clientPoint->y = includeOffsets(clientPoint->y, boundingRect.top, padding.top, scaleFactor); } // Method Description: @@ -124,11 +125,11 @@ void UiaTextRange::_TranslatePointToScreen(LPPOINT clientPoint) const // (0,0) is the top-left of the screen // Return Value: // - -void UiaTextRange::_TranslatePointFromScreen(LPPOINT screenPoint) const +void TermControlUiaTextRange::_TranslatePointFromScreen(LPPOINT screenPoint) const { - auto provider = static_cast(_pProvider); + const gsl::not_null provider = static_cast(_pProvider); - auto includeOffsets = [](long screenPos, double termControlPos, double padding, double scaleFactor) { + const auto includeOffsets = [](long screenPos, double termControlPos, double padding, double scaleFactor) { auto result = base::ClampedNumeric(screenPos); result -= termControlPos; result /= scaleFactor; @@ -144,17 +145,17 @@ void UiaTextRange::_TranslatePointFromScreen(LPPOINT screenPoint) const const auto padding = provider->GetPadding(); // Get scale factor for display - const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); + const auto scaleFactor = provider->GetScaleFactor(); - screenPoint->x = includeOffsets(screenPoint->x, boundingRect.left, padding.Left, scaleFactor); - screenPoint->y = includeOffsets(screenPoint->y, boundingRect.top, padding.Top, scaleFactor); + screenPoint->x = includeOffsets(screenPoint->x, boundingRect.left, padding.left, scaleFactor); + screenPoint->y = includeOffsets(screenPoint->y, boundingRect.top, padding.top, scaleFactor); } -const COORD UiaTextRange::_getScreenFontSize() const +const COORD TermControlUiaTextRange::_getScreenFontSize() const { // Do NOT get the font info from IRenderData. It is a dummy font info. // Instead, the font info is saved in the TermControl. So we have to // ask our parent to get it for us. - auto provider = static_cast(_pProvider); + const gsl::not_null provider = static_cast(_pProvider); return provider->GetFontSize(); } diff --git a/src/cascadia/TerminalControl/UiaTextRange.hpp b/src/types/TermControlUiaTextRange.hpp similarity index 81% rename from src/cascadia/TerminalControl/UiaTextRange.hpp rename to src/types/TermControlUiaTextRange.hpp index f0fe6e90ef9..287b4b66dbf 100644 --- a/src/cascadia/TerminalControl/UiaTextRange.hpp +++ b/src/types/TermControlUiaTextRange.hpp @@ -3,7 +3,7 @@ Copyright (c) Microsoft Corporation Licensed under the MIT license. Module Name: -- UiaTextRange.hpp +- TermControlUiaTextRange.hpp Abstract: - This module provides UI Automation access to the text of the console @@ -20,28 +20,28 @@ Author(s): namespace Microsoft::Terminal { - class UiaTextRange final : public Microsoft::Console::Types::UiaTextRangeBase + class TermControlUiaTextRange final : public Microsoft::Console::Types::UiaTextRangeBase { public: - UiaTextRange() = default; + TermControlUiaTextRange() = default; // degenerate range HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, - _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter); + _In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override; // degenerate range at cursor position HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, const Cursor& cursor, - const std::wstring_view wordDelimiters = DefaultWordDelimiter); + const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override; // specific endpoint range HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, const COORD start, const COORD end, - const std::wstring_view wordDelimiters = DefaultWordDelimiter); + const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override; // range from a UiaPoint HRESULT RuntimeClassInitialize(_In_ Microsoft::Console::Types::IUiaData* pData, @@ -49,7 +49,7 @@ namespace Microsoft::Terminal const UiaPoint point, const std::wstring_view wordDelimiters = DefaultWordDelimiter); - HRESULT RuntimeClassInitialize(const UiaTextRange& a); + HRESULT RuntimeClassInitialize(const TermControlUiaTextRange& a) noexcept; IFACEMETHODIMP Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override; diff --git a/src/types/UiaTextRangeBase.hpp b/src/types/UiaTextRangeBase.hpp index 17480ec1ba8..94c14906018 100644 --- a/src/types/UiaTextRangeBase.hpp +++ b/src/types/UiaTextRangeBase.hpp @@ -58,25 +58,26 @@ namespace Microsoft::Console::Types static constexpr std::wstring_view DefaultWordDelimiter{ &UNICODE_SPACE, 1 }; // degenerate range - HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, - _In_ IRawElementProviderSimple* const pProvider, - _In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept; + virtual HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, + _In_ IRawElementProviderSimple* const pProvider, + _In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept; // degenerate range at cursor position - HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, - _In_ IRawElementProviderSimple* const pProvider, - _In_ const Cursor& cursor, - _In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept; + virtual HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, + _In_ IRawElementProviderSimple* const pProvider, + _In_ const Cursor& cursor, + _In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept; // specific endpoint range - HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, - _In_ IRawElementProviderSimple* const pProvider, - _In_ const COORD start, - _In_ const COORD end, - _In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept; + virtual HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, + _In_ IRawElementProviderSimple* const pProvider, + _In_ const COORD start, + _In_ const COORD end, + _In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept; - HRESULT RuntimeClassInitialize(const UiaTextRangeBase& a) noexcept; + virtual HRESULT RuntimeClassInitialize(const UiaTextRangeBase& a) noexcept; + UiaTextRangeBase(const UiaTextRangeBase&) = default; UiaTextRangeBase(UiaTextRangeBase&&) = default; UiaTextRangeBase& operator=(const UiaTextRangeBase&) = default; UiaTextRangeBase& operator=(UiaTextRangeBase&&) = default; @@ -127,11 +128,11 @@ namespace Microsoft::Console::Types protected: UiaTextRangeBase() = default; - IUiaData* _pData; + IUiaData* _pData{ nullptr }; - IRawElementProviderSimple* _pProvider; + IRawElementProviderSimple* _pProvider{ nullptr }; - std::wstring _wordDelimiters; + std::wstring _wordDelimiters{}; virtual void _ChangeViewport(const SMALL_RECT NewWindow) = 0; virtual void _TranslatePointToScreen(LPPOINT clientPoint) const = 0; @@ -141,13 +142,13 @@ namespace Microsoft::Console::Types // used to debug objects passed back and forth // between the provider and the client - IdType _id; + IdType _id{}; // measure units in the form [_start, _end). // These are in the TextBuffer coordinate space. // NOTE: _start is inclusive, but _end is exclusive - COORD _start; - COORD _end; + COORD _start{}; + COORD _end{}; // This is used by tracing to extract the text value // that the UiaTextRange currently encompasses. diff --git a/src/types/lib/types.vcxproj b/src/types/lib/types.vcxproj index 53c04a49c8b..e1c16bca2f0 100644 --- a/src/types/lib/types.vcxproj +++ b/src/types/lib/types.vcxproj @@ -24,6 +24,8 @@ + + @@ -36,6 +38,7 @@ + @@ -48,6 +51,8 @@ + + diff --git a/src/types/lib/types.vcxproj.filters b/src/types/lib/types.vcxproj.filters index 6c45b62a65a..54681a8257e 100644 --- a/src/types/lib/types.vcxproj.filters +++ b/src/types/lib/types.vcxproj.filters @@ -75,6 +75,12 @@ Source Files + + Source Files + + + Source Files + @@ -101,6 +107,9 @@ Header Files + + Header Files + Header Files @@ -137,6 +146,12 @@ Header Files + + Header Files + + + Header Files + Header Files diff --git a/src/types/sources.inc b/src/types/sources.inc index 96a663dde9b..0834197df9d 100644 --- a/src/types/sources.inc +++ b/src/types/sources.inc @@ -45,6 +45,8 @@ SOURCES= \ ..\WindowUiaProviderBase.cpp \ ..\ScreenInfoUiaProviderBase.cpp \ ..\UiaTextRangeBase.cpp \ + ..\TermControlUiaProvider.cpp \ + ..\TermControlUiaTextRange.cpp \ INCLUDES= \ $(INCLUDES); \