Skip to content

Commit

Permalink
hook up UIA tree to WPF control
Browse files Browse the repository at this point in the history
  • Loading branch information
ZoeyR committed Feb 12, 2020
1 parent a241dbd commit 2027c0a
Show file tree
Hide file tree
Showing 19 changed files with 277 additions and 83 deletions.
112 changes: 105 additions & 7 deletions src/cascadia/PublicTerminalCore/HwndTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,40 @@

#include "pch.h"
#include "HwndTerminal.hpp"
#include "../../types/TermControlUiaProvider.hpp"
#include <DefaultSettings.h>
#include "../../renderer/base/Renderer.hpp"
#include "../../renderer/dx/DxRenderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../../types/viewport.cpp"
#include "../../types/inc/GlyphWidth.hpp"
#include <assert.h>

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
LPARAM lParam)
{
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
HwndTerminal* terminal = reinterpret_cast<HwndTerminal*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));

if (terminal)
{
switch (uMsg)
{
case WM_GETOBJECT:
if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId))
{
auto lock = terminal->_terminal->LockForWriting();
return UiaReturnRawElementProvider(hwnd, wParam, lParam, terminal->_GetUiaProvider());
}
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

static bool RegisterTermClass(HINSTANCE hInstance) noexcept
Expand All @@ -32,7 +48,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;
Expand All @@ -47,7 +63,8 @@ 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 }
{
HINSTANCE hInstance = wil::GetModuleInstanceHandle();

Expand All @@ -69,6 +86,8 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
nullptr,
hInstance,
nullptr));

SetWindowLongPtr(_hwnd.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
}
}

Expand Down Expand Up @@ -141,6 +160,16 @@ void HwndTerminal::RegisterWriteCallback(const void _stdcall callback(wchar_t*))
});
}

::Microsoft::Console::Types::IUiaData* HwndTerminal::GetUiaData() const
{
return _terminal.get();
}

HWND HwndTerminal::GetHwnd() const
{
return _hwnd.get();
}

void HwndTerminal::_UpdateFont(int newDpi)
{
auto lock = _terminal->LockForWriting();
Expand All @@ -150,6 +179,24 @@ void HwndTerminal::_UpdateFont(int newDpi)
_renderer->TriggerFontChange(newDpi, _desiredFont, _actualFont);
}

IRawElementProviderSimple* HwndTerminal::_GetUiaProvider()
{
if (nullptr == _uiaProvider)
{
try
{
THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, this->GetUiaData(), this));
}
catch (...)
{
LOG_HR(wil::ResultFromCaughtException());
_uiaProvider = nullptr;
}
}

return _uiaProvider.Get();
}

HRESULT HwndTerminal::Refresh(const SIZE windowSize, _Out_ COORD* dimensions)
{
RETURN_HR_IF_NULL(E_INVALIDARG, dimensions);
Expand Down Expand Up @@ -186,10 +233,27 @@ void HwndTerminal::SendOutput(std::wstring_view data)

HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal)
{
auto _terminal = std::make_unique<HwndTerminal>(parentHwnd);
auto _hostWindow = CreateWindowEx(
0,
L"static",
nullptr,
WS_CHILD |
WS_CLIPCHILDREN |
WS_CLIPSIBLINGS |
WS_VISIBLE,
0,
0,
0,
0,
parentHwnd,
(HMENU)0x02,
nullptr,
0
);
auto _terminal = std::make_unique<HwndTerminal>(_hostWindow);
RETURN_IF_FAILED(_terminal->Initialize());

*hwnd = _terminal->_hwnd.get();
*hwnd = _hostWindow;
*terminal = _terminal.release();

return S_OK;
Expand All @@ -216,6 +280,16 @@ void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data)
HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double height, _Out_ COORD* dimensions)
{
const auto publicTerminal = static_cast<HwndTerminal*>(terminal);

SetWindowPos(
publicTerminal->GetHwnd(),
nullptr,
0,
0,
static_cast<int>(width),
static_cast<int>(height),
0
);

const SIZE windowSize{ static_cast<short>(width), static_cast<short>(height) };
return publicTerminal->Refresh(windowSize, dimensions);
Expand Down Expand Up @@ -413,3 +487,27 @@ void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible)
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
publicTerminal->_terminal->SetCursorVisible(visible);
}

COORD HwndTerminal::GetFontSize()
{
return _actualFont.GetSize();
}

RECT HwndTerminal::GetBounds()
{
RECT windowRect;
GetWindowRect(_hwnd.get(), &windowRect);
return windowRect;
}

RECT HwndTerminal::GetPadding()
{
return {
0, 0, 0, 0,
};
}

HRESULT HwndTerminal::GetHostUiaProvider(IRawElementProviderSimple** provider)
{
return UiaHostProviderFromHwnd(_hwnd.get(), provider);
}
17 changes: 16 additions & 1 deletion src/cascadia/PublicTerminalCore/HwndTerminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include "../../renderer/base/Renderer.hpp"
#include "../../renderer/dx/DxRenderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp"
#include <UIAutomationCore.h>
#include "../../types/IControlInfo.h"
#include "../../types/TermControlUiaProvider.hpp"

using namespace Microsoft::Console::VirtualTerminal;

Expand Down Expand Up @@ -39,7 +42,7 @@ __declspec(dllexport) void _stdcall TerminalBlinkCursor(void* terminal);
__declspec(dllexport) void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible);
};

struct HwndTerminal
struct HwndTerminal : ::Microsoft::Console::Types::IControlInfo
{
public:
HwndTerminal(HWND hwnd);
Expand All @@ -48,11 +51,16 @@ struct HwndTerminal
HRESULT Refresh(const SIZE windowSize, _Out_ COORD* dimensions);
void RegisterScrollCallback(std::function<void(int, int, int)> callback);
void RegisterWriteCallback(const void _stdcall callback(wchar_t*));
::Microsoft::Console::Types::IUiaData* GetUiaData() const;
HWND GetHwnd() const;

static LRESULT CALLBACK HwndTerminalWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

private:
wil::unique_hwnd _hwnd;
FontInfoDesired _desiredFont;
FontInfo _actualFont;
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;

std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal;

Expand All @@ -74,4 +82,11 @@ struct HwndTerminal
friend void _stdcall TerminalBlinkCursor(void* terminal);
friend void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible);
void _UpdateFont(int newDpi);
IRawElementProviderSimple* _GetUiaProvider();

// Inherited via IControlInfo
virtual COORD GetFontSize() override;
virtual RECT GetBounds() override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
virtual RECT GetPadding() override;
};
12 changes: 12 additions & 0 deletions src/cascadia/PublicTerminalCore/PublicTerminalCore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
<ClCompile Include="HwndTerminal.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UiaTextRange.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TerminalControlUiaProvider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
Expand All @@ -32,5 +38,11 @@
<ClInclude Include="HwndTerminal.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UiaTextRange.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TerminalControlUiaProvider.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions src/cascadia/PublicTerminalCore/pch.h
Original file line number Diff line number Diff line change
@@ -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 <LibraryIncludes.h>
30 changes: 27 additions & 3 deletions src/cascadia/TerminalControl/TermControlAutomationPeer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ namespace XamlAutomation
namespace winrt::Microsoft::Terminal::TerminalControl::implementation
{
TermControlAutomationPeer::TermControlAutomationPeer(winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* owner) :
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner) // pass owner to FrameworkElementAutomationPeer
TermControlAutomationPeerT<TermControlAutomationPeer>(*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:
Expand Down Expand Up @@ -159,7 +160,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation

#pragma endregion

RECT TermControlAutomationPeer::GetBoundingRectWrapped()
#pragma region IControlInfo
COORD TermControlAutomationPeer::GetFontSize()
{
return _termControl->GetActualFont().GetSize();
}

RECT TermControlAutomationPeer::GetBounds()
{
auto rect = GetBoundingRectangle();
return {
Expand All @@ -170,6 +177,23 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
};
}

HRESULT TermControlAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
{
return S_OK;
}

RECT TermControlAutomationPeer::GetPadding()
{
auto padding = _termControl->GetPadding();
return {
gsl::narrow<LONG>(padding.Left),
gsl::narrow<LONG>(padding.Top),
gsl::narrow<LONG>(padding.Right),
gsl::narrow<LONG>(padding.Bottom)
}
}
#pragma endregion

// Method Description:
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
// Arguments:
Expand Down
14 changes: 12 additions & 2 deletions src/cascadia/TerminalControl/TermControlAutomationPeer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ Author(s):
#include <winrt/Microsoft.Terminal.TerminalControl.h>
#include "TermControlUiaProvider.hpp"
#include "../types/IUiaEventDispatcher.h"
#include "../types/IControlInfo.h"

namespace winrt::Microsoft::Terminal::TerminalControl::implementation
{
struct TermControlAutomationPeer :
public TermControlAutomationPeerT<TermControlAutomationPeer>,
::Microsoft::Console::Types::IUiaEventDispatcher
::Microsoft::Console::Types::IUiaEventDispatcher,
::Microsoft::Console::Types::IControlInfo,
{
public:
TermControlAutomationPeer(winrt::Microsoft::Terminal::TerminalControl::implementation::TermControl* owner);
Expand All @@ -59,11 +61,19 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider DocumentRange();
#pragma endregion

#pragma region IControlInfo Pattern
// Inherited via IControlInfo
virtual COORD GetFontSize() override;
virtual RECT GetBounds() override;
virtual RECT GetPadding() 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<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
};
}
4 changes: 0 additions & 4 deletions src/cascadia/TerminalControl/TerminalControl.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
<ClInclude Include="SearchBoxControl.h">
<DependentUpon>SearchBoxControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="TermControlUiaProvider.hpp" />
<ClInclude Include="TermControl.h">
<DependentUpon>TermControl.idl</DependentUpon>
</ClInclude>
Expand All @@ -46,7 +45,6 @@
<ClInclude Include="TSFInputControl.h">
<DependentUpon>TSFInputControl.idl</DependentUpon>
</ClInclude>
<ClInclude Include="UiaTextRange.hpp" />
<ClInclude Include="XamlUiaTextRange.h" />
</ItemGroup>
<ItemGroup>
Expand All @@ -57,7 +55,6 @@
<ClCompile Include="SearchBoxControl.cpp">
<DependentUpon>SearchBoxControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="TermControlUiaProvider.cpp" />
<ClCompile Include="TermControl.cpp">
<DependentUpon>TermControl.idl</DependentUpon>
</ClCompile>
Expand All @@ -68,7 +65,6 @@
<ClCompile Include="TermControlAutomationPeer.cpp">
<DependentUpon>TermControlAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="UiaTextRange.cpp" />
<ClCompile Include="XamlUiaTextRange.cpp" />
</ItemGroup>
<ItemGroup>
Expand Down
Loading

0 comments on commit 2027c0a

Please sign in to comment.