Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility: TermControl Automation Peer #2083

Merged
merged 28 commits into from
Jul 30, 2019
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bd996e0
- Created IWindow as a common interface to IConsoleWindow and BaseWindow
carlos-zamora Jun 26, 2019
f6e3a60
ConHost is building again. Wrong ScreenInfoUiaProvider (SIUP) is bein…
carlos-zamora Jun 27, 2019
02ebe8e
- Replaced IWindow with IConsoleWindow
carlos-zamora Jun 28, 2019
73275b8
Fixed rebase onto master
carlos-zamora Jun 28, 2019
4dc0c5c
CODE FORMATTING
carlos-zamora Jun 28, 2019
a162758
Accessibility: Finalized Shared UIA Tree Model (#1915)
carlos-zamora Jul 16, 2019
b618509
included some "using Microsoft::Console::Types" to make code prettier
carlos-zamora Jul 17, 2019
93a0f5c
Removed GetControl() from TermControl and just made it a control
carlos-zamora Jul 24, 2019
2be5ff2
- Created IWindow as a common interface to IConsoleWindow and BaseWindow
carlos-zamora Jun 26, 2019
4c6faec
ConHost is building again. Wrong ScreenInfoUiaProvider (SIUP) is bein…
carlos-zamora Jun 27, 2019
c1ce169
- Replaced IWindow with IConsoleWindow
carlos-zamora Jun 28, 2019
65dc3ff
Fixed rebase onto master
carlos-zamora Jun 28, 2019
8290f78
CODE FORMATTING
carlos-zamora Jun 28, 2019
7417a9a
Accessibility: Finalized Shared UIA Tree Model (#1915)
carlos-zamora Jul 16, 2019
867412a
included some "using Microsoft::Console::Types" to make code prettier
carlos-zamora Jul 17, 2019
a815b42
Changed IslandWindow from IConsoleWindow --> IUiaWindow
carlos-zamora Jul 23, 2019
ab4c0a8
merge dev/cazamor/accessibility
carlos-zamora Jul 24, 2019
a77a4ac
PR Changes
carlos-zamora Jul 25, 2019
7480805
NARRATOR NOW WORKS
carlos-zamora Jul 25, 2019
e182c12
Michael's PR Changes
carlos-zamora Jul 26, 2019
9674216
Missed one...whoops
carlos-zamora Jul 26, 2019
b0afc09
Most PR changes
carlos-zamora Jul 29, 2019
9bd83e9
Eliminated optional HWND
carlos-zamora Jul 29, 2019
c132ed8
Merge branch 'master' into dev/cazamor/acc/text_buffer
carlos-zamora Jul 30, 2019
1db8b20
Updated SafeArrayToOwningVector()
carlos-zamora Jul 30, 2019
573fcdb
Made code more readable
carlos-zamora Jul 30, 2019
6d57899
rename helper func
carlos-zamora Jul 30, 2019
c533307
Added THROW_IF_FAILED everywhere
carlos-zamora Jul 30, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ namespace winrt::TerminalApp::implementation
_UpdateTitle(tab);
});

term.GetControl().GotFocus([this, weakTabPtr](auto&&, auto&&) {
term.GotFocus([this, weakTabPtr](auto&&, auto&&) {
auto tab = weakTabPtr.lock();
if (!tab)
{
Expand Down
12 changes: 6 additions & 6 deletions src/cascadia/TerminalApp/Pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocus
_lastFocused{ lastFocused },
_profile{ profile }
{
_root.Children().Append(_control.GetControl());
_root.Children().Append(_control);
_connectionClosedToken = _control.ConnectionClosed({ this, &Pane::_ControlClosedHandler });

// Set the background of the pane to match that of the theme's default grid
Expand Down Expand Up @@ -426,7 +426,7 @@ bool Pane::_HasFocusedChild() const noexcept
// We're intentionally making this one giant expression, so the compiler
// will skip the following lookups if one of the lookups before it returns
// true
return (_control && _control.GetControl().FocusState() != FocusState::Unfocused) ||
return (_control && _control.FocusState() != FocusState::Unfocused) ||
(_firstChild && _firstChild->_HasFocusedChild()) ||
(_secondChild && _secondChild->_HasFocusedChild());
}
Expand All @@ -445,7 +445,7 @@ void Pane::UpdateFocus()
if (_IsLeaf())
{
const auto controlFocused = _control &&
_control.GetControl().FocusState() != FocusState::Unfocused;
_control.FocusState() != FocusState::Unfocused;

_lastFocused = controlFocused;
}
Expand All @@ -468,7 +468,7 @@ void Pane::_FocusFirstChild()
{
if (_IsLeaf())
{
_control.GetControl().Focus(FocusState::Programmatic);
_control.Focus(FocusState::Programmatic);
}
else
{
Expand Down Expand Up @@ -564,11 +564,11 @@ void Pane::_CloseChild(const bool closeFirst)
_separatorRoot = { nullptr };

// Reattach the TermControl to our grid.
_root.Children().Append(_control.GetControl());
_root.Children().Append(_control);

if (_lastFocused)
{
_control.GetControl().Focus(FocusState::Programmatic);
_control.Focus(FocusState::Programmatic);
}

_splitState = SplitState::None;
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/TerminalApp/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void Tab::_Focus()
auto lastFocusedControl = _rootPane->GetFocusedTerminalControl();
if (lastFocusedControl)
{
lastFocusedControl.GetControl().Focus(FocusState::Programmatic);
lastFocusedControl.Focus(FocusState::Programmatic);
}
}

Expand Down Expand Up @@ -181,7 +181,7 @@ void Tab::SetTabText(const winrt::hstring& text)
void Tab::Scroll(const int delta)
{
auto control = GetFocusedTerminalControl();
control.GetControl().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [control, delta]() {
control.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [control, delta]() {
const auto currentOffset = control.GetScrollOffset();
control.KeyboardScrollViewport(currentOffset + delta);
});
Expand Down
37 changes: 16 additions & 21 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "..\..\types\inc\GlyphWidth.hpp"

#include "TermControl.g.cpp"
#include "TermControlAutomationPeer.h"

using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Terminal::Core;
Expand All @@ -30,7 +31,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
_connection{ connection },
_initializedTerminal{ false },
_root{ nullptr },
_controlRoot{ nullptr },
_swapChainPanel{ nullptr },
_settings{ settings },
_closing{ false },
Expand All @@ -52,11 +52,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation

void TermControl::_Create()
{
// Create a dummy UserControl to use as the "root" of our control we'll
// build manually.
Controls::UserControl myControl;
_controlRoot = myControl;

Controls::Grid container;

Controls::ColumnDefinition contentColumn{};
Expand Down Expand Up @@ -108,20 +103,20 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
_bgImageLayer = bgImageLayer;

_swapChainPanel = swapChainPanel;
_controlRoot.Content(_root);
this->Content(_root);

_ApplyUISettings();

// These are important:
// 1. When we get tapped, focus us
_controlRoot.Tapped([this](auto&, auto& e) {
_controlRoot.Focus(FocusState::Pointer);
this->Tapped([this](auto&, auto& e) {
this->Focus(FocusState::Pointer);
e.Handled(true);
});
// 2. Make sure we can be focused (why this isn't `Focusable` I'll never know)
_controlRoot.IsTabStop(true);
this->IsTabStop(true);
// 3. Actually not sure about this one. Maybe it isn't necessary either.
_controlRoot.AllowFocusOnInteraction(true);
this->AllowFocusOnInteraction(true);

// DON'T CALL _InitializeTerminal here - wait until the swap chain is loaded to do that.

Expand Down Expand Up @@ -330,14 +325,14 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
Close();
}

UIElement TermControl::GetRoot()
Windows::UI::Xaml::Automation::Peers::AutomationPeer TermControl::OnCreateAutomationPeer()
{
return _root;
return winrt::make<winrt::Microsoft::Terminal::TerminalControl::implementation::TermControlAutomationPeer>(*this);
}

Controls::UserControl TermControl::GetControl()
::Microsoft::Console::Render::IRenderData* TermControl::GetRenderData() const
{
return _controlRoot;
return _terminal.get();
}

void TermControl::SwapChainChanged()
Expand Down Expand Up @@ -491,9 +486,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// through CharacterRecieved.
// I don't believe there's a difference between KeyDown and
// PreviewKeyDown for our purposes
// These two handlers _must_ be on _controlRoot, not _root.
_controlRoot.PreviewKeyDown({ this, &TermControl::_KeyDownHandler });
_controlRoot.CharacterReceived({ this, &TermControl::_CharacterHandler });
// These two handlers _must_ be on this, not _root.
this->PreviewKeyDown({ this, &TermControl::_KeyDownHandler });
this->CharacterReceived({ this, &TermControl::_CharacterHandler });

auto pfnTitleChanged = std::bind(&TermControl::_TerminalTitleChanged, this, std::placeholders::_1);
_terminal->SetTitleChangedCallback(pfnTitleChanged);
Expand Down Expand Up @@ -527,14 +522,14 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// import value from WinUser (convert from milli-seconds to micro-seconds)
_multiClickTimer = GetDoubleClickTime() * 1000;

_gotFocusRevoker = _controlRoot.GotFocus(winrt::auto_revoke, { this, &TermControl::_GotFocusHandler });
_lostFocusRevoker = _controlRoot.LostFocus(winrt::auto_revoke, { this, &TermControl::_LostFocusHandler });
_gotFocusRevoker = this->GotFocus(winrt::auto_revoke, { this, &TermControl::_GotFocusHandler });
_lostFocusRevoker = this->LostFocus(winrt::auto_revoke, { this, &TermControl::_LostFocusHandler });

// Focus the control here. If we do it up above (in _Create_), then the
// focus won't actually get passed to us. I believe this is because
// we're not technically a part of the UI tree yet, so focusing us
// becomes a no-op.
_controlRoot.Focus(FocusState::Programmatic);
this->Focus(FocusState::Programmatic);

_connection.Start();
_initializedTerminal = true;
Expand Down
6 changes: 3 additions & 3 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
TermControl();
TermControl(Settings::IControlSettings settings, TerminalConnection::ITerminalConnection connection);

Windows::UI::Xaml::UIElement GetRoot();
Windows::UI::Xaml::Controls::UserControl GetControl();
void UpdateSettings(Settings::IControlSettings newSettings);

hstring Title();
Expand All @@ -55,6 +53,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
void SwapChainChanged();
~TermControl();

Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
::Microsoft::Console::Render::IRenderData* GetRenderData() const;

static Windows::Foundation::Point GetProposedDimensions(Microsoft::Terminal::Settings::IControlSettings const& settings, const uint32_t dpi);

// clang-format off
Expand All @@ -71,7 +72,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
TerminalConnection::ITerminalConnection _connection;
bool _initializedTerminal;

Windows::UI::Xaml::Controls::UserControl _controlRoot;
Windows::UI::Xaml::Controls::Grid _root;
Windows::UI::Xaml::Controls::Image _bgImageLayer;
Windows::UI::Xaml::Controls::SwapChainPanel _swapChainPanel;
Expand Down
4 changes: 1 addition & 3 deletions src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@ namespace Microsoft.Terminal.TerminalControl
}

[default_interface]
runtimeclass TermControl
runtimeclass TermControl : Windows.UI.Xaml.Controls.UserControl
{
TermControl();
TermControl(Microsoft.Terminal.Settings.IControlSettings settings, Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);

static Windows.Foundation.Point GetProposedDimensions(Microsoft.Terminal.Settings.IControlSettings settings, UInt32 dpi);

Windows.UI.Xaml.UIElement GetRoot();
Windows.UI.Xaml.Controls.UserControl GetControl();
void UpdateSettings(Microsoft.Terminal.Settings.IControlSettings newSettings);

event TitleChangedEventArgs TitleChanged;
Expand Down
132 changes: 132 additions & 0 deletions src/cascadia/TerminalControl/TermControlAutomationPeer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include <UIAutomationCore.h>
#include "TermControlAutomationPeer.h"
#include "TermControl.h"
#include "TermControlAutomationPeer.g.cpp"

#include "XamlUiaTextRange.h"

namespace winrt::Microsoft::Terminal::TerminalControl::implementation
{
TermControlAutomationPeer::TermControlAutomationPeer(winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl const& owner) :
TermControlAutomationPeerT<TermControlAutomationPeer>(owner),
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
_uiaProvider{ owner.GetRenderData(), nullptr, std::bind(&TermControlAutomationPeer::GetBoundingRectWrapped, this) } {};

winrt::hstring TermControlAutomationPeer::GetClassNameCore() const
{
return L"TermControl";
}

AutomationControlType TermControlAutomationPeer::GetAutomationControlTypeCore() const
{
return AutomationControlType::Text;
}

winrt::hstring TermControlAutomationPeer::GetLocalizedControlTypeCore() const
{
// TODO GitHub #2142: Localize string
return L"TerminalControl";
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
}

winrt::Windows::Foundation::IInspectable TermControlAutomationPeer::GetPatternCore(PatternInterface patternInterface) const
{
switch (patternInterface)
{
case PatternInterface::Text:
return *this;
break;
default:
return nullptr;
}
}

#pragma region ITextProvider
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> TermControlAutomationPeer::GetSelection()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider.GetSelection(&pReturnVal));
return SafeArrayToComArray(pReturnVal);
}

winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> TermControlAutomationPeer::GetVisibleRanges()
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider.GetVisibleRanges(&pReturnVal));
return SafeArrayToComArray(pReturnVal);
}

Windows::UI::Xaml::Automation::Provider::ITextRangeProvider TermControlAutomationPeer::RangeFromChild(Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple childElement)
{
::ITextRangeProvider* returnVal;
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
_uiaProvider.RangeFromChild(/* IRawElementProviderSimple */ nullptr,
&returnVal);

auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>();
}

Windows::UI::Xaml::Automation::Provider::ITextRangeProvider TermControlAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
::ITextRangeProvider* returnVal;
_uiaProvider.RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal);

auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>();
}

Windows::UI::Xaml::Automation::Provider::ITextRangeProvider TermControlAutomationPeer::DocumentRange()
{
::ITextRangeProvider* returnVal;
_uiaProvider.get_DocumentRange(&returnVal);

auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>();
}

Windows::UI::Xaml::Automation::SupportedTextSelection TermControlAutomationPeer::SupportedTextSelection()
{
::SupportedTextSelection returnVal;
_uiaProvider.get_SupportedTextSelection(&returnVal);
return static_cast<Windows::UI::Xaml::Automation::SupportedTextSelection>(returnVal);
}

#pragma endregion

RECT TermControlAutomationPeer::GetBoundingRectWrapped()
{
auto rect = GetBoundingRectangle();
return {
gsl::narrow<LONG>(rect.X),
gsl::narrow<LONG>(rect.Y),
gsl::narrow<LONG>(rect.X + rect.Width),
gsl::narrow<LONG>(rect.Y + rect.Height)
};
}

winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> TermControlAutomationPeer::SafeArrayToComArray(SAFEARRAY* textRanges)
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
{
auto owningVector = SafeArrayToOwningVector<::UiaTextRange>(textRanges);
int count = owningVector.size();

std::vector<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> vec;
vec.reserve(count);
auto parentProvider = this->ProviderFromPeer(*this);
for (int i = 0; i < count; i++)
{
auto provider = owningVector[i];
auto xutr = winrt::make_self<XamlUiaTextRange>(provider.get(), parentProvider);
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
vec.emplace_back(xutr.as<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>());
}

winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> result{ vec };

return result;
}
}
Loading