From b1639653aaac86551553936e58936099910cf902 Mon Sep 17 00:00:00 2001 From: schectman Date: Thu, 10 Nov 2022 13:29:26 -0500 Subject: [PATCH 01/19] Initial --- shell/platform/windows/window.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index a6fe97b0d5383..8acf50457f998 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -203,6 +203,15 @@ LRESULT Window::OnGetObject(UINT const message, if (is_uia_request && root_view) { // TODO(cbracken): https://github.com/flutter/flutter/issues/94782 // Implement when we adopt UIA support. + // Retrieve UIA object for the root view. + Microsoft::WRL::ComPtr root; + root_view->QueryInterface( + IID_PPV_ARGS(&root)); + + // Return the UIA object via UiaReturnRawElementProvider(). See: + // https://docs.microsoft.com/en-us/windows/win32/winauto/wm-getobject + reference_result = + UiaReturnRawElementProvider(window_handle_, wparam, lparam, root.Get()); } else if (is_msaa_request && root_view) { // Create the accessibility root if it does not already exist. if (!accessibility_root_) { @@ -212,10 +221,9 @@ LRESULT Window::OnGetObject(UINT const message, // Microsoft::WRL::ComPtr root(root_view); accessibility_root_->SetWindow(root_view); Microsoft::WRL::ComPtr root(accessibility_root_); - LRESULT lresult = LresultFromObject(IID_IAccessible, wparam, root.Get()); - return lresult; + reference_result = LresultFromObject(IID_IAccessible, wparam, root.Get()); } - return 0; + return reference_result; } void Window::OnImeSetContext(UINT const message, From d73603eeef0f4f4be86e0420ab757418713b38d3 Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 14 Nov 2022 10:33:55 -0500 Subject: [PATCH 02/19] Comment TODOs --- shell/platform/windows/window.cc | 16 ++++++++-------- .../ax/platform/ax_platform_node_win.cc | 11 ++++++++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index 8acf50457f998..baee7b60ae37b 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -205,14 +205,14 @@ LRESULT Window::OnGetObject(UINT const message, // Implement when we adopt UIA support. // Retrieve UIA object for the root view. Microsoft::WRL::ComPtr root; - root_view->QueryInterface( - IID_PPV_ARGS(&root)); - - // Return the UIA object via UiaReturnRawElementProvider(). See: - // https://docs.microsoft.com/en-us/windows/win32/winauto/wm-getobject - reference_result = - UiaReturnRawElementProvider(window_handle_, wparam, lparam, root.Get()); - } else if (is_msaa_request && root_view) { + if (SUCCEEDED(root_view->QueryInterface( + IID_PPV_ARGS(&root)))) { + // Return the UIA object via UiaReturnRawElementProvider(). See: + // https://docs.microsoft.com/en-us/windows/win32/winauto/wm-getobject + reference_result = + UiaReturnRawElementProvider(window_handle_, wparam, lparam, root.Get()); + } + } else if (is_msaa_request && root_view && FALSE) { // Disabled this for now to test JUST UIA // Create the accessibility root if it does not already exist. if (!accessibility_root_) { CreateAccessibilityRootNode(); diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index dad8d2739806a..2fca77ed83048 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -2155,7 +2155,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, case UIA_ControlTypePropertyId: result->vt = VT_I4; - result->lVal = ComputeUIAControlType(); + result->lVal = UIA_ButtonControlTypeId;// ComputeUIAControlType(); TODO(schectman): replace, for testing break; case UIA_CulturePropertyId: { @@ -2304,7 +2304,8 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, if (!localized_control_type.empty()) { result->vt = VT_BSTR; result->bstrVal = - ::SysAllocString(base::UTF16ToWide(localized_control_type).c_str()); + //::SysAllocString(base::UTF16ToWide(localized_control_type).c_str()); TODO(schectman): this too + ::SysAllocString(base::UTF16ToWide(u"LOCAL").c_str()); } // If a role description has not been provided, leave as VT_EMPTY. // UIA core handles Localized Control type for some built-in types and @@ -2313,10 +2314,14 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, } break; case UIA_NamePropertyId: + // For testing + result->vt = VT_BSTR; + result->bstrVal = ::SysAllocString(L"NAME PROPERTY GOES HERE"); + /*/ if (IsNameExposed()) { result->vt = VT_BSTR; GetNameAsBstr(&result->bstrVal); - } + }*/ break; case UIA_OrientationPropertyId: From 0ee4a7c991166773804530f19556a73ea4769628 Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 14 Nov 2022 11:20:16 -0500 Subject: [PATCH 03/19] Shim windowsx --- shell/platform/windows/BUILD.gn | 1 + shell/platform/windows/flutter_window.h | 3 +- shell/platform/windows/flutter_windows_view.h | 3 +- .../windows/testing/mock_text_input_manager.h | 2 +- shell/platform/windows/testing/mock_window.h | 3 +- .../testing/mock_window_binding_handler.h | 3 +- .../platform/windows/testing/test_keyboard.cc | 2 +- shell/platform/windows/testing/wm_builders.h | 3 +- shell/platform/windows/window.cc | 23 +++++++++++++-- shell/platform/windows/window.h | 19 +++++++++++-- shell/platform/windows/windowsx_shim.h | 28 +++++++++++++++++++ 11 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 shell/platform/windows/windowsx_shim.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 53b997f5847c4..42f4c16f73bf8 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -111,6 +111,7 @@ source_set("flutter_windows_source") { "windows_proc_table.h", "windows_registry.cc", "windows_registry.h", + "windowsx_shim.h", ] libs = [ diff --git a/shell/platform/windows/flutter_window.h b/shell/platform/windows/flutter_window.h index b8f3183bcbd4f..6072103f1956b 100644 --- a/shell/platform/windows/flutter_window.h +++ b/shell/platform/windows/flutter_window.h @@ -5,8 +5,6 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOW_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOW_H_ -#include - #include #include #include @@ -16,6 +14,7 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/window.h" #include "flutter/shell/platform/windows/window_binding_handler.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" namespace flutter { diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 1c7d721e2f5eb..19afd47baf877 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -5,8 +5,6 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_ -#include - #include #include #include @@ -28,6 +26,7 @@ #include "flutter/shell/platform/windows/window_binding_handler.h" #include "flutter/shell/platform/windows/window_binding_handler_delegate.h" #include "flutter/shell/platform/windows/window_state.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" namespace flutter { diff --git a/shell/platform/windows/testing/mock_text_input_manager.h b/shell/platform/windows/testing/mock_text_input_manager.h index 7fefa1ae25170..13e2427ca6b58 100644 --- a/shell/platform/windows/testing/mock_text_input_manager.h +++ b/shell/platform/windows/testing/mock_text_input_manager.h @@ -5,11 +5,11 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_TEXT_INPUT_MANAGER_WIN32_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_TEXT_INPUT_MANAGER_WIN32_H_ -#include #include #include #include "flutter/shell/platform/windows/text_input_manager.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" #include "gmock/gmock.h" namespace flutter { diff --git a/shell/platform/windows/testing/mock_window.h b/shell/platform/windows/testing/mock_window.h index fc50235745e3b..debc363e7fec4 100644 --- a/shell/platform/windows/testing/mock_window.h +++ b/shell/platform/windows/testing/mock_window.h @@ -5,10 +5,9 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WIN32_WINDOW_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WIN32_WINDOW_H_ -#include - #include "flutter/shell/platform/windows/testing/test_keyboard.h" #include "flutter/shell/platform/windows/window.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" #include "gmock/gmock.h" namespace flutter { diff --git a/shell/platform/windows/testing/mock_window_binding_handler.h b/shell/platform/windows/testing/mock_window_binding_handler.h index dcbbc9e15f2a6..04ebf734782cf 100644 --- a/shell/platform/windows/testing/mock_window_binding_handler.h +++ b/shell/platform/windows/testing/mock_window_binding_handler.h @@ -5,9 +5,8 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOW_BINDING_HANDLER_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOW_BINDING_HANDLER_H_ -#include - #include "flutter/shell/platform/windows/window_binding_handler.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" #include "gmock/gmock.h" namespace flutter { diff --git a/shell/platform/windows/testing/test_keyboard.cc b/shell/platform/windows/testing/test_keyboard.cc index 06a5b86c38409..b034c32708a77 100644 --- a/shell/platform/windows/testing/test_keyboard.cc +++ b/shell/platform/windows/testing/test_keyboard.cc @@ -3,11 +3,11 @@ // found in the LICENSE file. #include "flutter/shell/platform/windows/testing/test_keyboard.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" #include "flutter/shell/platform/common/json_message_codec.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include -#include namespace flutter { namespace testing { diff --git a/shell/platform/windows/testing/wm_builders.h b/shell/platform/windows/testing/wm_builders.h index 6f93b13d1c61a..a60732394afe2 100644 --- a/shell/platform/windows/testing/wm_builders.h +++ b/shell/platform/windows/testing/wm_builders.h @@ -7,7 +7,8 @@ #include #include -#include + +#include "flutter/shell/platform/windows/windowsx_shim.h" namespace flutter { namespace testing { diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index baee7b60ae37b..0cc260e83679b 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -59,7 +59,8 @@ Window::Window(std::unique_ptr windows_proc_table, : touch_id_generator_(kMinTouchDeviceId, kMaxTouchDeviceId), windows_proc_table_(std::move(windows_proc_table)), text_input_manager_(std::move(text_input_manager)), - accessibility_root_(nullptr) { + accessibility_root_(nullptr), + ax_fragment_root_(nullptr) { // Get the DPI of the primary monitor as the initial DPI. If Per-Monitor V2 is // supported, |current_dpi_| should be updated in the // kWmDpiChangedBeforeParent message. @@ -201,18 +202,22 @@ LRESULT Window::OnGetObject(UINT const message, gfx::NativeViewAccessible root_view = GetNativeViewAccessible(); if (is_uia_request && root_view) { + if (!ax_fragment_root_) { + ax_fragment_root_ = std::make_unique(window_handle_, this); + } + // TODO(cbracken): https://github.com/flutter/flutter/issues/94782 // Implement when we adopt UIA support. // Retrieve UIA object for the root view. Microsoft::WRL::ComPtr root; - if (SUCCEEDED(root_view->QueryInterface( + if (SUCCEEDED(ax_fragment_root_->GetNativeViewAccessible()->QueryInterface( IID_PPV_ARGS(&root)))) { // Return the UIA object via UiaReturnRawElementProvider(). See: // https://docs.microsoft.com/en-us/windows/win32/winauto/wm-getobject reference_result = UiaReturnRawElementProvider(window_handle_, wparam, lparam, root.Get()); } - } else if (is_msaa_request && root_view && FALSE) { // Disabled this for now to test JUST UIA + } else if (is_msaa_request && root_view) { // Create the accessibility root if it does not already exist. if (!accessibility_root_) { CreateAccessibilityRootNode(); @@ -666,4 +671,16 @@ void Window::CreateAccessibilityRootNode() { accessibility_root_ = AccessibilityRootNode::Create(); } +gfx::NativeViewAccessible Window::GetChildOfAXFragmentRoot() { + return GetNativeViewAccessible(); +} + +gfx::NativeViewAccessible Window::GetParentOfAXFragmentRoot() { + return nullptr; +} + +bool Window::IsAXFragmentRootAControlElement() { + return true; +} + } // namespace flutter diff --git a/shell/platform/windows/window.h b/shell/platform/windows/window.h index ee9af55950b59..1af38d1ddf362 100644 --- a/shell/platform/windows/window.h +++ b/shell/platform/windows/window.h @@ -6,7 +6,6 @@ #define FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WIN32_WINDOW_H_ #include -#include #include #include @@ -20,14 +19,18 @@ #include "flutter/shell/platform/windows/sequential_id_generator.h" #include "flutter/shell/platform/windows/text_input_manager.h" #include "flutter/shell/platform/windows/windows_proc_table.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" #include "flutter/third_party/accessibility/gfx/native_widget_types.h" +#include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_delegate_win.h" +#include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_win.h" namespace flutter { // A class abstraction for a high DPI aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling. -class Window : public KeyboardManager::WindowDelegate { +class Window : public KeyboardManager::WindowDelegate, + public ui::AXFragmentRootDelegateWin { public: Window(); Window(std::unique_ptr windows_proc_table, @@ -211,6 +214,15 @@ class Window : public KeyboardManager::WindowDelegate { // Check if the high contrast feature is enabled on the OS virtual bool GetHighContrastEnabled(); + // | AXFragmentRootDelegateWin | + gfx::NativeViewAccessible GetChildOfAXFragmentRoot() override; + + // | AXFragmentRootDelegateWin | + gfx::NativeViewAccessible GetParentOfAXFragmentRoot() override; + + // | AXFragmentRootDelegateWin | + bool IsAXFragmentRootAControlElement() override; + protected: // Win32's DefWindowProc. // @@ -299,6 +311,9 @@ class Window : public KeyboardManager::WindowDelegate { // Timer identifier for DirectManipulation gesture polling. const static int kDirectManipulationTimer = 1; + + // Implements IRawElementProviderFragmentRoot when UIA is enabled. + std::unique_ptr ax_fragment_root_; }; } // namespace flutter diff --git a/shell/platform/windows/windowsx_shim.h b/shell/platform/windows/windowsx_shim.h new file mode 100644 index 0000000000000..2e3a88fc0522b --- /dev/null +++ b/shell/platform/windows/windowsx_shim.h @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_WIN_WINDOWSX_SHIM_H_ +#define BASE_WIN_WINDOWSX_SHIM_H_ + +// The Win32 platform header contains some macros for +// common function names. To work around that, windowsx.h is not to be +// included directly, and instead this file should be included. If one +// of the removed Win32 macros is wanted, use the expanded form +// manually instead. + +#ifdef _INC_WINDOWS_X +#error "There is an include of windowsx.h in the code. Use windowsx_shim.h" +#endif // _INC_WINDOWS_X + +#include + +#undef GetNextSibling // Same as GetWindow(hwnd, GW_HWNDNEXT) +#undef GetFirstChild // Same as GetTopWindow(hwnd) +#undef IsMaximized // Defined to IsZoomed, use IsZoomed directly instead +#undef IsMinimized // Defined to IsIconic, use IsIconic directly instead +#undef IsRestored // Macro to check that neither WS_MINIMIZE, nor + // WS_MAXIMIZE is set in the GetWindowStyle return + // value. + +#endif // BASE_WIN_WINDOWSX_SHIM_H_ From 18aef209c51950bdc68bc2c03d71bec626b12f4d Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 14 Nov 2022 13:03:36 -0500 Subject: [PATCH 04/19] Comment testing --- .../accessibility/ax/platform/ax_platform_node_win.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index 2fca77ed83048..9421175e2a130 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -2155,7 +2155,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, case UIA_ControlTypePropertyId: result->vt = VT_I4; - result->lVal = UIA_ButtonControlTypeId;// ComputeUIAControlType(); TODO(schectman): replace, for testing + result->lVal = ComputeUIAControlType(); //TODO(schectman): replace, for testing break; case UIA_CulturePropertyId: { @@ -2304,8 +2304,8 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, if (!localized_control_type.empty()) { result->vt = VT_BSTR; result->bstrVal = - //::SysAllocString(base::UTF16ToWide(localized_control_type).c_str()); TODO(schectman): this too - ::SysAllocString(base::UTF16ToWide(u"LOCAL").c_str()); + ::SysAllocString(base::UTF16ToWide(localized_control_type).c_str()); // TODO(schectman): this too + //::SysAllocString(base::UTF16ToWide(u"LOCAL").c_str()); } // If a role description has not been provided, leave as VT_EMPTY. // UIA core handles Localized Control type for some built-in types and From 0406379c3589059a04ad7ec60533fc05396bd508 Mon Sep 17 00:00:00 2001 From: schectman Date: Wed, 16 Nov 2022 12:06:24 -0500 Subject: [PATCH 05/19] UIA works at most basic --- .../common/flutter_platform_node_delegate.h | 1 - .../flutter_platform_node_delegate_windows.cc | 5 +++ .../flutter_platform_node_delegate_windows.h | 3 ++ shell/platform/windows/window.cc | 19 +++++++--- shell/platform/windows/window.h | 38 +++++++++++++------ .../accessibility/ax/ax_active_popup.cc | 2 +- .../ax/platform/ax_fragment_root_win.cc | 11 ++++++ .../ax/platform/ax_fragment_root_win.h | 2 + .../ax/platform/ax_platform_node_win.cc | 11 ++---- 9 files changed, 65 insertions(+), 27 deletions(-) diff --git a/shell/platform/common/flutter_platform_node_delegate.h b/shell/platform/common/flutter_platform_node_delegate.h index 2878fe45afe92..30b81c5b5d200 100644 --- a/shell/platform/common/flutter_platform_node_delegate.h +++ b/shell/platform/common/flutter_platform_node_delegate.h @@ -143,7 +143,6 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase { /// platform node delegate. This pointer is only safe in the /// platform thread. std::weak_ptr GetOwnerBridge() const; - private: ui::AXNode* ax_node_; std::weak_ptr bridge_; diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.cc b/shell/platform/windows/flutter_platform_node_delegate_windows.cc index 5f5ad62d4adcd..1a18fb600f8cc 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.cc +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.cc @@ -10,6 +10,7 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/third_party/accessibility/ax/ax_clipping_behavior.h" #include "flutter/third_party/accessibility/ax/ax_coordinate_system.h" +#include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_win.h" namespace flutter { @@ -107,4 +108,8 @@ void FlutterPlatformNodeDelegateWindows::SetFocus() { GetNativeViewAccessible()->accSelect(SELFLAG_TAKEFOCUS, varchild); } +gfx::AcceleratedWidget FlutterPlatformNodeDelegateWindows::GetTargetForNativeAccessibilityEvent() { + return ui::GetDefaultTarget(); +} + } // namespace flutter diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.h b/shell/platform/windows/flutter_platform_node_delegate_windows.h index 8bac155b9c14d..f7942efdcaed9 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.h +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.h @@ -48,6 +48,9 @@ class FlutterPlatformNodeDelegateWindows : public FlutterPlatformNodeDelegate { // this object. void SetFocus(); + // | AXPlatformNodeDelegate | + gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; + private: ui::AXPlatformNode* ax_platform_node_; std::weak_ptr bridge_; diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index 0cc260e83679b..a963e49115f01 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -203,7 +203,10 @@ LRESULT Window::OnGetObject(UINT const message, gfx::NativeViewAccessible root_view = GetNativeViewAccessible(); if (is_uia_request && root_view) { if (!ax_fragment_root_) { - ax_fragment_root_ = std::make_unique(window_handle_, this); + if (!ax_fragment_delegate_) { + ax_fragment_delegate_ = std::make_unique(*this); + } + ax_fragment_root_ = std::make_unique(window_handle_, ax_fragment_delegate_.get()); } // TODO(cbracken): https://github.com/flutter/flutter/issues/94782 @@ -216,8 +219,10 @@ LRESULT Window::OnGetObject(UINT const message, // https://docs.microsoft.com/en-us/windows/win32/winauto/wm-getobject reference_result = UiaReturnRawElementProvider(window_handle_, wparam, lparam, root.Get()); + } else { + FML_LOG(ERROR) << "Failed to query AX fragment root."; } - } else if (is_msaa_request && root_view) { + } else if (is_msaa_request && root_view && FALSE) { // TODO(schectman) revert this FALSE check; it's just for testing // Create the accessibility root if it does not already exist. if (!accessibility_root_) { CreateAccessibilityRootNode(); @@ -671,16 +676,18 @@ void Window::CreateAccessibilityRootNode() { accessibility_root_ = AccessibilityRootNode::Create(); } -gfx::NativeViewAccessible Window::GetChildOfAXFragmentRoot() { - return GetNativeViewAccessible(); +gfx::NativeViewAccessible WindowAXFragmentRootDelegate::GetChildOfAXFragmentRoot() { + return window_.GetNativeViewAccessible(); } -gfx::NativeViewAccessible Window::GetParentOfAXFragmentRoot() { +gfx::NativeViewAccessible WindowAXFragmentRootDelegate::GetParentOfAXFragmentRoot() { return nullptr; } -bool Window::IsAXFragmentRootAControlElement() { +bool WindowAXFragmentRootDelegate::IsAXFragmentRootAControlElement() { return true; } +WindowAXFragmentRootDelegate::WindowAXFragmentRootDelegate(Window& window) : window_(window) {} + } // namespace flutter diff --git a/shell/platform/windows/window.h b/shell/platform/windows/window.h index 1af38d1ddf362..b95c0ebf001bb 100644 --- a/shell/platform/windows/window.h +++ b/shell/platform/windows/window.h @@ -26,11 +26,12 @@ namespace flutter { +class WindowAXFragmentRootDelegate; + // A class abstraction for a high DPI aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling. -class Window : public KeyboardManager::WindowDelegate, - public ui::AXFragmentRootDelegateWin { +class Window : public KeyboardManager::WindowDelegate { public: Window(); Window(std::unique_ptr windows_proc_table, @@ -214,15 +215,6 @@ class Window : public KeyboardManager::WindowDelegate, // Check if the high contrast feature is enabled on the OS virtual bool GetHighContrastEnabled(); - // | AXFragmentRootDelegateWin | - gfx::NativeViewAccessible GetChildOfAXFragmentRoot() override; - - // | AXFragmentRootDelegateWin | - gfx::NativeViewAccessible GetParentOfAXFragmentRoot() override; - - // | AXFragmentRootDelegateWin | - bool IsAXFragmentRootAControlElement() override; - protected: // Win32's DefWindowProc. // @@ -314,6 +306,30 @@ class Window : public KeyboardManager::WindowDelegate, // Implements IRawElementProviderFragmentRoot when UIA is enabled. std::unique_ptr ax_fragment_root_; + + // Delegate for Fragment. + std::unique_ptr ax_fragment_delegate_; + + // Allow WindowAXFragmentRootDelegate to access protected method. + friend class WindowAXFragmentRootDelegate; +}; + +// A delegate class to the window. +class WindowAXFragmentRootDelegate : public ui::AXFragmentRootDelegateWin { + public: + // | AXFragmentRootDelegateWin | + gfx::NativeViewAccessible GetChildOfAXFragmentRoot() override; + + // | AXFragmentRootDelegateWin | + gfx::NativeViewAccessible GetParentOfAXFragmentRoot() override; + + // | AXFragmentRootDelegateWin | + bool IsAXFragmentRootAControlElement() override; + + WindowAXFragmentRootDelegate(Window& window); + + private: + Window& window_; }; } // namespace flutter diff --git a/third_party/accessibility/ax/ax_active_popup.cc b/third_party/accessibility/ax/ax_active_popup.cc index 904de75c4bbb0..a20cbc2ec2a05 100644 --- a/third_party/accessibility/ax/ax_active_popup.cc +++ b/third_party/accessibility/ax/ax_active_popup.cc @@ -15,7 +15,7 @@ namespace ui { static std::optional g_active_popup_ax_unique_id; std::optional GetActivePopupAxUniqueId() { - return *g_active_popup_ax_unique_id; + return g_active_popup_ax_unique_id; // TODO(schectman) pretty sure this shouldn't be dereferenced... } void SetActivePopupAxUniqueId(std::optional ax_unique_id) { diff --git a/third_party/accessibility/ax/platform/ax_fragment_root_win.cc b/third_party/accessibility/ax/platform/ax_fragment_root_win.cc index d6abe02c3e2c7..2c96d0898596a 100644 --- a/third_party/accessibility/ax/platform/ax_fragment_root_win.cc +++ b/third_party/accessibility/ax/platform/ax_fragment_root_win.cc @@ -283,6 +283,11 @@ class AXFragmentRootMapWin { return nullptr; } + std::pair GetDefaultIterator() { + const auto& entry = map_.begin(); + return {entry->first, entry->second}; + } + private: std::unordered_map map_; }; @@ -425,4 +430,10 @@ int AXFragmentRootWin::GetIndexInParentOfChild() const { return 0; } +gfx::AcceleratedWidget GetDefaultTarget() { + AXFragmentRootMapWin& map = AXFragmentRootMapWin::GetInstance(); + auto pair = map.GetDefaultIterator(); + return pair.first; +} + } // namespace ui diff --git a/third_party/accessibility/ax/platform/ax_fragment_root_win.h b/third_party/accessibility/ax/platform/ax_fragment_root_win.h index ec357d4dffbff..95600d035fd80 100644 --- a/third_party/accessibility/ax/platform/ax_fragment_root_win.h +++ b/third_party/accessibility/ax/platform/ax_fragment_root_win.h @@ -84,6 +84,8 @@ class AX_EXPORT AXFragmentRootWin : public ui::AXPlatformNodeDelegateBase { ui::AXUniqueId unique_id_; }; +gfx::AcceleratedWidget GetDefaultTarget(); + } // namespace ui #endif // UI_ACCESSIBILITY_PLATFORM_AX_FRAGMENT_ROOT_WIN_H_ diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index 9421175e2a130..dad8d2739806a 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -2155,7 +2155,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, case UIA_ControlTypePropertyId: result->vt = VT_I4; - result->lVal = ComputeUIAControlType(); //TODO(schectman): replace, for testing + result->lVal = ComputeUIAControlType(); break; case UIA_CulturePropertyId: { @@ -2304,8 +2304,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, if (!localized_control_type.empty()) { result->vt = VT_BSTR; result->bstrVal = - ::SysAllocString(base::UTF16ToWide(localized_control_type).c_str()); // TODO(schectman): this too - //::SysAllocString(base::UTF16ToWide(u"LOCAL").c_str()); + ::SysAllocString(base::UTF16ToWide(localized_control_type).c_str()); } // If a role description has not been provided, leave as VT_EMPTY. // UIA core handles Localized Control type for some built-in types and @@ -2314,14 +2313,10 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, } break; case UIA_NamePropertyId: - // For testing - result->vt = VT_BSTR; - result->bstrVal = ::SysAllocString(L"NAME PROPERTY GOES HERE"); - /*/ if (IsNameExposed()) { result->vt = VT_BSTR; GetNameAsBstr(&result->bstrVal); - }*/ + } break; case UIA_OrientationPropertyId: From 86872540685e27320bbead9be83c0621c064a7d0 Mon Sep 17 00:00:00 2001 From: schectman Date: Wed, 16 Nov 2022 14:34:28 -0500 Subject: [PATCH 06/19] Get Native target in win delegate --- .../windows/flutter_platform_node_delegate_windows.cc | 2 +- .../accessibility/ax/platform/ax_fragment_root_win.cc | 11 ----------- .../accessibility/ax/platform/ax_fragment_root_win.h | 2 -- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.cc b/shell/platform/windows/flutter_platform_node_delegate_windows.cc index 1a18fb600f8cc..7dc37b002f769 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.cc +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.cc @@ -109,7 +109,7 @@ void FlutterPlatformNodeDelegateWindows::SetFocus() { } gfx::AcceleratedWidget FlutterPlatformNodeDelegateWindows::GetTargetForNativeAccessibilityEvent() { - return ui::GetDefaultTarget(); + return view_->GetPlatformWindow(); } } // namespace flutter diff --git a/third_party/accessibility/ax/platform/ax_fragment_root_win.cc b/third_party/accessibility/ax/platform/ax_fragment_root_win.cc index 2c96d0898596a..d6abe02c3e2c7 100644 --- a/third_party/accessibility/ax/platform/ax_fragment_root_win.cc +++ b/third_party/accessibility/ax/platform/ax_fragment_root_win.cc @@ -283,11 +283,6 @@ class AXFragmentRootMapWin { return nullptr; } - std::pair GetDefaultIterator() { - const auto& entry = map_.begin(); - return {entry->first, entry->second}; - } - private: std::unordered_map map_; }; @@ -430,10 +425,4 @@ int AXFragmentRootWin::GetIndexInParentOfChild() const { return 0; } -gfx::AcceleratedWidget GetDefaultTarget() { - AXFragmentRootMapWin& map = AXFragmentRootMapWin::GetInstance(); - auto pair = map.GetDefaultIterator(); - return pair.first; -} - } // namespace ui diff --git a/third_party/accessibility/ax/platform/ax_fragment_root_win.h b/third_party/accessibility/ax/platform/ax_fragment_root_win.h index 95600d035fd80..ec357d4dffbff 100644 --- a/third_party/accessibility/ax/platform/ax_fragment_root_win.h +++ b/third_party/accessibility/ax/platform/ax_fragment_root_win.h @@ -84,8 +84,6 @@ class AX_EXPORT AXFragmentRootWin : public ui::AXPlatformNodeDelegateBase { ui::AXUniqueId unique_id_; }; -gfx::AcceleratedWidget GetDefaultTarget(); - } // namespace ui #endif // UI_ACCESSIBILITY_PLATFORM_AX_FRAGMENT_ROOT_WIN_H_ From 405ab9825662ec2793fc02666746ad8ff3099cc8 Mon Sep 17 00:00:00 2001 From: schectman Date: Thu, 17 Nov 2022 15:28:21 -0500 Subject: [PATCH 07/19] Rework events --- .../windows/accessibility_bridge_windows.cc | 53 +++++++++++++------ .../windows/accessibility_bridge_windows.h | 2 +- .../accessibility_bridge_windows_unittests.cc | 34 ++++++------ .../flutter_platform_node_delegate_windows.cc | 8 ++- .../flutter_platform_node_delegate_windows.h | 2 +- shell/platform/windows/window.cc | 2 +- .../ax/platform/ax_platform_node_win.cc | 4 ++ 7 files changed, 66 insertions(+), 39 deletions(-) diff --git a/shell/platform/windows/accessibility_bridge_windows.cc b/shell/platform/windows/accessibility_bridge_windows.cc index add1fc7f7c036..422942d964a25 100644 --- a/shell/platform/windows/accessibility_bridge_windows.cc +++ b/shell/platform/windows/accessibility_bridge_windows.cc @@ -31,53 +31,72 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent( switch (event_type) { case ui::AXEventGenerator::Event::ALERT: - DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_ALERT); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kAlert); + // DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_ALERT); break; case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); break; case ui::AXEventGenerator::Event::CHILDREN_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_REORDER); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kChildrenChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_REORDER); + break; + case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kDocumentSelectionChanged); break; case ui::AXEventGenerator::Event::FOCUS_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_FOCUS); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kFocus); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_FOCUS); SetFocus(win_delegate); break; case ui::AXEventGenerator::Event::IGNORED_CHANGED: if (ax_node->IsIgnored()) { - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_HIDE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kHide); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_HIDE); } break; case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_NAMECHANGE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kTextChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_NAMECHANGE); break; case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, - EVENT_OBJECT_LIVEREGIONCHANGED); + ax::mojom::Event::kLiveRegionChanged); + /*DispatchWinAccessibilityEvent(win_delegate, + EVENT_OBJECT_LIVEREGIONCHANGED);*/ break; case ui::AXEventGenerator::Event::NAME_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_NAMECHANGE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kTextChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_NAMECHANGE); break; case ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_SCROLLINGEND); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kScrollPositionChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_SCROLLINGEND); break; case ui::AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_SCROLLINGEND); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kScrollPositionChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_SCROLLINGEND); break; case ui::AXEventGenerator::Event::SELECTED_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); break; case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_SELECTIONWITHIN); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kSelectedChildrenChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_SELECTIONWITHIN); break; case ui::AXEventGenerator::Event::SUBTREE_CREATED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_SHOW); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kShow); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_SHOW); break; case ui::AXEventGenerator::Event::VALUE_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); break; case ui::AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_STATECHANGE); + DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kStateChanged); + //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_STATECHANGE); break; case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED: case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED: @@ -90,7 +109,6 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent( case ui::AXEventGenerator::Event::CONTROLS_CHANGED: case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED: case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED: - case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED: case ui::AXEventGenerator::Event::DROPEFFECT_CHANGED: case ui::AXEventGenerator::Event::ENABLED_CHANGED: @@ -151,7 +169,8 @@ AccessibilityBridgeWindows::CreateFlutterPlatformNodeDelegate() { void AccessibilityBridgeWindows::DispatchWinAccessibilityEvent( std::shared_ptr node_delegate, - DWORD event_type) { + ax::mojom::Event event_type) { + // TODO(schectman) change FlutterPlatformNodeDelegateWindows method too node_delegate->DispatchWinAccessibilityEvent(event_type); } diff --git a/shell/platform/windows/accessibility_bridge_windows.h b/shell/platform/windows/accessibility_bridge_windows.h index 68f75298a83e9..463d3aec0ac91 100644 --- a/shell/platform/windows/accessibility_bridge_windows.h +++ b/shell/platform/windows/accessibility_bridge_windows.h @@ -41,7 +41,7 @@ class AccessibilityBridgeWindows : public AccessibilityBridge { // This is a virtual method for the convenience of unit tests. virtual void DispatchWinAccessibilityEvent( std::shared_ptr node_delegate, - DWORD event_type); + ax::mojom::Event event_type); // Sets the accessibility focus to the accessibility node associated with the // specified semantics node. diff --git a/shell/platform/windows/accessibility_bridge_windows_unittests.cc b/shell/platform/windows/accessibility_bridge_windows_unittests.cc index 2dae9d8b41e01..cb185aa5dc8f5 100644 --- a/shell/platform/windows/accessibility_bridge_windows_unittests.cc +++ b/shell/platform/windows/accessibility_bridge_windows_unittests.cc @@ -29,7 +29,7 @@ namespace { // A structure representing a Win32 MSAA event targeting a specified node. struct MsaaEvent { std::shared_ptr node_delegate; - DWORD event_type; + ax::mojom::Event event_type; }; // Accessibility bridge delegate that captures events dispatched to the OS. @@ -43,7 +43,7 @@ class AccessibilityBridgeWindowsSpy : public AccessibilityBridgeWindows { void DispatchWinAccessibilityEvent( std::shared_ptr node_delegate, - DWORD event_type) override { + ax::mojom::Event event_type) override { dispatched_events_.push_back({node_delegate, event_type}); } @@ -169,7 +169,7 @@ std::shared_ptr GetAccessibilityBridgeSpy( void ExpectWinEventFromAXEvent(int32_t node_id, ui::AXEventGenerator::Event ax_event, - DWORD expected_event) { + ax::mojom::Event expected_event) { auto window_binding_handler = std::make_unique<::testing::NiceMock>(); FlutterWindowsView view(std::move(window_binding_handler)); @@ -246,12 +246,12 @@ TEST(AccessibilityBridgeWindows, DispatchAccessibilityAction) { TEST(AccessibilityBridgeWindows, OnAccessibilityEventAlert) { ExpectWinEventFromAXEvent(0, ui::AXEventGenerator::Event::ALERT, - EVENT_SYSTEM_ALERT); + ax::mojom::Event::kAlert); } TEST(AccessibilityBridgeWindows, OnAccessibilityEventChildrenChanged) { ExpectWinEventFromAXEvent(0, ui::AXEventGenerator::Event::CHILDREN_CHANGED, - EVENT_OBJECT_REORDER); + ax::mojom::Event::kChildrenChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilityEventFocusChanged) { @@ -270,7 +270,7 @@ TEST(AccessibilityBridgeWindows, OnAccessibilityEventFocusChanged) { ax::mojom::EventFrom::kNone, {}}}); ASSERT_EQ(bridge->dispatched_events().size(), 1); - EXPECT_EQ(bridge->dispatched_events()[0].event_type, EVENT_OBJECT_FOCUS); + EXPECT_EQ(bridge->dispatched_events()[0].event_type, ax::mojom::Event::kFocus); ASSERT_EQ(bridge->focused_nodes().size(), 1); EXPECT_EQ(bridge->focused_nodes()[0], 1); @@ -279,62 +279,62 @@ TEST(AccessibilityBridgeWindows, OnAccessibilityEventFocusChanged) { TEST(AccessibilityBridgeWindows, OnAccessibilityEventIgnoredChanged) { // Static test nodes with no text, hint, or scrollability are ignored. ExpectWinEventFromAXEvent(4, ui::AXEventGenerator::Event::IGNORED_CHANGED, - EVENT_OBJECT_HIDE); + ax::mojom::Event::kHide); } TEST(AccessibilityBridgeWindows, OnAccessibilityImageAnnotationChanged) { ExpectWinEventFromAXEvent( 1, ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED, - EVENT_OBJECT_NAMECHANGE); + ax::mojom::Event::kTextChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilityLiveRegionChanged) { ExpectWinEventFromAXEvent(1, ui::AXEventGenerator::Event::LIVE_REGION_CHANGED, - EVENT_OBJECT_LIVEREGIONCHANGED); + ax::mojom::Event::kLiveRegionChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilityNameChanged) { ExpectWinEventFromAXEvent(1, ui::AXEventGenerator::Event::NAME_CHANGED, - EVENT_OBJECT_NAMECHANGE); + ax::mojom::Event::kTextChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilityHScrollPosChanged) { ExpectWinEventFromAXEvent( 1, ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED, - EVENT_SYSTEM_SCROLLINGEND); + ax::mojom::Event::kScrollPositionChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilityVScrollPosChanged) { ExpectWinEventFromAXEvent( 1, ui::AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED, - EVENT_SYSTEM_SCROLLINGEND); + ax::mojom::Event::kScrollPositionChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilitySelectedChanged) { ExpectWinEventFromAXEvent(1, ui::AXEventGenerator::Event::SELECTED_CHANGED, - EVENT_OBJECT_VALUECHANGE); + ax::mojom::Event::kValueChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilitySelectedChildrenChanged) { ExpectWinEventFromAXEvent( 2, ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED, - EVENT_OBJECT_SELECTIONWITHIN); + ax::mojom::Event::kSelectedChildrenChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilitySubtreeCreated) { ExpectWinEventFromAXEvent(0, ui::AXEventGenerator::Event::SUBTREE_CREATED, - EVENT_OBJECT_SHOW); + ax::mojom::Event::kShow); } TEST(AccessibilityBridgeWindows, OnAccessibilityValueChanged) { ExpectWinEventFromAXEvent(1, ui::AXEventGenerator::Event::VALUE_CHANGED, - EVENT_OBJECT_VALUECHANGE); + ax::mojom::Event::kValueChanged); } TEST(AccessibilityBridgeWindows, OnAccessibilityStateChanged) { ExpectWinEventFromAXEvent( 1, ui::AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED, - EVENT_OBJECT_STATECHANGE); + ax::mojom::Event::kStateChanged); } } // namespace testing diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.cc b/shell/platform/windows/flutter_platform_node_delegate_windows.cc index 7dc37b002f769..27e0e0e994b08 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.cc +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.cc @@ -91,14 +91,18 @@ gfx::Rect FlutterPlatformNodeDelegateWindows::GetBoundsRect( } void FlutterPlatformNodeDelegateWindows::DispatchWinAccessibilityEvent( - DWORD event_type) { + ax::mojom::Event event_type) { + ax_platform_node_->NotifyAccessibilityEvent(event_type); + + /* HWND hwnd = view_->GetPlatformWindow(); if (!hwnd) { return; } assert(ax_platform_node_); ::NotifyWinEvent(event_type, hwnd, OBJID_CLIENT, - -ax_platform_node_->GetUniqueId()); + -ax_platform_node_->GetUniqueId());*/ + // TODO(schectman) this may be a good place to call NotifyAccessibilityEvent, if I change the input param to use mojom events. } void FlutterPlatformNodeDelegateWindows::SetFocus() { diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.h b/shell/platform/windows/flutter_platform_node_delegate_windows.h index f7942efdcaed9..364411cfffeab 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.h +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.h @@ -42,7 +42,7 @@ class FlutterPlatformNodeDelegateWindows : public FlutterPlatformNodeDelegate { // Dispatches a Windows accessibility event of the specified type, generated // by the accessibility node associated with this object. This is a // convenience wrapper around |NotifyWinEvent|. - virtual void DispatchWinAccessibilityEvent(DWORD event_type); + virtual void DispatchWinAccessibilityEvent(ax::mojom::Event event_type); // Sets the accessibility focus to the accessibility node associated with // this object. diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index a963e49115f01..81bb1e97ba19c 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -222,7 +222,7 @@ LRESULT Window::OnGetObject(UINT const message, } else { FML_LOG(ERROR) << "Failed to query AX fragment root."; } - } else if (is_msaa_request && root_view && FALSE) { // TODO(schectman) revert this FALSE check; it's just for testing + } else if (is_msaa_request && root_view) { // TODO(schectman) revert this FALSE check; it's just for testing // Create the accessibility root if it does not already exist. if (!accessibility_root_) { CreateAccessibilityRootNode(); diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index dad8d2739806a..da862672a842c 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -5216,6 +5216,8 @@ std::optional AXPlatformNodeWin::MojoEventToUIAEvent( switch (event) { case ax::mojom::Event::kAlert: return UIA_SystemAlertEventId; + case ax::mojom::Event::kDocumentSelectionChanged: + return UIA_Text_TextChangedEventId; case ax::mojom::Event::kFocus: case ax::mojom::Event::kFocusContext: case ax::mojom::Event::kFocusAfterMenuClose: @@ -5582,6 +5584,8 @@ AXPlatformNodeWin::GetPatternProviderFactoryMethod(PATTERNID pattern_id) { } break; + // TODO(schectman) add implementations for text and textchild + case UIA_TogglePatternId: if (SupportsToggle(data.role)) { return &PatternProvider; From 30ed86c332d01a857e1a8878a1a248569b1f27db Mon Sep 17 00:00:00 2001 From: schectman Date: Thu, 17 Nov 2022 17:13:28 -0500 Subject: [PATCH 08/19] FlutterWindowsView unit tests for UIA --- .../windows/flutter_windows_view_unittests.cc | 86 +++++++++++++++++++ .../ax/platform/ax_platform_node_win.cc | 13 +++ 2 files changed, 99 insertions(+) diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index f2699206f0daf..efafc175ecf07 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -231,6 +232,31 @@ TEST(FlutterWindowsView, AddSemanticsNodeUpdate) { varrole.vt = VT_I4; ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK); EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT); + + // Get the IRawElementProviderFragment object. + IRawElementProviderSimple* uia_view; + native_view->QueryInterface(IID_PPV_ARGS(&uia_view)); + ASSERT_TRUE(uia_view != nullptr); + + // Verify name property matches our label. + VARIANT varname{}; + ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK); + EXPECT_EQ(varname.vt, VT_BSTR); + name = _com_util::ConvertBSTRToString(varname.bstrVal); + EXPECT_EQ(name, "name"); + + // Verify value property matches our label. + VARIANT varvalue{}; + ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue), S_OK); + EXPECT_EQ(varvalue.vt, VT_BSTR); + value = _com_util::ConvertBSTRToString(varvalue.bstrVal); + EXPECT_EQ(value, "value"); + + // Verify node control type is text. + varrole = {}; + ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole), S_OK); + EXPECT_EQ(varrole.vt, VT_I4); + EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId); } // Verify the native IAccessible COM object tree is an accurate reflection of @@ -660,6 +686,15 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { VARIANT native_state = {}; ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED); + + // Perform similar tests for UIA value; + IRawElementProviderSimple* uia_node; + native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state))); + EXPECT_EQ(native_state.lVal, ToggleState_On); + + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state))); + EXPECT_NE(std::wcsstr(native_state.bstrVal, L"checked=true"), nullptr); } // Test unchecked too. @@ -690,6 +725,15 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { VARIANT native_state = {}; ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED); + + // Perform similar tests for UIA value; + IRawElementProviderSimple* uia_node; + native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state))); + EXPECT_EQ(native_state.lVal, ToggleState_Off); + + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state))); + EXPECT_NE(std::wcsstr(native_state.bstrVal, L"checked=false"), nullptr); } // Now check mixed state. @@ -721,6 +765,15 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { VARIANT native_state = {}; ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_MIXED); + + // Perform similar tests for UIA value; + IRawElementProviderSimple* uia_node; + native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state))); + EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate); + + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state))); + EXPECT_NE(std::wcsstr(native_state.bstrVal, L"checked=mixed"), nullptr); } } @@ -788,6 +841,16 @@ TEST(FlutterWindowsViewTest, SwitchNativeState) { VARIANT native_state = {}; ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED); + + // Test similarly on UIA node. + IRawElementProviderSimple* uia_node; + native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole), S_OK); + EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state), S_OK); + EXPECT_EQ(native_state.lVal, ToggleState_On); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state), S_OK); + EXPECT_NE(std::wcsstr(native_state.bstrVal, L"pressed=true"), nullptr); } // Test unpressed too. @@ -818,6 +881,14 @@ TEST(FlutterWindowsViewTest, SwitchNativeState) { VARIANT native_state = {}; ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED); + + // Test similarly on UIA node. + IRawElementProviderSimple* uia_node; + native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state), S_OK); + EXPECT_EQ(native_state.lVal, ToggleState_Off); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state), S_OK); + EXPECT_NE(std::wcsstr(native_state.bstrVal, L"pressed=false"), nullptr); } } @@ -862,6 +933,21 @@ TEST(FlutterWindowsViewTest, TooltipNodeData) { std::string tooltip = root_node->GetData().GetStringAttribute( ax::mojom::StringAttribute::kTooltip); EXPECT_EQ(tooltip, "tooltip"); + + // Check that MSAA name contains the tooltip. + IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(AccessibilityBridge::kRootNodeId).lock()->GetNativeViewAccessible(); + VARIANT varchild = {.vt=VT_I4, .lVal=CHILDID_SELF}; + BSTR bname; + ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK); + EXPECT_NE(std::wcsstr(bname, L"tooltip"), nullptr); + + // Check that UIA help text is equal to the tooltip. + IRawElementProviderSimple* uia_node; + native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); + VARIANT varname{}; + ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK); + std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal); + EXPECT_EQ(uia_tooltip, "tooltip"); } } // namespace testing diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index da862672a842c..5a1e48041b587 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -2465,6 +2465,19 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, result->intVal = static_cast(ComputeExpandCollapseState()); break; + case UIA_ToggleToggleStatePropertyId:{ + ToggleState state; + get_ToggleState(&state); + result->vt = VT_I4; + result->lVal = state; + break; + } + + case UIA_ValueValuePropertyId: + result->vt = VT_BSTR; + result->bstrVal = GetValueAttributeAsBstr(this); + break; + // Not currently implemented. case UIA_AnnotationObjectsPropertyId: case UIA_AnnotationTypesPropertyId: From 5243bcae7df289625fc726e3a0a5c9837f6eb2b5 Mon Sep 17 00:00:00 2001 From: schectman Date: Fri, 18 Nov 2022 10:02:27 -0500 Subject: [PATCH 09/19] Enable UIA unit tests --- .../platform/ax_platform_node_win_unittest.cc | 52 +++++++++---------- .../ax/platform/test_ax_node_wrapper.cc | 6 ++- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc b/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc index 90d5e40156d0f..bfa064a425f1f 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc @@ -1760,7 +1760,7 @@ TEST_F(AXPlatformNodeWinTest, ITableItemProviderGetRowHeaderItems) { EXPECT_EQ(nullptr, safearray.Get()); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertySimple) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertySimple) { AXNodeData root; root.role = ax::mojom::Role::kList; root.SetName("fake name"); @@ -1820,7 +1820,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertySimple) { EXPECT_UIA_INT_EQ(child_node1, UIA_PositionInSetPropertyId, 1); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueClickablePoint) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueClickablePoint) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kButton; @@ -1837,7 +1837,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueClickablePoint) { UIA_ClickablePointPropertyId, expected_values); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueIsDialog) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueIsDialog) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -1948,7 +1948,7 @@ TEST_F(AXPlatformNodeWinTest, UIA_IsControlElementPropertyId, false); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetControllerForPropertyId) { +TEST_F(AXPlatformNodeWinTest, UIAGetControllerForPropertyId) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -1996,7 +1996,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetControllerForPropertyId) { expected_names_2); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetDescribedByPropertyId) { +TEST_F(AXPlatformNodeWinTest, UIAGetDescribedByPropertyId) { AXNodeData root; std::vector describedby_ids = {2, 3, 4}; root.AddIntListAttribute(ax::mojom::IntListAttribute::kDescribedbyIds, @@ -2029,7 +2029,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetDescribedByPropertyId) { root_node, UIA_DescribedByPropertyId, UIA_NamePropertyId, expected_names); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAItemStatusPropertyId) { +TEST_F(AXPlatformNodeWinTest, UIAItemStatusPropertyId) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kTable; @@ -2097,7 +2097,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAItemStatusPropertyId) { UIA_ItemStatusPropertyId, ScopedVariant::kEmptyVariant); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetFlowsToPropertyId) { +TEST_F(AXPlatformNodeWinTest, UIAGetFlowsToPropertyId) { AXNodeData root; std::vector flowto_ids = {2, 3, 4}; root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, flowto_ids); @@ -2128,7 +2128,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetFlowsToPropertyId) { UIA_NamePropertyId, expected_names); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFlowsFromNone) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueFlowsFromNone) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2146,7 +2146,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFlowsFromNone) { EXPECT_EQ(nullptr, V_ARRAY(property_value.ptr())); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFlowsFromSingle) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueFlowsFromSingle) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2171,7 +2171,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFlowsFromSingle) { child_node1, UIA_FlowsFromPropertyId, UIA_NamePropertyId, expected_names); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFlowsFromMultiple) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueFlowsFromMultiple) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2215,7 +2215,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFlowsFromMultiple) { expected_names_2); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetPropertyValueFrameworkId) { +TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueFrameworkId) { AXNodeData root_ax_node_data; root_ax_node_data.id = 1; root_ax_node_data.role = ax::mojom::Role::kRootWebArea; @@ -2554,7 +2554,7 @@ TEST_F(AXPlatformNodeWinTest, GetPropertyValue_IsControlElement) { UIA_IsControlElementPropertyId, true); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetProviderOptions) { +TEST_F(AXPlatformNodeWinTest, UIAGetProviderOptions) { AXNodeData root_data; root_data.id = 1; Init(root_data); @@ -2571,7 +2571,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetProviderOptions) { provider_options); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetHostRawElementProvider) { +TEST_F(AXPlatformNodeWinTest, UIAGetHostRawElementProvider) { AXNodeData root_data; root_data.id = 1; Init(root_data); @@ -2585,7 +2585,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetHostRawElementProvider) { EXPECT_EQ(nullptr, host_provider.Get()); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetBoundingRectangle) { +TEST_F(AXPlatformNodeWinTest, UIAGetBoundingRectangle) { AXNodeData root_data; root_data.id = 1; root_data.relative_bounds.bounds = gfx::RectF(10, 20, 30, 50); @@ -2603,7 +2603,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetBoundingRectangle) { EXPECT_EQ(50, bounding_rectangle.height); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetFragmentRoot) { +TEST_F(AXPlatformNodeWinTest, UIAGetFragmentRoot) { // This test needs to be run on a child node since AXPlatformRootNodeWin // overrides the method. AXNodeData root_data; @@ -2643,7 +2643,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetFragmentRoot) { element1_provider->get_FragmentRoot(&actual_fragment_root)); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetEmbeddedFragmentRoots) { +TEST_F(AXPlatformNodeWinTest, UIAGetEmbeddedFragmentRoots) { AXNodeData root_data; root_data.id = 1; Init(root_data); @@ -2657,7 +2657,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetEmbeddedFragmentRoots) { EXPECT_EQ(nullptr, embedded_fragment_roots.Get()); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetRuntimeId) { +TEST_F(AXPlatformNodeWinTest, UIAGetRuntimeId) { AXNodeData root_data; root_data.id = 1; Init(root_data); @@ -2687,7 +2687,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAGetRuntimeId) { EXPECT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(runtime_id.Get())); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderGetIsModalUnset) { +TEST_F(AXPlatformNodeWinTest, UIAIWindowProviderGetIsModalUnset) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2701,7 +2701,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderGetIsModalUnset) { ASSERT_EQ(nullptr, window_provider.Get()); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderGetIsModalFalse) { +TEST_F(AXPlatformNodeWinTest, UIAIWindowProviderGetIsModalFalse) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2720,7 +2720,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderGetIsModalFalse) { ASSERT_FALSE(is_modal); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderGetIsModalTrue) { +TEST_F(AXPlatformNodeWinTest, UIAIWindowProviderGetIsModalTrue) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2739,7 +2739,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderGetIsModalTrue) { ASSERT_TRUE(is_modal); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderInvalidArgument) { +TEST_F(AXPlatformNodeWinTest, UIAIWindowProviderInvalidArgument) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2762,7 +2762,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderInvalidArgument) { ASSERT_EQ(E_INVALIDARG, window_provider->get_IsTopmost(nullptr)); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderNotSupported) { +TEST_F(AXPlatformNodeWinTest, UIAIWindowProviderNotSupported) { AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; @@ -2800,7 +2800,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIAIWindowProviderNotSupported) { window_provider->get_IsTopmost(&bool_result)); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIANavigate) { +TEST_F(AXPlatformNodeWinTest, UIANavigate) { AXNodeData root_data; root_data.id = 1; @@ -3076,7 +3076,7 @@ TEST_F(AXPlatformNodeWinTest, ComputeUIAControlType) { UIA_ControlTypePropertyId, int{UIA_EditControlTypeId}); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIALandmarkType) { +TEST_F(AXPlatformNodeWinTest, UIALandmarkType) { auto TestLandmarkType = [this](ax::mojom::Role node_role, std::optional expected_landmark_type, const std::string& node_name = {}) { @@ -3120,7 +3120,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_UIALandmarkType) { TestLandmarkType(ax::mojom::Role::kTable, {}); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIALocalizedLandmarkType) { +TEST_F(AXPlatformNodeWinTest, UIALocalizedLandmarkType) { auto TestLocalizedLandmarkType = [this](ax::mojom::Role node_role, const std::wstring& expected_localized_landmark, @@ -3196,7 +3196,7 @@ TEST_F(AXPlatformNodeWinTest, IRawElementProviderSimple2ShowContextMenu) { EXPECT_EQ(root_node, TestAXNodeWrapper::GetNodeFromLastShowContextMenu()); } -TEST_F(AXPlatformNodeWinTest, DISABLED_UIAErrorHandling) { +TEST_F(AXPlatformNodeWinTest, UIAErrorHandling) { AXNodeData root; root.id = 1; Init(root); diff --git a/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc b/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc index 7270b83911da4..0f1c65d522a05 100644 --- a/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc +++ b/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc @@ -54,9 +54,13 @@ std::map g_hit_test_result; class TestAXTreeObserver : public AXTreeObserver { private: void OnNodeDeleted(AXTree* tree, int32_t node_id) override { - const auto iter = g_node_id_to_wrapper_map.find(node_id); + const auto& iter = g_node_id_to_wrapper_map.find(node_id); if (iter != g_node_id_to_wrapper_map.end()) { TestAXNodeWrapper* wrapper = iter->second; + const auto& focus_iter = g_focused_node_in_tree.find(tree); + if (focus_iter != g_focused_node_in_tree.end() && focus_iter->second->id() == node_id) { + g_focused_node_in_tree.erase(tree); + } delete wrapper; g_node_id_to_wrapper_map.erase(node_id); } From dda9ff149ef6171832defddc620973b0839d6e6f Mon Sep 17 00:00:00 2001 From: schectman Date: Fri, 18 Nov 2022 13:40:56 -0500 Subject: [PATCH 10/19] Conditional UIA implementation --- .../windows/accessibility_bridge_windows.cc | 17 ----------------- .../flutter_platform_node_delegate_windows.cc | 10 ---------- shell/platform/windows/window.cc | 8 +++++++- third_party/accessibility/ax/ax_active_popup.cc | 2 +- .../ax/platform/ax_platform_node_win.cc | 4 +++- 5 files changed, 11 insertions(+), 30 deletions(-) diff --git a/shell/platform/windows/accessibility_bridge_windows.cc b/shell/platform/windows/accessibility_bridge_windows.cc index 422942d964a25..2e74cc1e36864 100644 --- a/shell/platform/windows/accessibility_bridge_windows.cc +++ b/shell/platform/windows/accessibility_bridge_windows.cc @@ -32,71 +32,55 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent( switch (event_type) { case ui::AXEventGenerator::Event::ALERT: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kAlert); - // DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_ALERT); break; case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); break; case ui::AXEventGenerator::Event::CHILDREN_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kChildrenChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_REORDER); break; case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kDocumentSelectionChanged); break; case ui::AXEventGenerator::Event::FOCUS_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kFocus); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_FOCUS); SetFocus(win_delegate); break; case ui::AXEventGenerator::Event::IGNORED_CHANGED: if (ax_node->IsIgnored()) { DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kHide); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_HIDE); } break; case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kTextChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_NAMECHANGE); break; case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kLiveRegionChanged); - /*DispatchWinAccessibilityEvent(win_delegate, - EVENT_OBJECT_LIVEREGIONCHANGED);*/ break; case ui::AXEventGenerator::Event::NAME_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kTextChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_NAMECHANGE); break; case ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kScrollPositionChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_SCROLLINGEND); break; case ui::AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kScrollPositionChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_SYSTEM_SCROLLINGEND); break; case ui::AXEventGenerator::Event::SELECTED_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); break; case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kSelectedChildrenChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_SELECTIONWITHIN); break; case ui::AXEventGenerator::Event::SUBTREE_CREATED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kShow); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_SHOW); break; case ui::AXEventGenerator::Event::VALUE_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_VALUECHANGE); break; case ui::AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kStateChanged); - //DispatchWinAccessibilityEvent(win_delegate, EVENT_OBJECT_STATECHANGE); break; case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED: case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED: @@ -170,7 +154,6 @@ AccessibilityBridgeWindows::CreateFlutterPlatformNodeDelegate() { void AccessibilityBridgeWindows::DispatchWinAccessibilityEvent( std::shared_ptr node_delegate, ax::mojom::Event event_type) { - // TODO(schectman) change FlutterPlatformNodeDelegateWindows method too node_delegate->DispatchWinAccessibilityEvent(event_type); } diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.cc b/shell/platform/windows/flutter_platform_node_delegate_windows.cc index 27e0e0e994b08..af48db0c1a4c2 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.cc +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.cc @@ -93,16 +93,6 @@ gfx::Rect FlutterPlatformNodeDelegateWindows::GetBoundsRect( void FlutterPlatformNodeDelegateWindows::DispatchWinAccessibilityEvent( ax::mojom::Event event_type) { ax_platform_node_->NotifyAccessibilityEvent(event_type); - - /* - HWND hwnd = view_->GetPlatformWindow(); - if (!hwnd) { - return; - } - assert(ax_platform_node_); - ::NotifyWinEvent(event_type, hwnd, OBJID_CLIENT, - -ax_platform_node_->GetUniqueId());*/ - // TODO(schectman) this may be a good place to call NotifyAccessibilityEvent, if I change the input param to use mojom events. } void FlutterPlatformNodeDelegateWindows::SetFocus() { diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index 81bb1e97ba19c..a63cf6711c873 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -201,6 +201,9 @@ LRESULT Window::OnGetObject(UINT const message, } gfx::NativeViewAccessible root_view = GetNativeViewAccessible(); + // TODO(schectman): UIA is currently disabled by default. + // https://github.com/flutter/flutter/issues/114547 +#ifdef FLUTTER_ENGINE_USE_UIA if (is_uia_request && root_view) { if (!ax_fragment_root_) { if (!ax_fragment_delegate_) { @@ -222,7 +225,10 @@ LRESULT Window::OnGetObject(UINT const message, } else { FML_LOG(ERROR) << "Failed to query AX fragment root."; } - } else if (is_msaa_request && root_view) { // TODO(schectman) revert this FALSE check; it's just for testing + } else if (is_msaa_request && root_view) { +#else + if (is_msaa_request && root_view) { +#endif // FLUTTER_ENGINE_USE_UIA // Create the accessibility root if it does not already exist. if (!accessibility_root_) { CreateAccessibilityRootNode(); diff --git a/third_party/accessibility/ax/ax_active_popup.cc b/third_party/accessibility/ax/ax_active_popup.cc index a20cbc2ec2a05..d41510bceb157 100644 --- a/third_party/accessibility/ax/ax_active_popup.cc +++ b/third_party/accessibility/ax/ax_active_popup.cc @@ -15,7 +15,7 @@ namespace ui { static std::optional g_active_popup_ax_unique_id; std::optional GetActivePopupAxUniqueId() { - return g_active_popup_ax_unique_id; // TODO(schectman) pretty sure this shouldn't be dereferenced... + return g_active_popup_ax_unique_id; } void SetActivePopupAxUniqueId(std::optional ax_unique_id) { diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index 5a1e48041b587..ac20daeffd34f 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -5597,7 +5597,9 @@ AXPlatformNodeWin::GetPatternProviderFactoryMethod(PATTERNID pattern_id) { } break; - // TODO(schectman) add implementations for text and textchild + // TODO(schectman): add implementations for ITextProvider and ITextRangeProvider interfaces. + // https://github.com/flutter/flutter/issues/114547 and + // https://github.com/flutter/flutter/issues/109804 case UIA_TogglePatternId: if (SupportsToggle(data.role)) { From 2b0daaeb85c38ac1c9a2ddb132ed0eb636215502 Mon Sep 17 00:00:00 2001 From: schectman Date: Fri, 18 Nov 2022 13:59:00 -0500 Subject: [PATCH 11/19] Text selection MSAA event --- third_party/accessibility/ax/platform/ax_platform_node_win.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index ac20daeffd34f..e63b3963e3ab2 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -5218,6 +5218,10 @@ std::optional AXPlatformNodeWin::MojoEventToMSAAEvent( return EVENT_OBJECT_SHOW; case ax::mojom::Event::kValueChanged: return EVENT_OBJECT_VALUECHANGE; +#ifdef EVENT_OBJECT_TEXTSELECTIONCHANGED + case ax::mojom::Event::kDocumentSelectionChanged: + return EVENT_OBJECT_TEXTSELECTIONCHANGED; +#endif default: return std::nullopt; } From 813622575a32743177dd78ec16b7df399033cfbd Mon Sep 17 00:00:00 2001 From: schectman Date: Fri, 18 Nov 2022 14:43:09 -0500 Subject: [PATCH 12/19] License --- ci/licenses_golden/licenses_flutter | 1 + .../common/flutter_platform_node_delegate.h | 1 + .../windows/accessibility_bridge_windows.cc | 33 ++++++++---- .../accessibility_bridge_windows_unittests.cc | 3 +- .../flutter_platform_node_delegate_windows.cc | 3 +- .../windows/flutter_windows_view_unittests.cc | 53 +++++++++++++------ .../platform/windows/testing/test_keyboard.cc | 2 +- shell/platform/windows/window.cc | 21 +++++--- shell/platform/windows/window.h | 2 +- .../ax/platform/ax_platform_node_win.cc | 9 ++-- .../ax/platform/test_ax_node_wrapper.cc | 3 +- 11 files changed, 87 insertions(+), 44 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ea0738c72c1b3..77ad3e05aa1a6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -3277,6 +3277,7 @@ FILE: ../../../flutter/shell/platform/windows/windows_proc_table.cc FILE: ../../../flutter/shell/platform/windows/windows_proc_table.h FILE: ../../../flutter/shell/platform/windows/windows_registry.cc FILE: ../../../flutter/shell/platform/windows/windows_registry.h +FILE: ../../../flutter/shell/platform/windows/windowsx_shim.h FILE: ../../../flutter/shell/profiling/sampling_profiler.cc FILE: ../../../flutter/shell/profiling/sampling_profiler.h FILE: ../../../flutter/shell/profiling/sampling_profiler_unittest.cc diff --git a/shell/platform/common/flutter_platform_node_delegate.h b/shell/platform/common/flutter_platform_node_delegate.h index 30b81c5b5d200..2878fe45afe92 100644 --- a/shell/platform/common/flutter_platform_node_delegate.h +++ b/shell/platform/common/flutter_platform_node_delegate.h @@ -143,6 +143,7 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase { /// platform node delegate. This pointer is only safe in the /// platform thread. std::weak_ptr GetOwnerBridge() const; + private: ui::AXNode* ax_node_; std::weak_ptr bridge_; diff --git a/shell/platform/windows/accessibility_bridge_windows.cc b/shell/platform/windows/accessibility_bridge_windows.cc index 2e74cc1e36864..3bfa54e188663 100644 --- a/shell/platform/windows/accessibility_bridge_windows.cc +++ b/shell/platform/windows/accessibility_bridge_windows.cc @@ -34,13 +34,16 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent( DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kAlert); break; case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kValueChanged); break; case ui::AXEventGenerator::Event::CHILDREN_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kChildrenChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kChildrenChanged); break; case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kDocumentSelectionChanged); + DispatchWinAccessibilityEvent( + win_delegate, ax::mojom::Event::kDocumentSelectionChanged); break; case ui::AXEventGenerator::Event::FOCUS_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kFocus); @@ -52,35 +55,43 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent( } break; case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kTextChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kTextChanged); break; case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kLiveRegionChanged); break; case ui::AXEventGenerator::Event::NAME_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kTextChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kTextChanged); break; case ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kScrollPositionChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kScrollPositionChanged); break; case ui::AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kScrollPositionChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kScrollPositionChanged); break; case ui::AXEventGenerator::Event::SELECTED_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kValueChanged); break; case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kSelectedChildrenChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kSelectedChildrenChanged); break; case ui::AXEventGenerator::Event::SUBTREE_CREATED: DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kShow); break; case ui::AXEventGenerator::Event::VALUE_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kValueChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kValueChanged); break; case ui::AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED: - DispatchWinAccessibilityEvent(win_delegate, ax::mojom::Event::kStateChanged); + DispatchWinAccessibilityEvent(win_delegate, + ax::mojom::Event::kStateChanged); break; case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED: case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED: diff --git a/shell/platform/windows/accessibility_bridge_windows_unittests.cc b/shell/platform/windows/accessibility_bridge_windows_unittests.cc index cb185aa5dc8f5..81094d6972b2b 100644 --- a/shell/platform/windows/accessibility_bridge_windows_unittests.cc +++ b/shell/platform/windows/accessibility_bridge_windows_unittests.cc @@ -270,7 +270,8 @@ TEST(AccessibilityBridgeWindows, OnAccessibilityEventFocusChanged) { ax::mojom::EventFrom::kNone, {}}}); ASSERT_EQ(bridge->dispatched_events().size(), 1); - EXPECT_EQ(bridge->dispatched_events()[0].event_type, ax::mojom::Event::kFocus); + EXPECT_EQ(bridge->dispatched_events()[0].event_type, + ax::mojom::Event::kFocus); ASSERT_EQ(bridge->focused_nodes().size(), 1); EXPECT_EQ(bridge->focused_nodes()[0], 1); diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.cc b/shell/platform/windows/flutter_platform_node_delegate_windows.cc index af48db0c1a4c2..a7c972be10a62 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.cc +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.cc @@ -102,7 +102,8 @@ void FlutterPlatformNodeDelegateWindows::SetFocus() { GetNativeViewAccessible()->accSelect(SELFLAG_TAKEFOCUS, varchild); } -gfx::AcceleratedWidget FlutterPlatformNodeDelegateWindows::GetTargetForNativeAccessibilityEvent() { +gfx::AcceleratedWidget +FlutterPlatformNodeDelegateWindows::GetTargetForNativeAccessibilityEvent() { return view_->GetPlatformWindow(); } diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index efafc175ecf07..0c1aa369fbe7d 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -4,10 +4,10 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" +#include #include #include #include -#include #include #include @@ -247,14 +247,16 @@ TEST(FlutterWindowsView, AddSemanticsNodeUpdate) { // Verify value property matches our label. VARIANT varvalue{}; - ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue), S_OK); + ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue), + S_OK); EXPECT_EQ(varvalue.vt, VT_BSTR); value = _com_util::ConvertBSTRToString(varvalue.bstrVal); EXPECT_EQ(value, "value"); // Verify node control type is text. varrole = {}; - ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole), S_OK); + ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole), + S_OK); EXPECT_EQ(varrole.vt, VT_I4); EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId); } @@ -690,10 +692,12 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { // Perform similar tests for UIA value; IRawElementProviderSimple* uia_node; native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); - ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state))); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue( + UIA_ToggleToggleStatePropertyId, &native_state))); EXPECT_EQ(native_state.lVal, ToggleState_On); - ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state))); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue( + UIA_AriaPropertiesPropertyId, &native_state))); EXPECT_NE(std::wcsstr(native_state.bstrVal, L"checked=true"), nullptr); } @@ -729,10 +733,12 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { // Perform similar tests for UIA value; IRawElementProviderSimple* uia_node; native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); - ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state))); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue( + UIA_ToggleToggleStatePropertyId, &native_state))); EXPECT_EQ(native_state.lVal, ToggleState_Off); - ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state))); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue( + UIA_AriaPropertiesPropertyId, &native_state))); EXPECT_NE(std::wcsstr(native_state.bstrVal, L"checked=false"), nullptr); } @@ -769,10 +775,12 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { // Perform similar tests for UIA value; IRawElementProviderSimple* uia_node; native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); - ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state))); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue( + UIA_ToggleToggleStatePropertyId, &native_state))); EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate); - ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state))); + ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue( + UIA_AriaPropertiesPropertyId, &native_state))); EXPECT_NE(std::wcsstr(native_state.bstrVal, L"checked=mixed"), nullptr); } } @@ -845,11 +853,16 @@ TEST(FlutterWindowsViewTest, SwitchNativeState) { // Test similarly on UIA node. IRawElementProviderSimple* uia_node; native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); - ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole), S_OK); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole), + S_OK); EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId); - ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state), S_OK); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, + &native_state), + S_OK); EXPECT_EQ(native_state.lVal, ToggleState_On); - ASSERT_EQ(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state), S_OK); + ASSERT_EQ( + uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state), + S_OK); EXPECT_NE(std::wcsstr(native_state.bstrVal, L"pressed=true"), nullptr); } @@ -885,9 +898,13 @@ TEST(FlutterWindowsViewTest, SwitchNativeState) { // Test similarly on UIA node. IRawElementProviderSimple* uia_node; native_view->QueryInterface(IID_PPV_ARGS(&uia_node)); - ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, &native_state), S_OK); + ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId, + &native_state), + S_OK); EXPECT_EQ(native_state.lVal, ToggleState_Off); - ASSERT_EQ(uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state), S_OK); + ASSERT_EQ( + uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state), + S_OK); EXPECT_NE(std::wcsstr(native_state.bstrVal, L"pressed=false"), nullptr); } } @@ -935,8 +952,12 @@ TEST(FlutterWindowsViewTest, TooltipNodeData) { EXPECT_EQ(tooltip, "tooltip"); // Check that MSAA name contains the tooltip. - IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(AccessibilityBridge::kRootNodeId).lock()->GetNativeViewAccessible(); - VARIANT varchild = {.vt=VT_I4, .lVal=CHILDID_SELF}; + IAccessible* native_view = bridge + ->GetFlutterPlatformNodeDelegateFromID( + AccessibilityBridge::kRootNodeId) + .lock() + ->GetNativeViewAccessible(); + VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF}; BSTR bname; ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK); EXPECT_NE(std::wcsstr(bname, L"tooltip"), nullptr); diff --git a/shell/platform/windows/testing/test_keyboard.cc b/shell/platform/windows/testing/test_keyboard.cc index b034c32708a77..92389b9bf5141 100644 --- a/shell/platform/windows/testing/test_keyboard.cc +++ b/shell/platform/windows/testing/test_keyboard.cc @@ -3,9 +3,9 @@ // found in the LICENSE file. #include "flutter/shell/platform/windows/testing/test_keyboard.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" #include "flutter/shell/platform/common/json_message_codec.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" +#include "flutter/shell/platform/windows/windowsx_shim.h" #include diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index a63cf6711c873..3ab638b6d7cde 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -207,9 +207,11 @@ LRESULT Window::OnGetObject(UINT const message, if (is_uia_request && root_view) { if (!ax_fragment_root_) { if (!ax_fragment_delegate_) { - ax_fragment_delegate_ = std::make_unique(*this); + ax_fragment_delegate_ = + std::make_unique(*this); } - ax_fragment_root_ = std::make_unique(window_handle_, ax_fragment_delegate_.get()); + ax_fragment_root_ = std::make_unique( + window_handle_, ax_fragment_delegate_.get()); } // TODO(cbracken): https://github.com/flutter/flutter/issues/94782 @@ -217,11 +219,11 @@ LRESULT Window::OnGetObject(UINT const message, // Retrieve UIA object for the root view. Microsoft::WRL::ComPtr root; if (SUCCEEDED(ax_fragment_root_->GetNativeViewAccessible()->QueryInterface( - IID_PPV_ARGS(&root)))) { + IID_PPV_ARGS(&root)))) { // Return the UIA object via UiaReturnRawElementProvider(). See: // https://docs.microsoft.com/en-us/windows/win32/winauto/wm-getobject - reference_result = - UiaReturnRawElementProvider(window_handle_, wparam, lparam, root.Get()); + reference_result = UiaReturnRawElementProvider(window_handle_, wparam, + lparam, root.Get()); } else { FML_LOG(ERROR) << "Failed to query AX fragment root."; } @@ -682,11 +684,13 @@ void Window::CreateAccessibilityRootNode() { accessibility_root_ = AccessibilityRootNode::Create(); } -gfx::NativeViewAccessible WindowAXFragmentRootDelegate::GetChildOfAXFragmentRoot() { +gfx::NativeViewAccessible +WindowAXFragmentRootDelegate::GetChildOfAXFragmentRoot() { return window_.GetNativeViewAccessible(); } -gfx::NativeViewAccessible WindowAXFragmentRootDelegate::GetParentOfAXFragmentRoot() { +gfx::NativeViewAccessible +WindowAXFragmentRootDelegate::GetParentOfAXFragmentRoot() { return nullptr; } @@ -694,6 +698,7 @@ bool WindowAXFragmentRootDelegate::IsAXFragmentRootAControlElement() { return true; } -WindowAXFragmentRootDelegate::WindowAXFragmentRootDelegate(Window& window) : window_(window) {} +WindowAXFragmentRootDelegate::WindowAXFragmentRootDelegate(Window& window) + : window_(window) {} } // namespace flutter diff --git a/shell/platform/windows/window.h b/shell/platform/windows/window.h index b95c0ebf001bb..c80da8770d150 100644 --- a/shell/platform/windows/window.h +++ b/shell/platform/windows/window.h @@ -20,9 +20,9 @@ #include "flutter/shell/platform/windows/text_input_manager.h" #include "flutter/shell/platform/windows/windows_proc_table.h" #include "flutter/shell/platform/windows/windowsx_shim.h" -#include "flutter/third_party/accessibility/gfx/native_widget_types.h" #include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_delegate_win.h" #include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_win.h" +#include "flutter/third_party/accessibility/gfx/native_widget_types.h" namespace flutter { diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index e63b3963e3ab2..d8578392093c2 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -2465,7 +2465,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id, result->intVal = static_cast(ComputeExpandCollapseState()); break; - case UIA_ToggleToggleStatePropertyId:{ + case UIA_ToggleToggleStatePropertyId: { ToggleState state; get_ToggleState(&state); result->vt = VT_I4; @@ -5601,9 +5601,10 @@ AXPlatformNodeWin::GetPatternProviderFactoryMethod(PATTERNID pattern_id) { } break; - // TODO(schectman): add implementations for ITextProvider and ITextRangeProvider interfaces. - // https://github.com/flutter/flutter/issues/114547 and - // https://github.com/flutter/flutter/issues/109804 + // TODO(schectman): add implementations for ITextProvider and + // ITextRangeProvider interfaces. + // https://github.com/flutter/flutter/issues/114547 and + // https://github.com/flutter/flutter/issues/109804 case UIA_TogglePatternId: if (SupportsToggle(data.role)) { diff --git a/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc b/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc index 0f1c65d522a05..05a655194948e 100644 --- a/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc +++ b/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc @@ -58,7 +58,8 @@ class TestAXTreeObserver : public AXTreeObserver { if (iter != g_node_id_to_wrapper_map.end()) { TestAXNodeWrapper* wrapper = iter->second; const auto& focus_iter = g_focused_node_in_tree.find(tree); - if (focus_iter != g_focused_node_in_tree.end() && focus_iter->second->id() == node_id) { + if (focus_iter != g_focused_node_in_tree.end() && + focus_iter->second->id() == node_id) { g_focused_node_in_tree.erase(tree); } delete wrapper; From e87e43ad28708ec125148068f5fb5ec8ce277a52 Mon Sep 17 00:00:00 2001 From: schectman Date: Wed, 23 Nov 2022 17:29:06 -0500 Subject: [PATCH 13/19] PR --- shell/platform/windows/window.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index 3ab638b6d7cde..1a944de635da4 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -203,8 +203,8 @@ LRESULT Window::OnGetObject(UINT const message, gfx::NativeViewAccessible root_view = GetNativeViewAccessible(); // TODO(schectman): UIA is currently disabled by default. // https://github.com/flutter/flutter/issues/114547 -#ifdef FLUTTER_ENGINE_USE_UIA if (is_uia_request && root_view) { +#ifdef FLUTTER_ENGINE_USE_UIA if (!ax_fragment_root_) { if (!ax_fragment_delegate_) { ax_fragment_delegate_ = @@ -214,8 +214,6 @@ LRESULT Window::OnGetObject(UINT const message, window_handle_, ax_fragment_delegate_.get()); } - // TODO(cbracken): https://github.com/flutter/flutter/issues/94782 - // Implement when we adopt UIA support. // Retrieve UIA object for the root view. Microsoft::WRL::ComPtr root; if (SUCCEEDED(ax_fragment_root_->GetNativeViewAccessible()->QueryInterface( @@ -227,10 +225,8 @@ LRESULT Window::OnGetObject(UINT const message, } else { FML_LOG(ERROR) << "Failed to query AX fragment root."; } - } else if (is_msaa_request && root_view) { -#else - if (is_msaa_request && root_view) { #endif // FLUTTER_ENGINE_USE_UIA + } else if (is_msaa_request && root_view) { // Create the accessibility root if it does not already exist. if (!accessibility_root_) { CreateAccessibilityRootNode(); From 7e1c4d059c7086d695515b3f3c0cf20abeae86a5 Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 28 Nov 2022 10:12:00 -0500 Subject: [PATCH 14/19] Before change to AccessibilityBridgeWindows --- shell/platform/windows/flutter_window.cc | 4 ++++ shell/platform/windows/flutter_window.h | 3 +++ shell/platform/windows/flutter_windows_view.cc | 5 +++++ shell/platform/windows/flutter_windows_view.h | 3 +++ shell/platform/windows/testing/mock_window.h | 2 ++ .../windows/testing/mock_window_binding_handler_delegate.h | 2 ++ shell/platform/windows/window.cc | 2 +- shell/platform/windows/window.h | 3 +++ shell/platform/windows/window_binding_handler_delegate.h | 4 ++++ 9 files changed, 27 insertions(+), 1 deletion(-) diff --git a/shell/platform/windows/flutter_window.cc b/shell/platform/windows/flutter_window.cc index 165fd52413a8d..18e7210bedda6 100644 --- a/shell/platform/windows/flutter_window.cc +++ b/shell/platform/windows/flutter_window.cc @@ -303,4 +303,8 @@ AccessibilityRootNode* FlutterWindow::GetAccessibilityRootNode() { return accessibility_root_; } +ui::AXFragmentRootDelegateWin* FlutterWindow::GetAxFragmentRootDelegate() { + return binding_handler_delegate_->GetAxFragmentRootDelegate(); +} + } // namespace flutter diff --git a/shell/platform/windows/flutter_window.h b/shell/platform/windows/flutter_window.h index 6072103f1956b..3f66622b58f46 100644 --- a/shell/platform/windows/flutter_window.h +++ b/shell/platform/windows/flutter_window.h @@ -153,6 +153,9 @@ class FlutterWindow : public Window, public WindowBindingHandler { // |WindowBindingHandler| AccessibilityRootNode* GetAccessibilityRootNode() override; + // |Window| + ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() override; + private: // A pointer to a FlutterWindowsView that can be used to update engine // windowing and input state. diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index a7b9a675d6b58..88440a8b9aec5 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -675,4 +675,9 @@ void FlutterWindowsView::NotifyWinEventWrapper(DWORD event, } } +ui::AXFragmentRootDelegateWin* FlutterWindowsView::GetAxFragmentRootDelegate() { + // TODO(schectman): implement + return nullptr; +} + } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 19afd47baf877..cac647ea04721 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -196,6 +196,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate, // |TextInputPluginDelegate| void OnResetImeComposing() override; + // |WindowBindingHandlerDelegate| + virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() override; + protected: // Called to create keyboard key handler. // diff --git a/shell/platform/windows/testing/mock_window.h b/shell/platform/windows/testing/mock_window.h index debc363e7fec4..483404c06a0c9 100644 --- a/shell/platform/windows/testing/mock_window.h +++ b/shell/platform/windows/testing/mock_window.h @@ -66,6 +66,8 @@ class MockWindow : public Window { MOCK_METHOD0(OnThemeChange, void()); + MOCK_METHOD0(GetAxFragmentRootDelegate, ui::AXFragmentRootDelegateWin*()); + void CallOnImeComposition(UINT const message, WPARAM const wparam, LPARAM const lparam); diff --git a/shell/platform/windows/testing/mock_window_binding_handler_delegate.h b/shell/platform/windows/testing/mock_window_binding_handler_delegate.h index 03534b2e5ecfd..2e7df003cc847 100644 --- a/shell/platform/windows/testing/mock_window_binding_handler_delegate.h +++ b/shell/platform/windows/testing/mock_window_binding_handler_delegate.h @@ -63,6 +63,8 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate { MOCK_METHOD1(OnScrollInertiaCancel, void(int32_t)); MOCK_METHOD0(OnPlatformBrightnessChanged, void()); MOCK_METHOD1(UpdateHighContrastEnabled, void(bool enabled)); + + MOCK_METHOD0(GetAxFragmentRootDelegate, ui::AXFragmentRootDelegateWin*()); }; } // namespace testing diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index 1a944de635da4..c5d7a2417848f 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -204,7 +204,7 @@ LRESULT Window::OnGetObject(UINT const message, // TODO(schectman): UIA is currently disabled by default. // https://github.com/flutter/flutter/issues/114547 if (is_uia_request && root_view) { -#ifdef FLUTTER_ENGINE_USE_UIA +#ifndef FLUTTER_ENGINE_USE_UIA if (!ax_fragment_root_) { if (!ax_fragment_delegate_) { ax_fragment_delegate_ = diff --git a/shell/platform/windows/window.h b/shell/platform/windows/window.h index c80da8770d150..81b6691cc92fa 100644 --- a/shell/platform/windows/window.h +++ b/shell/platform/windows/window.h @@ -215,6 +215,9 @@ class Window : public KeyboardManager::WindowDelegate { // Check if the high contrast feature is enabled on the OS virtual bool GetHighContrastEnabled(); + // Called to obtain a pointer to the fragment root delegate. + virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() = 0; + protected: // Win32's DefWindowProc. // diff --git a/shell/platform/windows/window_binding_handler_delegate.h b/shell/platform/windows/window_binding_handler_delegate.h index 485fe4384f3cc..7bf13cab142c6 100644 --- a/shell/platform/windows/window_binding_handler_delegate.h +++ b/shell/platform/windows/window_binding_handler_delegate.h @@ -9,6 +9,7 @@ #include "flutter/shell/platform/common/geometry.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_delegate_win.h" #include "flutter/third_party/accessibility/gfx/native_widget_types.h" namespace flutter { @@ -135,6 +136,9 @@ class WindowBindingHandlerDelegate { // Update the status of the high contrast feature virtual void UpdateHighContrastEnabled(bool enabled) = 0; + + // Obtain a pointer to the fragment root delegate. + virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() = 0; }; } // namespace flutter From 43920ff9fcf94d4b589b0c5389217ce54d515ff9 Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 28 Nov 2022 10:26:54 -0500 Subject: [PATCH 15/19] AccessibilityBridgeWindows in FlutterWindowsEngine --- shell/platform/windows/accessibility_bridge_windows.h | 4 +--- .../windows/accessibility_bridge_windows_unittests.cc | 2 +- shell/platform/windows/flutter_windows_engine.cc | 2 +- shell/platform/windows/flutter_windows_engine.h | 7 ++++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/shell/platform/windows/accessibility_bridge_windows.h b/shell/platform/windows/accessibility_bridge_windows.h index 463d3aec0ac91..d3d9715003059 100644 --- a/shell/platform/windows/accessibility_bridge_windows.h +++ b/shell/platform/windows/accessibility_bridge_windows.h @@ -7,12 +7,10 @@ #include "flutter/shell/platform/common/accessibility_bridge.h" -#include "flutter/shell/platform/windows/flutter_windows_engine.h" -#include "flutter/shell/platform/windows/flutter_windows_view.h" - namespace flutter { class FlutterWindowsEngine; +class FlutterWindowsView; class FlutterPlatformNodeDelegateWindows; // The Win32 implementation of AccessibilityBridge. diff --git a/shell/platform/windows/accessibility_bridge_windows_unittests.cc b/shell/platform/windows/accessibility_bridge_windows_unittests.cc index 81094d6972b2b..e3cc3b58a0f98 100644 --- a/shell/platform/windows/accessibility_bridge_windows_unittests.cc +++ b/shell/platform/windows/accessibility_bridge_windows_unittests.cc @@ -76,7 +76,7 @@ class FlutterWindowsEngineSpy : public FlutterWindowsEngine { : FlutterWindowsEngine(project) {} protected: - virtual std::shared_ptr CreateAccessibilityBridge( + virtual std::shared_ptr CreateAccessibilityBridge( FlutterWindowsEngine* engine, FlutterWindowsView* view) override { return std::make_shared(engine, view); diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 795d83efea6fd..5118f1e39d5bb 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -618,7 +618,7 @@ void FlutterWindowsEngine::UpdateSemanticsEnabled(bool enabled) { } } -std::shared_ptr +std::shared_ptr FlutterWindowsEngine::CreateAccessibilityBridge(FlutterWindowsEngine* engine, FlutterWindowsView* view) { return std::make_shared(engine, view); diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index d7f08036c552c..193cc8f03f520 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -19,6 +19,7 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/basic_message_channel.h" #include "flutter/shell/platform/common/incoming_message_dispatcher.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/accessibility_bridge_windows.h" #include "flutter/shell/platform/windows/angle_surface_manager.h" #include "flutter/shell/platform/windows/flutter_desktop_messenger.h" #include "flutter/shell/platform/windows/flutter_project_bundle.h" @@ -142,7 +143,7 @@ class FlutterWindowsEngine { // rendering using software instead of OpenGL. AngleSurfaceManager* surface_manager() { return surface_manager_.get(); } - std::weak_ptr accessibility_bridge() { + std::weak_ptr accessibility_bridge() { return accessibility_bridge_; } @@ -251,7 +252,7 @@ class FlutterWindowsEngine { // // By default this method calls AccessibilityBridge's constructor. Exposing // this method allows unit tests to override in order to capture information. - virtual std::shared_ptr CreateAccessibilityBridge( + virtual std::shared_ptr CreateAccessibilityBridge( FlutterWindowsEngine* engine, FlutterWindowsView* view); @@ -333,7 +334,7 @@ class FlutterWindowsEngine { bool high_contrast_enabled_ = false; - std::shared_ptr accessibility_bridge_; + std::shared_ptr accessibility_bridge_; // The manager for WindowProc delegate registration and callbacks. std::unique_ptr window_proc_delegate_manager_; From 8a05697bfa5c6a17bd2e87663ab96ad8a80c4344 Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 28 Nov 2022 10:54:19 -0500 Subject: [PATCH 16/19] Use AccessibilityBridgeWindows for AXFragmentRootDelegateWin --- .../windows/accessibility_bridge_windows.cc | 12 +++++++++ .../windows/accessibility_bridge_windows.h | 13 +++++++++- .../platform/windows/flutter_windows_view.cc | 3 +-- shell/platform/windows/window.cc | 25 ++----------------- shell/platform/windows/window.h | 23 ----------------- 5 files changed, 27 insertions(+), 49 deletions(-) diff --git a/shell/platform/windows/accessibility_bridge_windows.cc b/shell/platform/windows/accessibility_bridge_windows.cc index 3bfa54e188663..c03bb3d72fe68 100644 --- a/shell/platform/windows/accessibility_bridge_windows.cc +++ b/shell/platform/windows/accessibility_bridge_windows.cc @@ -173,4 +173,16 @@ void AccessibilityBridgeWindows::SetFocus( node_delegate->SetFocus(); } +gfx::NativeViewAccessible AccessibilityBridgeWindows::GetChildOfAXFragmentRoot() { + return view_->GetNativeViewAccessible(); +} + +gfx::NativeViewAccessible AccessibilityBridgeWindows::GetParentOfAXFragmentRoot() { + return nullptr; +} + +bool AccessibilityBridgeWindows::IsAXFragmentRootAControlElement() { + return true; +} + } // namespace flutter diff --git a/shell/platform/windows/accessibility_bridge_windows.h b/shell/platform/windows/accessibility_bridge_windows.h index d3d9715003059..9f32b5ed666fa 100644 --- a/shell/platform/windows/accessibility_bridge_windows.h +++ b/shell/platform/windows/accessibility_bridge_windows.h @@ -6,6 +6,7 @@ #define FLUTTER_SHELL_PLATFORM_WINDOWS_ACCESSIBILITY_BRIDGE_WINDOWS_H_ #include "flutter/shell/platform/common/accessibility_bridge.h" +#include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_delegate_win.h" namespace flutter { @@ -22,7 +23,8 @@ class FlutterPlatformNodeDelegateWindows; /// /// AccessibilityBridgeWindows must be created as a shared_ptr, since some /// methods acquires its weak_ptr. -class AccessibilityBridgeWindows : public AccessibilityBridge { +class AccessibilityBridgeWindows : public AccessibilityBridge, + public ui::AXFragmentRootDelegateWin { public: AccessibilityBridgeWindows(FlutterWindowsEngine* engine, FlutterWindowsView* view); @@ -48,6 +50,15 @@ class AccessibilityBridgeWindows : public AccessibilityBridge { virtual void SetFocus( std::shared_ptr node_delegate); + // |AXFragmentRootDelegateWin| + gfx::NativeViewAccessible GetChildOfAXFragmentRoot() override; + + // |AXFragmentRootDelegateWin| + gfx::NativeViewAccessible GetParentOfAXFragmentRoot() override; + + // |AXFragmentRootDelegateWin| + bool IsAXFragmentRootAControlElement() override; + protected: // |AccessibilityBridge| void OnAccessibilityEvent( diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 88440a8b9aec5..65ae0ef3cef40 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -676,8 +676,7 @@ void FlutterWindowsView::NotifyWinEventWrapper(DWORD event, } ui::AXFragmentRootDelegateWin* FlutterWindowsView::GetAxFragmentRootDelegate() { - // TODO(schectman): implement - return nullptr; + return engine_->accessibility_bridge().lock().get(); } } // namespace flutter diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index c5d7a2417848f..8f2a3327a97db 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -204,14 +204,10 @@ LRESULT Window::OnGetObject(UINT const message, // TODO(schectman): UIA is currently disabled by default. // https://github.com/flutter/flutter/issues/114547 if (is_uia_request && root_view) { -#ifndef FLUTTER_ENGINE_USE_UIA +#ifdef FLUTTER_ENGINE_USE_UIA if (!ax_fragment_root_) { - if (!ax_fragment_delegate_) { - ax_fragment_delegate_ = - std::make_unique(*this); - } ax_fragment_root_ = std::make_unique( - window_handle_, ax_fragment_delegate_.get()); + window_handle_, GetAxFragmentRootDelegate()); } // Retrieve UIA object for the root view. @@ -680,21 +676,4 @@ void Window::CreateAccessibilityRootNode() { accessibility_root_ = AccessibilityRootNode::Create(); } -gfx::NativeViewAccessible -WindowAXFragmentRootDelegate::GetChildOfAXFragmentRoot() { - return window_.GetNativeViewAccessible(); -} - -gfx::NativeViewAccessible -WindowAXFragmentRootDelegate::GetParentOfAXFragmentRoot() { - return nullptr; -} - -bool WindowAXFragmentRootDelegate::IsAXFragmentRootAControlElement() { - return true; -} - -WindowAXFragmentRootDelegate::WindowAXFragmentRootDelegate(Window& window) - : window_(window) {} - } // namespace flutter diff --git a/shell/platform/windows/window.h b/shell/platform/windows/window.h index 81b6691cc92fa..6c234ce68fc58 100644 --- a/shell/platform/windows/window.h +++ b/shell/platform/windows/window.h @@ -26,8 +26,6 @@ namespace flutter { -class WindowAXFragmentRootDelegate; - // A class abstraction for a high DPI aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling. @@ -310,31 +308,10 @@ class Window : public KeyboardManager::WindowDelegate { // Implements IRawElementProviderFragmentRoot when UIA is enabled. std::unique_ptr ax_fragment_root_; - // Delegate for Fragment. - std::unique_ptr ax_fragment_delegate_; - // Allow WindowAXFragmentRootDelegate to access protected method. friend class WindowAXFragmentRootDelegate; }; -// A delegate class to the window. -class WindowAXFragmentRootDelegate : public ui::AXFragmentRootDelegateWin { - public: - // | AXFragmentRootDelegateWin | - gfx::NativeViewAccessible GetChildOfAXFragmentRoot() override; - - // | AXFragmentRootDelegateWin | - gfx::NativeViewAccessible GetParentOfAXFragmentRoot() override; - - // | AXFragmentRootDelegateWin | - bool IsAXFragmentRootAControlElement() override; - - WindowAXFragmentRootDelegate(Window& window); - - private: - Window& window_; -}; - } // namespace flutter #endif // FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WIN32_WINDOW_H_ From 978657d0f274544badc0c66c59bf1d97fcc4d07f Mon Sep 17 00:00:00 2001 From: schectman Date: Mon, 28 Nov 2022 11:50:10 -0500 Subject: [PATCH 17/19] Format --- shell/platform/windows/accessibility_bridge_windows.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shell/platform/windows/accessibility_bridge_windows.cc b/shell/platform/windows/accessibility_bridge_windows.cc index c03bb3d72fe68..83435ce3a41b1 100644 --- a/shell/platform/windows/accessibility_bridge_windows.cc +++ b/shell/platform/windows/accessibility_bridge_windows.cc @@ -173,11 +173,13 @@ void AccessibilityBridgeWindows::SetFocus( node_delegate->SetFocus(); } -gfx::NativeViewAccessible AccessibilityBridgeWindows::GetChildOfAXFragmentRoot() { +gfx::NativeViewAccessible +AccessibilityBridgeWindows::GetChildOfAXFragmentRoot() { return view_->GetNativeViewAccessible(); } -gfx::NativeViewAccessible AccessibilityBridgeWindows::GetParentOfAXFragmentRoot() { +gfx::NativeViewAccessible +AccessibilityBridgeWindows::GetParentOfAXFragmentRoot() { return nullptr; } From ca62e045f99b2b16c05610f1fca17de95d9f8e0f Mon Sep 17 00:00:00 2001 From: schectman Date: Tue, 6 Dec 2022 12:35:42 -0500 Subject: [PATCH 18/19] Remove unneeded windowsx_shim imports --- shell/platform/windows/flutter_window.h | 1 - shell/platform/windows/flutter_windows_view.h | 1 - shell/platform/windows/testing/mock_text_input_manager.h | 1 - shell/platform/windows/testing/mock_window.h | 1 - shell/platform/windows/testing/mock_window_binding_handler.h | 1 - shell/platform/windows/testing/test_keyboard.cc | 1 - shell/platform/windows/testing/wm_builders.h | 2 -- 7 files changed, 8 deletions(-) diff --git a/shell/platform/windows/flutter_window.h b/shell/platform/windows/flutter_window.h index 3f66622b58f46..e80d98b801d6d 100644 --- a/shell/platform/windows/flutter_window.h +++ b/shell/platform/windows/flutter_window.h @@ -14,7 +14,6 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/window.h" #include "flutter/shell/platform/windows/window_binding_handler.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" namespace flutter { diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index cac647ea04721..2c0c719953f7c 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -26,7 +26,6 @@ #include "flutter/shell/platform/windows/window_binding_handler.h" #include "flutter/shell/platform/windows/window_binding_handler_delegate.h" #include "flutter/shell/platform/windows/window_state.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" namespace flutter { diff --git a/shell/platform/windows/testing/mock_text_input_manager.h b/shell/platform/windows/testing/mock_text_input_manager.h index 13e2427ca6b58..e51d218273207 100644 --- a/shell/platform/windows/testing/mock_text_input_manager.h +++ b/shell/platform/windows/testing/mock_text_input_manager.h @@ -9,7 +9,6 @@ #include #include "flutter/shell/platform/windows/text_input_manager.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" #include "gmock/gmock.h" namespace flutter { diff --git a/shell/platform/windows/testing/mock_window.h b/shell/platform/windows/testing/mock_window.h index 483404c06a0c9..78fabc663c1cf 100644 --- a/shell/platform/windows/testing/mock_window.h +++ b/shell/platform/windows/testing/mock_window.h @@ -7,7 +7,6 @@ #include "flutter/shell/platform/windows/testing/test_keyboard.h" #include "flutter/shell/platform/windows/window.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" #include "gmock/gmock.h" namespace flutter { diff --git a/shell/platform/windows/testing/mock_window_binding_handler.h b/shell/platform/windows/testing/mock_window_binding_handler.h index 04ebf734782cf..2fc5cbd77e905 100644 --- a/shell/platform/windows/testing/mock_window_binding_handler.h +++ b/shell/platform/windows/testing/mock_window_binding_handler.h @@ -6,7 +6,6 @@ #define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOW_BINDING_HANDLER_H_ #include "flutter/shell/platform/windows/window_binding_handler.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" #include "gmock/gmock.h" namespace flutter { diff --git a/shell/platform/windows/testing/test_keyboard.cc b/shell/platform/windows/testing/test_keyboard.cc index 92389b9bf5141..d752f027c80c0 100644 --- a/shell/platform/windows/testing/test_keyboard.cc +++ b/shell/platform/windows/testing/test_keyboard.cc @@ -5,7 +5,6 @@ #include "flutter/shell/platform/windows/testing/test_keyboard.h" #include "flutter/shell/platform/common/json_message_codec.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" -#include "flutter/shell/platform/windows/windowsx_shim.h" #include diff --git a/shell/platform/windows/testing/wm_builders.h b/shell/platform/windows/testing/wm_builders.h index a60732394afe2..49b78035b7e01 100644 --- a/shell/platform/windows/testing/wm_builders.h +++ b/shell/platform/windows/testing/wm_builders.h @@ -8,8 +8,6 @@ #include #include -#include "flutter/shell/platform/windows/windowsx_shim.h" - namespace flutter { namespace testing { From 77e0ba1e23499159d26995ad70345a7835f33214 Mon Sep 17 00:00:00 2001 From: schectman Date: Tue, 6 Dec 2022 15:24:03 -0500 Subject: [PATCH 19/19] PR Comment --- shell/platform/windows/window_binding_handler_delegate.h | 4 ++++ third_party/accessibility/ax/platform/ax_platform_node_win.cc | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/shell/platform/windows/window_binding_handler_delegate.h b/shell/platform/windows/window_binding_handler_delegate.h index 7bf13cab142c6..9d0e0253c447a 100644 --- a/shell/platform/windows/window_binding_handler_delegate.h +++ b/shell/platform/windows/window_binding_handler_delegate.h @@ -138,6 +138,10 @@ class WindowBindingHandlerDelegate { virtual void UpdateHighContrastEnabled(bool enabled) = 0; // Obtain a pointer to the fragment root delegate. + // This is required by UIA in order to obtain the fragment root that + // contains a fragment obtained by, for example, a hit test. Unlike + // MSAA, UIA elements do not explicitly store or enumerate their + // children and parents, so a method such as this is required. virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() = 0; }; diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win.cc b/third_party/accessibility/ax/platform/ax_platform_node_win.cc index d8578392093c2..9de6867ad9eed 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win.cc @@ -5218,10 +5218,8 @@ std::optional AXPlatformNodeWin::MojoEventToMSAAEvent( return EVENT_OBJECT_SHOW; case ax::mojom::Event::kValueChanged: return EVENT_OBJECT_VALUECHANGE; -#ifdef EVENT_OBJECT_TEXTSELECTIONCHANGED case ax::mojom::Event::kDocumentSelectionChanged: return EVENT_OBJECT_TEXTSELECTIONCHANGED; -#endif default: return std::nullopt; }