From fe357d75116f8d3332390ad755bf013beff8caea Mon Sep 17 00:00:00 2001 From: Yajur Grover Date: Wed, 18 Oct 2023 15:58:33 -0700 Subject: [PATCH 1/6] value provider changes --- .../CompositionDynamicAutomationProvider.cpp | 66 ++++++++++++++++++- .../CompositionDynamicAutomationProvider.h | 9 ++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index bb23cc81e62..347b7e2dd09 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -137,6 +137,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE if (props == nullptr) return UIA_E_ELEMENTNOTAVAILABLE; auto accessibilityRole = props->accessibilityRole; + auto accessibilityValue = props->accessibilityValue; // Invoke control pattern is used to support controls that do not maintain state // when activated but rather initiate or perform a single, unambiguous action. if (patternId == UIA_InvokePatternId && @@ -147,6 +148,11 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE AddRef(); } + if (patternId == UIA_ValuePatternId && accessibilityValue.text.has_value()) { + *pRetVal = static_cast(this); + AddRef(); + } + return S_OK; } @@ -327,4 +333,62 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::Invoke() { return S_OK; } -} // namespace winrt::Microsoft::ReactNative::implementation +std::string convertLPCWSTRToString(LPCWSTR val) { + int strLength = WideCharToMultiByte(CP_UTF8, 0, val, -1, nullptr, 0, nullptr, nullptr); + std::string str(strLength, 0); + WideCharToMultiByte(CP_UTF8, 0, val, -1, &str[0], strLength, nullptr, nullptr); + return str; +} + +BSTR StringToBSTR(const std::string &str) { + // Calculate the required BSTR size in bytes + int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0); + if (len == 0) { + return nullptr; // Conversion error + } + + // Allocate memory for the BSTR + BSTR bstr = SysAllocStringLen(nullptr, len - 1); // len includes the null terminator + + // Convert the std::string to BSTR + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bstr, len); + + return bstr; +} + +HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(LPCWSTR val) { + auto strongView = m_view.view(); + + if (!strongView) + return UIA_E_ELEMENTNOTAVAILABLE; + + auto props = std::static_pointer_cast(strongView->props()); + std::string value = convertLPCWSTRToString(val); + auto baseView = std::static_pointer_cast<::Microsoft::ReactNative::CompositionBaseComponentView>(strongView); + if (baseView == nullptr) + return UIA_E_ELEMENTNOTAVAILABLE; + winrt::IInspectable uiaProvider = baseView->EnsureUiaProvider(); + UpdateUiaProperty(uiaProvider, UIA_ValueValuePropertyId, *props->accessibilityValue.text, value); + + return S_OK; +} + +HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(BSTR* pRetVal) { + if (pRetVal == nullptr) + return E_POINTER; + auto strongView = m_view.view(); + + if (!strongView) + return UIA_E_ELEMENTNOTAVAILABLE; + + auto props = std::static_pointer_cast(strongView->props()); + *pRetVal = StringToBSTR(*props->accessibilityValue.text); + + return S_OK; +} + +HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsReadOnly(BOOL* pRetVal) { + return S_OK; +} + +} // namespace winrt::Microsoft::ReactNative::implementation \ No newline at end of file diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h index 6e800104c3e..facd857fe85 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h @@ -13,7 +13,8 @@ class CompositionDynamicAutomationProvider : public winrt::implements< IInspectable, IRawElementProviderFragment, IRawElementProviderSimple, - IInvokeProvider> { + IInvokeProvider, + IValueProvider> { public: CompositionDynamicAutomationProvider( const std::shared_ptr<::Microsoft::ReactNative::CompositionBaseComponentView> &componentView) noexcept; @@ -36,8 +37,12 @@ class CompositionDynamicAutomationProvider : public winrt::implements< // inherited via IInvokeProvider virtual HRESULT __stdcall Invoke() override; + // inherited via IValueProvider + virtual HRESULT __stdcall SetValue(LPCWSTR val) override; + virtual HRESULT __stdcall get_Value(BSTR *pRetVal) override; + virtual HRESULT __stdcall get_IsReadOnly(BOOL *pRetVal) override; private: ::Microsoft::ReactNative::ReactTaggedView m_view; }; -} // namespace winrt::Microsoft::ReactNative::implementation +} // namespace winrt::Microsoft::ReactNative::implementation \ No newline at end of file From d22a18cd94a7d0375de530383d470d077cdff81a Mon Sep 17 00:00:00 2001 From: Yajur Grover Date: Wed, 18 Oct 2023 16:00:03 -0700 Subject: [PATCH 2/6] Change files --- ...ative-windows-008fe6b2-a10c-4b12-b46e-00415bf35fce.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-008fe6b2-a10c-4b12-b46e-00415bf35fce.json diff --git a/change/react-native-windows-008fe6b2-a10c-4b12-b46e-00415bf35fce.json b/change/react-native-windows-008fe6b2-a10c-4b12-b46e-00415bf35fce.json new file mode 100644 index 00000000000..125caa01ebc --- /dev/null +++ b/change/react-native-windows-008fe6b2-a10c-4b12-b46e-00415bf35fce.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "value provider changes", + "packageName": "react-native-windows", + "email": "yajurgrover24@gmail.com", + "dependentChangeType": "patch" +} From 3e0df00800ff58a4fdcae6422467cc318f415a00 Mon Sep 17 00:00:00 2001 From: Yajur Grover Date: Wed, 18 Oct 2023 16:01:07 -0700 Subject: [PATCH 3/6] fix formatting --- .../Composition/CompositionDynamicAutomationProvider.cpp | 4 ++-- .../Fabric/Composition/CompositionDynamicAutomationProvider.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 347b7e2dd09..9d1506416d2 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -373,7 +373,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(LPCWSTR val) { return S_OK; } -HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(BSTR* pRetVal) { +HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(BSTR *pRetVal) { if (pRetVal == nullptr) return E_POINTER; auto strongView = m_view.view(); @@ -387,7 +387,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(BSTR* pRetVal) return S_OK; } -HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsReadOnly(BOOL* pRetVal) { +HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsReadOnly(BOOL *pRetVal) { return S_OK; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h index facd857fe85..da0d7053c29 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h @@ -41,6 +41,7 @@ class CompositionDynamicAutomationProvider : public winrt::implements< virtual HRESULT __stdcall SetValue(LPCWSTR val) override; virtual HRESULT __stdcall get_Value(BSTR *pRetVal) override; virtual HRESULT __stdcall get_IsReadOnly(BOOL *pRetVal) override; + private: ::Microsoft::ReactNative::ReactTaggedView m_view; }; From 11fb0a5ae7d8f303362c2ee9ed75daa3220f16b5 Mon Sep 17 00:00:00 2001 From: Yajur Grover Date: Thu, 19 Oct 2023 10:22:26 -0700 Subject: [PATCH 4/6] fixed string conversion --- .../CompositionDynamicAutomationProvider.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 9d1506416d2..54ee249b9bf 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -333,13 +333,6 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::Invoke() { return S_OK; } -std::string convertLPCWSTRToString(LPCWSTR val) { - int strLength = WideCharToMultiByte(CP_UTF8, 0, val, -1, nullptr, 0, nullptr, nullptr); - std::string str(strLength, 0); - WideCharToMultiByte(CP_UTF8, 0, val, -1, &str[0], strLength, nullptr, nullptr); - return str; -} - BSTR StringToBSTR(const std::string &str) { // Calculate the required BSTR size in bytes int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0); @@ -363,7 +356,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(LPCWSTR val) { return UIA_E_ELEMENTNOTAVAILABLE; auto props = std::static_pointer_cast(strongView->props()); - std::string value = convertLPCWSTRToString(val); + std::string value = winrt::to_string(val); auto baseView = std::static_pointer_cast<::Microsoft::ReactNative::CompositionBaseComponentView>(strongView); if (baseView == nullptr) return UIA_E_ELEMENTNOTAVAILABLE; @@ -391,4 +384,4 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsReadOnly(BOOL *pRe return S_OK; } -} // namespace winrt::Microsoft::ReactNative::implementation \ No newline at end of file +} // namespace winrt::Microsoft::ReactNative::implementation From 8a2b5eec8095c7c7cad52a8757e23884a87c28d7 Mon Sep 17 00:00:00 2001 From: Yajur Grover Date: Thu, 19 Oct 2023 16:16:32 -0700 Subject: [PATCH 5/6] addressed feedback --- .../CompositionDynamicAutomationProvider.cpp | 4 +--- .../CompositionViewComponentView.cpp | 17 +++++++++++++++++ .../Composition/CompositionViewComponentView.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 54ee249b9bf..e59c796b237 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -360,9 +360,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(LPCWSTR val) { auto baseView = std::static_pointer_cast<::Microsoft::ReactNative::CompositionBaseComponentView>(strongView); if (baseView == nullptr) return UIA_E_ELEMENTNOTAVAILABLE; - winrt::IInspectable uiaProvider = baseView->EnsureUiaProvider(); - UpdateUiaProperty(uiaProvider, UIA_ValueValuePropertyId, *props->accessibilityValue.text, value); - + baseView->updateAccessibilityValue(value); return S_OK; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index e79e92a61b7..cb33b80cc55 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1305,6 +1305,17 @@ void CompositionBaseComponentView::EnsureTransformMatrixFacade() noexcept { } } +void CompositionBaseComponentView::updateAccessibilityValue(std::string newValue) noexcept { + auto props = std::static_pointer_cast(this->props()); + if (newValue != props->accessibilityValue.text) { + auto provider = EnsureUiaProvider(); + if (provider != nullptr) { + winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( + provider, UIA_ValueValuePropertyId, *props->accessibilityValue.text, newValue); + } + } +} + facebook::react::SharedViewEventEmitter CompositionBaseComponentView::eventEmitter() noexcept { return m_eventEmitter; } @@ -1387,6 +1398,12 @@ void CompositionViewComponentView::updateProps( m_visual.Opacity(newViewProps.opacity); } + if (oldViewProps.accessibilityValue.text.has_value() && + newViewProps.accessibilityValue.text.has_value() && + oldViewProps.accessibilityValue.text != newViewProps.accessibilityValue.text) { + updateAccessibilityValue(*newViewProps.accessibilityValue.text); + } + // update BaseComponentView props updateAccessibilityProps(oldViewProps, newViewProps); updateShadowProps(oldViewProps, newViewProps, m_visual); diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h index 08f0b04de36..675dca42ca1 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h @@ -35,6 +35,7 @@ struct CompositionBaseComponentView : public IComponentView, bool runOnChildren(bool forward, Mso::Functor &fn) noexcept override; void onFocusLost() noexcept override; void onFocusGained() noexcept override; + void updateAccessibilityValue(std::string newValue) noexcept; void onPointerEntered( const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept override; void onPointerExited( From 4178883b16710332b807513578c29ebab0298edc Mon Sep 17 00:00:00 2001 From: Yajur Grover Date: Thu, 19 Oct 2023 16:42:29 -0700 Subject: [PATCH 6/6] formatting fix --- .../Fabric/Composition/CompositionViewComponentView.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index cb33b80cc55..048f39b8043 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1398,8 +1398,7 @@ void CompositionViewComponentView::updateProps( m_visual.Opacity(newViewProps.opacity); } - if (oldViewProps.accessibilityValue.text.has_value() && - newViewProps.accessibilityValue.text.has_value() && + if (oldViewProps.accessibilityValue.text.has_value() && newViewProps.accessibilityValue.text.has_value() && oldViewProps.accessibilityValue.text != newViewProps.accessibilityValue.text) { updateAccessibilityValue(*newViewProps.accessibilityValue.text); }