terminal/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp
Mike Griese d749df70ed
Rename Microsoft.Terminal.TerminalControl to .Control; Split into dll & lib (#9472)
**BE NOT AFRAID**. I know that there's 107 files in this PR, but almost
all of it is just find/replacing `TerminalControl` with `Control`.

This is the start of the work to move TermControl into multiple pieces,
for #5000. The PR starts this work by:
* Splits `TerminalControl` into separate lib and dll projects. We'll
  want control tests in the future, and for that, we'll need a lib.
* Moves `ICoreSettings` back into the `Microsoft.Terminal.Core`
  namespace. We'll have other types in there soon too. 
  * I could not tell you why this works suddenly. New VS versions? New
    cppwinrt version? Maybe we're just better at dealing with mdmerge
    bugs these days.
* RENAMES  `Microsoft.Terminal.TerminalControl` to
  `Microsoft.Terminal.Control`. This touches pretty much every file in
  the sln. Sorry about that (not sorry). 

An upcoming PR will move much of the logic in TermControl into a new
`ControlCore` class that we'll add in `Microsoft.Terminal.Core`.
`ControlCore` will then be unittest-able in the
`UnitTests_TerminalCore`, which will help prevent regressions like #9455 

## Detailed Description of the Pull Request / Additional comments
You're really gonna want to clean the sln first, then merge this into
your branch, then rebuild. It's very likely that old winmds will get
left behind. If you see something like 

```
Error    MDM2007    Cannot create type
Microsoft.Terminal.TerminalControl.KeyModifiers in read-only metadata
file Microsoft.Terminal.TerminalControl.
```

then that's what happened to you.
2021-03-17 20:47:24 +00:00

272 lines
9.9 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <UIAutomationCore.h>
#include <LibraryResources.h>
#include "TermControlAutomationPeer.h"
#include "TermControl.h"
#include "TermControlAutomationPeer.g.cpp"
#include "XamlUiaTextRange.h"
#include "../types/UiaTracing.h"
using namespace Microsoft::Console::Types;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
using namespace winrt::Windows::Graphics::Display;
namespace UIA
{
using ::ITextRangeProvider;
using ::SupportedTextSelection;
}
namespace XamlAutomation
{
using winrt::Windows::UI::Xaml::Automation::SupportedTextSelection;
using winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple;
using winrt::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider;
}
namespace winrt::Microsoft::Terminal::Control::implementation
{
TermControlAutomationPeer::TermControlAutomationPeer(winrt::Microsoft::Terminal::Control::implementation::TermControl* owner) :
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner), // pass owner to FrameworkElementAutomationPeer
_termControl{ owner }
{
THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, _termControl->GetUiaData(), this));
};
// Method Description:
// - Signals the ui automation client that the terminal's selection has changed and should be updated
// Arguments:
// - <none>
// Return Value:
// - <none>
void TermControlAutomationPeer::SignalSelectionChanged()
{
UiaTracing::Signal::SelectionChanged();
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
// The event that is raised when the text selection is modified.
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
});
}
// Method Description:
// - Signals the ui automation client that the terminal's output has changed and should be updated
// Arguments:
// - <none>
// Return Value:
// - <none>
void TermControlAutomationPeer::SignalTextChanged()
{
UiaTracing::Signal::TextChanged();
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
// The event that is raised when textual content is modified.
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
});
}
// Method Description:
// - Signals the ui automation client that the cursor's state has changed and should be updated
// Arguments:
// - <none>
// Return Value:
// - <none>
void TermControlAutomationPeer::SignalCursorChanged()
{
UiaTracing::Signal::CursorChanged();
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
// The event that is raised when the text was changed in an edit control.
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
// will expect more information. Though you can dispatch that event
// on its own, it may result in a nullptr exception on the other side
// because no additional information was provided. Crashing the screen
// reader.
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
});
}
hstring TermControlAutomationPeer::GetClassNameCore() const
{
return L"TermControl";
}
AutomationControlType TermControlAutomationPeer::GetAutomationControlTypeCore() const
{
return AutomationControlType::Text;
}
hstring TermControlAutomationPeer::GetLocalizedControlTypeCore() const
{
return RS_(L"TerminalControl_ControlType");
}
Windows::Foundation::IInspectable TermControlAutomationPeer::GetPatternCore(PatternInterface patternInterface) const
{
switch (patternInterface)
{
case PatternInterface::Text:
return *this;
break;
default:
return nullptr;
}
}
AutomationOrientation TermControlAutomationPeer::GetOrientationCore() const
{
return AutomationOrientation::Vertical;
}
hstring TermControlAutomationPeer::GetNameCore() const
{
// fallback to title if profile name is empty
auto profileName = _termControl->GetProfileName();
if (profileName.empty())
{
return _termControl->Title();
}
return profileName;
}
hstring TermControlAutomationPeer::GetHelpTextCore() const
{
return _termControl->Title();
}
AutomationLiveSetting TermControlAutomationPeer::GetLiveSettingCore() const
{
return AutomationLiveSetting::Polite;
}
#pragma region ITextProvider
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetSelection()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetSelection(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
}
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetVisibleRanges()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetVisibleRanges(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromChild(XamlAutomation::IRawElementProviderSimple childElement)
{
UIA::ITextRangeProvider* returnVal;
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
THROW_IF_FAILED(_uiaProvider->RangeFromChild(/* IRawElementProviderSimple */ nullptr,
&returnVal));
auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::DocumentRange()
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
}
XamlAutomation::SupportedTextSelection TermControlAutomationPeer::SupportedTextSelection()
{
UIA::SupportedTextSelection returnVal;
THROW_IF_FAILED(_uiaProvider->get_SupportedTextSelection(&returnVal));
return static_cast<XamlAutomation::SupportedTextSelection>(returnVal);
}
#pragma endregion
#pragma region IControlAccessibilityInfo
COORD TermControlAutomationPeer::GetFontSize() const
{
return _termControl->GetActualFont().GetSize();
}
RECT TermControlAutomationPeer::GetBounds() const
{
auto rect = GetBoundingRectangle();
return {
gsl::narrow_cast<LONG>(rect.X),
gsl::narrow_cast<LONG>(rect.Y),
gsl::narrow_cast<LONG>(rect.X + rect.Width),
gsl::narrow_cast<LONG>(rect.Y + rect.Height)
};
}
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<LONG>(padding.Left),
gsl::narrow_cast<LONG>(padding.Top),
gsl::narrow_cast<LONG>(padding.Right),
gsl::narrow_cast<LONG>(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:
// - SAFEARRAY of UIA::UiaTextRange (ITextRangeProviders)
// Return Value:
// - com_array of Xaml Wrapped UiaTextRange (ITextRangeProviders)
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges)
{
// transfer ownership of UiaTextRanges to this new vector
auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges);
int count = gsl::narrow<int>(providers.size());
std::vector<XamlAutomation::ITextRangeProvider> vec;
vec.reserve(count);
auto parentProvider = this->ProviderFromPeer(*this);
for (int i = 0; i < count; i++)
{
auto xutr = make_self<XamlUiaTextRange>(providers[i].detach(), parentProvider);
vec.emplace_back(xutr.as<XamlAutomation::ITextRangeProvider>());
}
com_array<XamlAutomation::ITextRangeProvider> result{ vec };
return result;
}
}