From db58ba381e201f256c937ed0bce44ceab78b4e71 Mon Sep 17 00:00:00 2001 From: Chiara Mooney <34109996+chiaramooney@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:01:14 -0700 Subject: [PATCH 1/6] Add Support for ControlType Specification --- .../Composition/ActivityIndicatorComponentView.cpp | 4 ++++ .../Composition/ActivityIndicatorComponentView.h | 1 + .../CompositionDynamicAutomationProvider.cpp | 12 ++++++++++-- .../Composition/CompositionViewComponentView.cpp | 11 +++++++++++ .../Composition/CompositionViewComponentView.h | 3 +++ .../Fabric/Composition/ImageComponentView.cpp | 4 ++++ .../Fabric/Composition/ImageComponentView.h | 1 + .../Fabric/Composition/ParagraphComponentView.cpp | 4 ++++ .../Fabric/Composition/ParagraphComponentView.h | 1 + .../Fabric/Composition/ScrollViewComponentView.cpp | 4 ++++ .../Fabric/Composition/ScrollViewComponentView.h | 1 + .../Fabric/Composition/SwitchComponentView.cpp | 4 ++++ .../Fabric/Composition/SwitchComponentView.h | 1 + .../TextInput/WindowsTextInputComponentView.cpp | 4 ++++ .../TextInput/WindowsTextInputComponentView.h | 1 + 15 files changed, 54 insertions(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp index 466a0c4bb0d..52a8a4ed0bd 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp @@ -126,4 +126,8 @@ bool ActivityIndicatorComponentView::focusable() const noexcept { return false; } +std::string ActivityIndicatorComponentView::DefaultControlType() const noexcept { + return "progressbar"; +} + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h index 359f214ba8f..ca1afa63e03 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h @@ -40,6 +40,7 @@ struct ActivityIndicatorComponentView : CompositionBaseComponentView { facebook::react::Tag hitTest(facebook::react::Point pt, facebook::react::Point &localPt, bool ignorePointerEvents) const noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ActivityIndicatorComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 4975fcfc64f..298cf332fc0 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -135,7 +135,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE long GetControlType(const std::string &role) noexcept { if (role == "adjustable") { return UIA_SliderControlTypeId; - } else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) { + } else if (role == "group" || role == "radiogroup" || role == "timer" || role.empty()) { return UIA_GroupControlTypeId; } else if (role == "button" || role == "imagebutton" || role == "switch" || role == "togglebutton") { return UIA_ButtonControlTypeId; @@ -182,6 +182,10 @@ long GetControlType(const std::string &role) noexcept { return UIA_TabItemControlTypeId; } else if (role == "tablist") { return UIA_TabControlTypeId; + } else if (role == "text") { + return UIA_TextControlTypeId; + } else if (role == "textinput" || role == "searchbox" || role == "search") { + return UIA_EditControlTypeId; } else if (role == "toolbar") { return UIA_ToolBarControlTypeId; } else if (role == "tree") { @@ -205,12 +209,16 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT if (props == nullptr) return UIA_E_ELEMENTNOTAVAILABLE; + auto baseView = std::static_pointer_cast<::Microsoft::ReactNative::CompositionBaseComponentView>(strongView); + if (baseView == nullptr) + return UIA_E_ELEMENTNOTAVAILABLE; + auto hr = S_OK; switch (propertyId) { case UIA_ControlTypePropertyId: { pRetVal->vt = VT_I4; - auto role = props->accessibilityRole; + auto role = props->accessibilityRole == "" ? baseView.get()->DefaultControlType() : props->accessibilityRole; pRetVal->lVal = GetControlType(role); break; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index 0a67532ea24..bf2bda3478e 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1091,6 +1091,9 @@ void CompositionBaseComponentView::updateAccessibilityProps( UIA_IsEnabledPropertyId, !oldViewProps.accessibilityState.disabled, !newViewProps.accessibilityState.disabled); + + winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( + provider, UIA_ControlTypePropertyId, oldViewProps.accessibilityRole, newViewProps.accessibilityRole); } void CompositionBaseComponentView::updateBorderLayoutMetrics( @@ -1212,6 +1215,10 @@ bool CompositionBaseComponentView::focusable() const noexcept { return false; } +std::string CompositionBaseComponentView::DefaultControlType() const noexcept { + return "group"; +} + CompositionViewComponentView::CompositionViewComponentView( const winrt::Microsoft::ReactNative::Composition::ICompositionContext &compContext, facebook::react::Tag tag) @@ -1413,6 +1420,10 @@ bool CompositionViewComponentView::focusable() const noexcept { return m_props->focusable; } +std::string CompositionViewComponentView::DefaultControlType() const noexcept { + return "group"; +} + IComponentView *lastDeepChild(IComponentView &view) noexcept { auto current = &view; while (current) { diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h index c47e704940f..9c9db7c33a7 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h @@ -66,6 +66,8 @@ struct CompositionBaseComponentView : public IComponentView, winrt::IInspectable EnsureUiaProvider() noexcept override; + virtual std::string DefaultControlType() const noexcept; + protected: std::array FindSpecialBorderLayers() const noexcept; @@ -116,6 +118,7 @@ struct CompositionViewComponentView : public CompositionBaseComponentView { void finalizeUpdates(RNComponentViewUpdateMask updateMask) noexcept override; void prepareForRecycle() noexcept override; bool focusable() const noexcept override; + std::string DefaultControlType() const noexcept override; facebook::react::Props::Shared props() noexcept override; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp index 4f73b625964..9ba850d67aa 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp @@ -409,6 +409,10 @@ bool ImageComponentView::focusable() const noexcept { return m_props->focusable; } +std::string ImageComponentView::DefaultControlType() const noexcept { + return "image"; +} + std::shared_ptr ImageComponentView::Create( const winrt::Microsoft::ReactNative::Composition::ICompositionContext &compContext, facebook::react::Tag tag, diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h index ab80d091e9f..041bbf54bba 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h @@ -53,6 +53,7 @@ struct ImageComponentView : CompositionBaseComponentView { const noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; bool focusable() const noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ImageComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp index f6b20b95df3..cca1f273352 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp @@ -474,6 +474,10 @@ void ParagraphComponentView::DrawText() noexcept { } } +std::string ParagraphComponentView::DefaultControlType() const noexcept { + return "text"; +} + winrt::Microsoft::ReactNative::Composition::IVisual ParagraphComponentView::Visual() const noexcept { return m_visual; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h index 530785676f1..10fb1b7765b 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h @@ -42,6 +42,7 @@ struct ParagraphComponentView : CompositionBaseComponentView { facebook::react::SharedTouchEventEmitter touchEventEmitterAtPoint(facebook::react::Point pt) noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ParagraphComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index 93c47aa8f48..24ff2846d92 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -460,4 +460,8 @@ winrt::Microsoft::ReactNative::Composition::IVisual ScrollViewComponentView::Vis return m_visual; } + std::string ScrollViewComponentView::DefaultControlType() const noexcept { + return "scrollbar"; + } + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h index 343e5152f30..c6e53f0d93d 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h @@ -79,6 +79,7 @@ struct ScrollInteractionTrackerOwner : public winrt::implements< bool ScrollWheel(facebook::react::Point pt, int32_t delta) noexcept override; void StartBringIntoView(BringIntoViewOptions &&args) noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ScrollViewComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp index fc10b0bc5ad..05642ac0a26 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp @@ -266,4 +266,8 @@ bool SwitchComponentView::focusable() const noexcept { return m_props->focusable; } +std::string SwitchComponentView::DefaultControlType() const noexcept { + return "switch"; +} + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h index 46f53e28301..545fc09d112 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h @@ -42,6 +42,7 @@ struct SwitchComponentView : CompositionBaseComponentView { const noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; int64_t sendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept override; + std::string DefaultControlType() const noexcept override; private: SwitchComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index 81b16f77204..e7189a12d17 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -594,6 +594,10 @@ bool WindowsTextInputComponentView::focusable() const noexcept { return m_props->focusable; } +std::string WindowsTextInputComponentView::DefaultControlType() const noexcept { + return "textinput"; +} + void WindowsTextInputComponentView::updateProps( facebook::react::Props::Shared const &props, facebook::react::Props::Shared const &oldProps) noexcept { diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h index 4e949bc1298..56a86ab26ad 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h @@ -52,6 +52,7 @@ struct WindowsTextInputComponentView : CompositionBaseComponentView { void onFocusLost() noexcept override; void onFocusGained() noexcept override; bool focusable() const noexcept override; + std::string DefaultControlType() const noexcept override; private: WindowsTextInputComponentView( From 98cdc1ebeb082e76e63b65710c8a986c15c8669a Mon Sep 17 00:00:00 2001 From: Chiara Mooney <34109996+chiaramooney@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:34:42 -0700 Subject: [PATCH 2/6] Change files --- ...ative-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json diff --git a/change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json b/change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json new file mode 100644 index 00000000000..26539d7ae88 --- /dev/null +++ b/change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add Support for ControlType Specification", + "packageName": "react-native-windows", + "email": "34109996+chiaramooney@users.noreply.github.com", + "dependentChangeType": "patch" +} From 255ad5e49d483b9a5ffd11089780d0841f45013a Mon Sep 17 00:00:00 2001 From: Chiara Mooney <34109996+chiaramooney@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:02:30 -0700 Subject: [PATCH 3/6] Format --- .../Fabric/Composition/ScrollViewComponentView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index 24ff2846d92..3d7ceab58e4 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -460,8 +460,8 @@ winrt::Microsoft::ReactNative::Composition::IVisual ScrollViewComponentView::Vis return m_visual; } - std::string ScrollViewComponentView::DefaultControlType() const noexcept { +std::string ScrollViewComponentView::DefaultControlType() const noexcept { return "scrollbar"; - } +} } // namespace Microsoft::ReactNative From c0d7f16dce6ebe617d9efb6c27dd07733fa76ae3 Mon Sep 17 00:00:00 2001 From: Chiara Mooney <34109996+chiaramooney@users.noreply.github.com> Date: Thu, 13 Jul 2023 16:17:23 -0700 Subject: [PATCH 4/6] Fix Switch Statement --- .../Composition/CompositionDynamicAutomationProvider.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 298cf332fc0..834a2204b06 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -135,7 +135,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE long GetControlType(const std::string &role) noexcept { if (role == "adjustable") { return UIA_SliderControlTypeId; - } else if (role == "group" || role == "radiogroup" || role == "timer" || role.empty()) { + } else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) { return UIA_GroupControlTypeId; } else if (role == "button" || role == "imagebutton" || role == "switch" || role == "togglebutton") { return UIA_ButtonControlTypeId; @@ -184,7 +184,7 @@ long GetControlType(const std::string &role) noexcept { return UIA_TabControlTypeId; } else if (role == "text") { return UIA_TextControlTypeId; - } else if (role == "textinput" || role == "searchbox" || role == "search") { + } else if (role == "textinput" || role == "searchbox") { return UIA_EditControlTypeId; } else if (role == "toolbar") { return UIA_ToolBarControlTypeId; From 8209ca749865cd5e6230f6b9e70377509dc4f492 Mon Sep 17 00:00:00 2001 From: Chiara Mooney <34109996+chiaramooney@users.noreply.github.com> Date: Thu, 13 Jul 2023 16:24:50 -0700 Subject: [PATCH 5/6] Format --- .../Fabric/Composition/CompositionDynamicAutomationProvider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 834a2204b06..3a9107b0155 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -135,7 +135,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE long GetControlType(const std::string &role) noexcept { if (role == "adjustable") { return UIA_SliderControlTypeId; - } else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) { + } else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) { return UIA_GroupControlTypeId; } else if (role == "button" || role == "imagebutton" || role == "switch" || role == "togglebutton") { return UIA_ButtonControlTypeId; From 2d9619ccb05c13001d55ea0baea57f731acf2782 Mon Sep 17 00:00:00 2001 From: Chiara Mooney <34109996+chiaramooney@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:00:41 -0700 Subject: [PATCH 6/6] Remove Dup --- .../Fabric/Composition/CompositionDynamicAutomationProvider.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 3a9107b0155..25de87e540d 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -182,8 +182,6 @@ long GetControlType(const std::string &role) noexcept { return UIA_TabItemControlTypeId; } else if (role == "tablist") { return UIA_TabControlTypeId; - } else if (role == "text") { - return UIA_TextControlTypeId; } else if (role == "textinput" || role == "searchbox") { return UIA_EditControlTypeId; } else if (role == "toolbar") {