From 0f6bdf3ab5085bccfabf3a8d65733287cb565855 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 8 Nov 2023 18:44:57 -0500 Subject: [PATCH] Adds option to allow ViewManagers to capture pointer (#8969) * Adds option to allow ViewManagers to capture pointer Adds property to ReactPointerEventArgs to allow view managers to capture the pointer while still allowing RN to emit events to JS. XAML only allows capturing the pointer on PointerPressed, so this would allow, for example, a view manager that supports custom native drag behaviors that have a threshold for action (and when that threshold is not exceeded, the gesture is handled by RN). * Change files --- ...windows-1fca69d4-5eb2-4787-91ff-91a19b4fbad9.json | 7 +++++++ .../Microsoft.ReactNative/ReactPointerEventArgs.cpp | 8 ++++++++ vnext/Microsoft.ReactNative/ReactPointerEventArgs.h | 4 ++++ .../Microsoft.ReactNative/ReactPointerEventArgs.idl | 12 ++++++++++++ .../Views/TouchEventHandler.cpp | 2 +- 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 change/react-native-windows-1fca69d4-5eb2-4787-91ff-91a19b4fbad9.json diff --git a/change/react-native-windows-1fca69d4-5eb2-4787-91ff-91a19b4fbad9.json b/change/react-native-windows-1fca69d4-5eb2-4787-91ff-91a19b4fbad9.json new file mode 100644 index 00000000000..50e34233a8a --- /dev/null +++ b/change/react-native-windows-1fca69d4-5eb2-4787-91ff-91a19b4fbad9.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "applying package updates ***NO_CI***", + "packageName": "react-native-windows", + "email": "erozell@outlook.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Microsoft.ReactNative/ReactPointerEventArgs.cpp b/vnext/Microsoft.ReactNative/ReactPointerEventArgs.cpp index f22454e8143..63f494c061e 100644 --- a/vnext/Microsoft.ReactNative/ReactPointerEventArgs.cpp +++ b/vnext/Microsoft.ReactNative/ReactPointerEventArgs.cpp @@ -39,6 +39,14 @@ void ReactPointerEventArgs::Target(winrt::IInspectable const &target) noexcept { m_target = target; } +bool ReactPointerEventArgs::AllowUncaptured() const noexcept { + return m_allowUncaptured; +} + +void ReactPointerEventArgs::AllowUncaptured(bool allowUncaptured) noexcept { + m_allowUncaptured = allowUncaptured; +} + ReactPointerEventArgs::ReactPointerEventArgs( PointerEventKind kind, xaml::Input::PointerRoutedEventArgs const &args) noexcept diff --git a/vnext/Microsoft.ReactNative/ReactPointerEventArgs.h b/vnext/Microsoft.ReactNative/ReactPointerEventArgs.h index 907b85e0d13..f844b4f1b37 100644 --- a/vnext/Microsoft.ReactNative/ReactPointerEventArgs.h +++ b/vnext/Microsoft.ReactNative/ReactPointerEventArgs.h @@ -16,6 +16,9 @@ struct ReactPointerEventArgs : ReactPointerEventArgsT { winrt::IInspectable Target() const noexcept; void Target(winrt::IInspectable const &target) noexcept; + bool AllowUncaptured() const noexcept; + void AllowUncaptured(bool allowUncaptured) noexcept; + // Internal use ReactPointerEventArgs(PointerEventKind kind, xaml::Input::PointerRoutedEventArgs const &args) noexcept; @@ -23,6 +26,7 @@ struct ReactPointerEventArgs : ReactPointerEventArgsT { PointerEventKind m_kind; xaml::Input::PointerRoutedEventArgs const &m_args; winrt::IInspectable m_target{nullptr}; + bool m_allowUncaptured{false}; }; } // namespace winrt::Microsoft::ReactNative::implementation diff --git a/vnext/Microsoft.ReactNative/ReactPointerEventArgs.idl b/vnext/Microsoft.ReactNative/ReactPointerEventArgs.idl index 00d2c424017..66f9aa02c98 100644 --- a/vnext/Microsoft.ReactNative/ReactPointerEventArgs.idl +++ b/vnext/Microsoft.ReactNative/ReactPointerEventArgs.idl @@ -63,5 +63,17 @@ namespace Microsoft.ReactNative { get; set; }; + DOC_STRING( + "Gets or sets a flag that allows the ReactRootView to handle pointer " + "events even when it does not capture the pointer. This is particularly " + "useful for view managers that seek to capture the pointer to handle " + "move events for a gesture (e.g., dragging), but conditionally may " + "allow the ReactRootView to emit events (e.g., if the " + "@PointerEventKind.End event is received before a drag threshold is hit." + ) + Boolean AllowUncaptured { + get; + set; + }; } } // namespace Microsoft.ReactNative diff --git a/vnext/Microsoft.ReactNative/Views/TouchEventHandler.cpp b/vnext/Microsoft.ReactNative/Views/TouchEventHandler.cpp index f3c616de52d..8eb49fac670 100644 --- a/vnext/Microsoft.ReactNative/Views/TouchEventHandler.cpp +++ b/vnext/Microsoft.ReactNative/Views/TouchEventHandler.cpp @@ -119,7 +119,7 @@ void TouchEventHandler::OnPointerPressed( return; } - if (m_xamlView.as().CapturePointer(args.Pointer())) { + if (reactArgs.AllowUncaptured() || m_xamlView.as().CapturePointer(args.Pointer())) { assert(!tagsForBranch.empty()); const auto tag = tagsForBranch.front();