react-native-windows 0.81.13 → 0.81.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Common/Common.vcxproj +1 -1
- package/Folly/Folly.vcxproj +1 -1
- package/Libraries/Modal/Modal.windows.js +1 -7
- package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.cpp +73 -97
- package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.h +4 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +58 -21
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +253 -58
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +18 -4
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +149 -27
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +10 -0
- package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +5 -0
- package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +2 -0
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +3 -1
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +4 -6
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +101 -44
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +4 -2
- package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +3 -3
- package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.h +3 -1
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +0 -1
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/HostPlatformColor.h +3 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.cpp +2 -7
- package/Microsoft.ReactNative/IReactPackageBuilder.idl +5 -0
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +2 -2
- package/Microsoft.ReactNative/Modules/Animated/AnimatedNode.cpp +3 -3
- package/Microsoft.ReactNative/Modules/Animated/AnimatedNode.h +3 -2
- package/Microsoft.ReactNative/Modules/Timing.h +2 -1
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +2 -0
- package/Microsoft.ReactNative/ReactPackageBuilder.cpp +7 -0
- package/Microsoft.ReactNative/ReactPackageBuilder.h +1 -0
- package/Microsoft.ReactNative/TurboModulesProvider.cpp +5 -10
- package/Microsoft.ReactNative/TurboModulesProvider.h +2 -0
- package/Microsoft.ReactNative.Cxx/ModuleRegistration.cpp +8 -2
- package/Microsoft.ReactNative.Cxx/ModuleRegistration.h +17 -4
- package/Microsoft.ReactNative.Cxx/NativeModules.h +5 -0
- package/PropertySheets/External/Microsoft.ReactNative.Composition.CppApp.targets +2 -2
- package/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.targets +2 -2
- package/PropertySheets/External/Microsoft.ReactNative.Uwp.CSharpApp.targets +1 -1
- package/PropertySheets/External/Microsoft.ReactNative.Uwp.CppApp.targets +1 -1
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/JSEngine.props +2 -1
- package/PropertySheets/WinUI.props +3 -3
- package/ReactCommon/ReactCommon.vcxproj +1 -1
- package/Scripts/OfficeReact.Win32.nuspec +44 -44
- package/Scripts/Tfs/Invoke-WebRequestWithRetry.ps1 +40 -0
- package/Scripts/Tfs/Layout-Desktop-Headers.ps1 +1 -15
- package/Shared/Shared.vcxitems.filters +2 -2
- package/package.json +1 -1
- package/Scripts/OpenSSL.nuspec +0 -39
- package/Scripts/OpenSSL.targets +0 -36
|
@@ -253,7 +253,10 @@ void CompositionEventHandler::Initialize() noexcept {
|
|
|
253
253
|
if (strongThis->SurfaceId() == -1)
|
|
254
254
|
return;
|
|
255
255
|
|
|
256
|
-
auto
|
|
256
|
+
auto *rootView = strongThis->RootComponentView();
|
|
257
|
+
if (!rootView)
|
|
258
|
+
return;
|
|
259
|
+
auto focusedComponent = rootView->GetFocusedComponent();
|
|
257
260
|
auto keyboardSource = winrt::make<CompositionInputKeyboardSource>(source);
|
|
258
261
|
auto keyArgs =
|
|
259
262
|
winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::KeyRoutedEventArgs>(
|
|
@@ -279,7 +282,10 @@ void CompositionEventHandler::Initialize() noexcept {
|
|
|
279
282
|
if (strongThis->SurfaceId() == -1)
|
|
280
283
|
return;
|
|
281
284
|
|
|
282
|
-
auto
|
|
285
|
+
auto *rootView = strongThis->RootComponentView();
|
|
286
|
+
if (!rootView)
|
|
287
|
+
return;
|
|
288
|
+
auto focusedComponent = rootView->GetFocusedComponent();
|
|
283
289
|
auto keyboardSource = winrt::make<CompositionInputKeyboardSource>(source);
|
|
284
290
|
auto keyArgs =
|
|
285
291
|
winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::KeyRoutedEventArgs>(
|
|
@@ -306,7 +312,10 @@ void CompositionEventHandler::Initialize() noexcept {
|
|
|
306
312
|
if (strongThis->SurfaceId() == -1)
|
|
307
313
|
return;
|
|
308
314
|
|
|
309
|
-
auto
|
|
315
|
+
auto *rootView = strongThis->RootComponentView();
|
|
316
|
+
if (!rootView)
|
|
317
|
+
return;
|
|
318
|
+
auto focusedComponent = rootView->GetFocusedComponent();
|
|
310
319
|
auto keyboardSource = winrt::make<CompositionInputKeyboardSource>(source);
|
|
311
320
|
auto charArgs = winrt::make<
|
|
312
321
|
winrt::Microsoft::ReactNative::Composition::Input::implementation::CharacterReceivedRoutedEventArgs>(
|
|
@@ -333,7 +342,10 @@ void CompositionEventHandler::Initialize() noexcept {
|
|
|
333
342
|
if (strongThis->SurfaceId() == -1)
|
|
334
343
|
return;
|
|
335
344
|
|
|
336
|
-
auto
|
|
345
|
+
auto *rootView = strongThis->RootComponentView();
|
|
346
|
+
if (!rootView)
|
|
347
|
+
return;
|
|
348
|
+
auto focusedComponent = rootView->GetFocusedComponent();
|
|
337
349
|
if (focusedComponent) {
|
|
338
350
|
auto tag =
|
|
339
351
|
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(focusedComponent)
|
|
@@ -363,6 +375,7 @@ CompositionEventHandler::~CompositionEventHandler() {
|
|
|
363
375
|
pointerSource.PointerMoved(m_pointerMovedToken);
|
|
364
376
|
pointerSource.PointerCaptureLost(m_pointerCaptureLostToken);
|
|
365
377
|
pointerSource.PointerWheelChanged(m_pointerWheelChangedToken);
|
|
378
|
+
pointerSource.PointerExited(m_pointerExitedToken);
|
|
366
379
|
auto keyboardSource = winrt::Microsoft::UI::Input::InputKeyboardSource::GetForIsland(island);
|
|
367
380
|
keyboardSource.KeyDown(m_keyDownToken);
|
|
368
381
|
keyboardSource.KeyUp(m_keyUpToken);
|
|
@@ -386,10 +399,15 @@ facebook::react::SurfaceId CompositionEventHandler::SurfaceId() const noexcept {
|
|
|
386
399
|
return -1;
|
|
387
400
|
}
|
|
388
401
|
|
|
389
|
-
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView
|
|
402
|
+
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *
|
|
390
403
|
CompositionEventHandler::RootComponentView() const noexcept {
|
|
391
404
|
auto island = m_wkRootView.get();
|
|
392
|
-
|
|
405
|
+
if (!island) {
|
|
406
|
+
return nullptr;
|
|
407
|
+
}
|
|
408
|
+
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(island)
|
|
409
|
+
->GetComponentView()
|
|
410
|
+
.get();
|
|
393
411
|
}
|
|
394
412
|
|
|
395
413
|
void CompositionEventHandler::onPointerWheelChanged(
|
|
@@ -404,8 +422,11 @@ void CompositionEventHandler::onPointerWheelChanged(
|
|
|
404
422
|
|
|
405
423
|
// In the case of a sub rootview, we may have a non-zero origin. hitTest takes a pt in the parent coords, so we
|
|
406
424
|
// need to apply the current origin
|
|
407
|
-
|
|
408
|
-
|
|
425
|
+
auto *rootView = RootComponentView();
|
|
426
|
+
if (!rootView)
|
|
427
|
+
return;
|
|
428
|
+
ptScaled += rootView->layoutMetrics().frame.origin;
|
|
429
|
+
auto tag = rootView->hitTest(ptScaled, ptLocal);
|
|
409
430
|
|
|
410
431
|
if (tag == -1)
|
|
411
432
|
return;
|
|
@@ -559,7 +580,10 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
|
|
|
559
580
|
case WM_CHAR:
|
|
560
581
|
case WM_SYSCHAR: {
|
|
561
582
|
if (auto strongRootView = m_wkRootView.get()) {
|
|
562
|
-
auto
|
|
583
|
+
auto *rootView = RootComponentView();
|
|
584
|
+
if (!rootView)
|
|
585
|
+
break;
|
|
586
|
+
auto focusedComponent = rootView->GetFocusedComponent();
|
|
563
587
|
auto keyboardSource = winrt::make<CompositionKeyboardSource>(this);
|
|
564
588
|
auto args = winrt::make<
|
|
565
589
|
winrt::Microsoft::ReactNative::Composition::Input::implementation::CharacterReceivedRoutedEventArgs>(
|
|
@@ -582,7 +606,10 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
|
|
|
582
606
|
case WM_SYSKEYDOWN:
|
|
583
607
|
case WM_SYSKEYUP: {
|
|
584
608
|
if (auto strongRootView = m_wkRootView.get()) {
|
|
585
|
-
auto
|
|
609
|
+
auto *rootView = RootComponentView();
|
|
610
|
+
if (!rootView)
|
|
611
|
+
break;
|
|
612
|
+
auto focusedComponent = rootView->GetFocusedComponent();
|
|
586
613
|
auto keyboardSource = winrt::make<CompositionKeyboardSource>(this);
|
|
587
614
|
auto args = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::KeyRoutedEventArgs>(
|
|
588
615
|
focusedComponent
|
|
@@ -614,9 +641,12 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
|
|
|
614
641
|
|
|
615
642
|
void CompositionEventHandler::onKeyDown(
|
|
616
643
|
const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
|
|
617
|
-
RootComponentView()
|
|
644
|
+
auto *rootView = RootComponentView();
|
|
645
|
+
if (!rootView)
|
|
646
|
+
return;
|
|
647
|
+
rootView->UseKeyboardForProgrammaticFocus(true);
|
|
618
648
|
|
|
619
|
-
if (auto focusedComponent =
|
|
649
|
+
if (auto focusedComponent = rootView->GetFocusedComponent()) {
|
|
620
650
|
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(focusedComponent)->OnKeyDown(args);
|
|
621
651
|
|
|
622
652
|
if (args.Handled())
|
|
@@ -639,7 +669,7 @@ void CompositionEventHandler::onKeyDown(
|
|
|
639
669
|
}
|
|
640
670
|
|
|
641
671
|
if (!fCtrl && args.Key() == winrt::Windows::System::VirtualKey::Tab) {
|
|
642
|
-
if (
|
|
672
|
+
if (rootView->TryMoveFocus(!fShift, winrt::Microsoft::ReactNative::FocusState::Keyboard)) {
|
|
643
673
|
args.Handled(true);
|
|
644
674
|
}
|
|
645
675
|
|
|
@@ -649,9 +679,12 @@ void CompositionEventHandler::onKeyDown(
|
|
|
649
679
|
|
|
650
680
|
void CompositionEventHandler::onKeyUp(
|
|
651
681
|
const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
|
|
652
|
-
RootComponentView()
|
|
682
|
+
auto *rootView = RootComponentView();
|
|
683
|
+
if (!rootView)
|
|
684
|
+
return;
|
|
685
|
+
rootView->UseKeyboardForProgrammaticFocus(true);
|
|
653
686
|
|
|
654
|
-
if (auto focusedComponent =
|
|
687
|
+
if (auto focusedComponent = rootView->GetFocusedComponent()) {
|
|
655
688
|
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(focusedComponent)->OnKeyUp(args);
|
|
656
689
|
|
|
657
690
|
if (args.Handled())
|
|
@@ -661,7 +694,10 @@ void CompositionEventHandler::onKeyUp(
|
|
|
661
694
|
|
|
662
695
|
void CompositionEventHandler::onCharacterReceived(
|
|
663
696
|
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept {
|
|
664
|
-
|
|
697
|
+
auto *rootView = RootComponentView();
|
|
698
|
+
if (!rootView)
|
|
699
|
+
return;
|
|
700
|
+
if (auto focusedComponent = rootView->GetFocusedComponent()) {
|
|
665
701
|
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(focusedComponent)
|
|
666
702
|
->OnCharacterReceived(args);
|
|
667
703
|
|
|
@@ -670,7 +706,7 @@ void CompositionEventHandler::onCharacterReceived(
|
|
|
670
706
|
}
|
|
671
707
|
}
|
|
672
708
|
|
|
673
|
-
std::vector<winrt::Microsoft::ReactNative::ComponentView> GetTouchableViewsInPathToRoot(
|
|
709
|
+
std::vector<winrt::Microsoft::ReactNative::ComponentView> CompositionEventHandler::GetTouchableViewsInPathToRoot(
|
|
674
710
|
const winrt::Microsoft::ReactNative::ComponentView &componentView) {
|
|
675
711
|
std::vector<winrt::Microsoft::ReactNative::ComponentView> results;
|
|
676
712
|
auto view = componentView;
|
|
@@ -680,6 +716,7 @@ std::vector<winrt::Microsoft::ReactNative::ComponentView> GetTouchableViewsInPat
|
|
|
680
716
|
}
|
|
681
717
|
view = view.Parent();
|
|
682
718
|
}
|
|
719
|
+
|
|
683
720
|
return results;
|
|
684
721
|
}
|
|
685
722
|
|
|
@@ -980,8 +1017,8 @@ void CompositionEventHandler::UpdateActiveTouch(
|
|
|
980
1017
|
// activeTouch.touch.isEraser = false;
|
|
981
1018
|
activeTouch.touch.pagePoint.x = ptScaled.x;
|
|
982
1019
|
activeTouch.touch.pagePoint.y = ptScaled.y;
|
|
983
|
-
activeTouch.touch.screenPoint.x =
|
|
984
|
-
activeTouch.touch.screenPoint.y =
|
|
1020
|
+
activeTouch.touch.screenPoint.x = ptScaled.x;
|
|
1021
|
+
activeTouch.touch.screenPoint.y = ptScaled.y;
|
|
985
1022
|
activeTouch.touch.offsetPoint.x = ptLocal.x;
|
|
986
1023
|
activeTouch.touch.offsetPoint.y = ptLocal.y;
|
|
987
1024
|
activeTouch.touch.timestamp = static_cast<facebook::react::Float>(
|
|
@@ -1034,9 +1071,12 @@ void CompositionEventHandler::getTargetPointerArgs(
|
|
|
1034
1071
|
|
|
1035
1072
|
// In the case of a sub rootview, we may have a non-zero origin. hitTest takes a pt in the parent coords, so we need
|
|
1036
1073
|
// to apply the current origin
|
|
1037
|
-
|
|
1074
|
+
auto *rootView = RootComponentView();
|
|
1075
|
+
if (!rootView)
|
|
1076
|
+
return;
|
|
1077
|
+
ptScaled += rootView->layoutMetrics().frame.origin;
|
|
1038
1078
|
|
|
1039
|
-
if (
|
|
1079
|
+
if (m_capturedPointers.count(pointerId)) {
|
|
1040
1080
|
assert(m_pointerCapturingComponentTag != -1);
|
|
1041
1081
|
tag = m_pointerCapturingComponentTag;
|
|
1042
1082
|
|
|
@@ -1048,7 +1088,7 @@ void CompositionEventHandler::getTargetPointerArgs(
|
|
|
1048
1088
|
ptLocal.y = ptScaled.y - (clientRect.top / strongRootView.ScaleFactor());
|
|
1049
1089
|
}
|
|
1050
1090
|
} else {
|
|
1051
|
-
tag =
|
|
1091
|
+
tag = rootView->hitTest(ptScaled, ptLocal);
|
|
1052
1092
|
}
|
|
1053
1093
|
}
|
|
1054
1094
|
|
|
@@ -1058,12 +1098,26 @@ void CompositionEventHandler::onPointerCaptureLost(
|
|
|
1058
1098
|
if (SurfaceId() == -1)
|
|
1059
1099
|
return;
|
|
1060
1100
|
|
|
1061
|
-
if (m_pointerCapturingComponentTag) {
|
|
1101
|
+
if (m_pointerCapturingComponentTag != -1) {
|
|
1062
1102
|
// copy array to avoid iterator being invalidated during deletion
|
|
1063
|
-
std::
|
|
1103
|
+
std::unordered_set<PointerId> capturedPointers = m_capturedPointers;
|
|
1064
1104
|
|
|
1065
1105
|
for (auto pointerId : capturedPointers) {
|
|
1066
1106
|
releasePointerCapture(pointerId, m_pointerCapturingComponentTag);
|
|
1107
|
+
|
|
1108
|
+
// Cancel any active touch for this pointer so React Native is notified that
|
|
1109
|
+
// the touch ended. Without this, m_activeTouches retains a zombie entry and
|
|
1110
|
+
// RN JS is never told the touch is gone — leaving Pressables stuck in a
|
|
1111
|
+
// pressed state after a system-interrupted gesture (e.g. system back swipe,
|
|
1112
|
+
// Alt+Tab, another window coming foreground).
|
|
1113
|
+
auto activeTouch = m_activeTouches.find(pointerId);
|
|
1114
|
+
if (activeTouch != m_activeTouches.end()) {
|
|
1115
|
+
ActiveTouch cancelledTouchCopy = std::move(activeTouch->second);
|
|
1116
|
+
m_activeTouches.erase(activeTouch);
|
|
1117
|
+
if (cancelledTouchCopy.eventEmitter) {
|
|
1118
|
+
DispatchSynthesizedTouchCancelForActiveTouch(cancelledTouchCopy, pointerPoint, keyModifiers);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1067
1121
|
}
|
|
1068
1122
|
|
|
1069
1123
|
m_pointerCapturingComponentTag = -1;
|
|
@@ -1107,10 +1161,11 @@ void CompositionEventHandler::onPointerMoved(
|
|
|
1107
1161
|
|
|
1108
1162
|
auto handler = [&, targetView, pointerEvent, isActiveTouch](
|
|
1109
1163
|
std::vector<winrt::Microsoft::ReactNative::ComponentView> &eventPathViews) {
|
|
1164
|
+
auto *rootViewForEmitter = RootComponentView();
|
|
1110
1165
|
const auto eventEmitter = targetView
|
|
1111
1166
|
? winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(targetView)
|
|
1112
1167
|
->eventEmitterAtPoint(pointerEvent.offsetPoint)
|
|
1113
|
-
:
|
|
1168
|
+
: (rootViewForEmitter ? rootViewForEmitter->eventEmitterAtPoint(pointerEvent.offsetPoint) : nullptr);
|
|
1114
1169
|
|
|
1115
1170
|
if (eventEmitter != nullptr) {
|
|
1116
1171
|
eventEmitter->onPointerMove(pointerEvent);
|
|
@@ -1136,7 +1191,10 @@ void CompositionEventHandler::ClearAllHoveredForPointer(const facebook::react::P
|
|
|
1136
1191
|
// events. If we get null for the targetView, that means that the mouse is no over any components, so we have no
|
|
1137
1192
|
// element to send the move event to. However we need to send something so that any previously hovered elements
|
|
1138
1193
|
// are no longer hovered.
|
|
1139
|
-
auto
|
|
1194
|
+
auto *rootView = RootComponentView();
|
|
1195
|
+
if (!rootView)
|
|
1196
|
+
return;
|
|
1197
|
+
auto children = rootView->Children();
|
|
1140
1198
|
if (auto size = children.Size()) {
|
|
1141
1199
|
auto firstChild = children.GetAt(0);
|
|
1142
1200
|
if (auto childEventEmitter =
|
|
@@ -1176,28 +1234,67 @@ void CompositionEventHandler::onPointerExited(
|
|
|
1176
1234
|
}
|
|
1177
1235
|
}
|
|
1178
1236
|
|
|
1237
|
+
// Windows touch pointer IDs can be arbitrarily large (e.g. 2233). React Native's JS
|
|
1238
|
+
// touch handler uses identifiers as array indices and warns/misbehaves for values > 20.
|
|
1239
|
+
// This function maps each live Windows pointer to a small identifier in [0, 19] by
|
|
1240
|
+
// scanning m_activeTouches for in-use slots and cycling from the last assigned index.
|
|
1241
|
+
// Identifier MOUSE_POINTER_ID (1) is permanently reserved for mouse and never returned here.
|
|
1242
|
+
int CompositionEventHandler::AllocateTouchIdentifier() noexcept {
|
|
1243
|
+
constexpr int kMaxTouchIdentifier = 20;
|
|
1244
|
+
for (int i = 0; i < kMaxTouchIdentifier; i++) {
|
|
1245
|
+
int candidate = (m_touchId + i) % kMaxTouchIdentifier;
|
|
1246
|
+
if (candidate == static_cast<int>(MOUSE_POINTER_ID)) {
|
|
1247
|
+
continue; // reserved for mouse
|
|
1248
|
+
}
|
|
1249
|
+
bool inUse = std::any_of(m_activeTouches.begin(), m_activeTouches.end(), [candidate](const auto &pair) {
|
|
1250
|
+
return pair.second.touch.identifier == candidate;
|
|
1251
|
+
});
|
|
1252
|
+
if (!inUse) {
|
|
1253
|
+
m_touchId = (candidate + 1) % kMaxTouchIdentifier;
|
|
1254
|
+
return candidate;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
// All non-mouse slots occupied (> 19 simultaneous touch/pen points) — wrap anyway,
|
|
1258
|
+
// skipping the mouse-reserved slot.
|
|
1259
|
+
int fallback = m_touchId;
|
|
1260
|
+
m_touchId = (m_touchId + 1) % kMaxTouchIdentifier;
|
|
1261
|
+
if (fallback == static_cast<int>(MOUSE_POINTER_ID)) {
|
|
1262
|
+
fallback = m_touchId;
|
|
1263
|
+
m_touchId = (m_touchId + 1) % kMaxTouchIdentifier;
|
|
1264
|
+
}
|
|
1265
|
+
return fallback;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1179
1268
|
void CompositionEventHandler::onPointerPressed(
|
|
1180
1269
|
const winrt::Microsoft::ReactNative::Composition::Input::PointerPoint &pointerPoint,
|
|
1181
1270
|
winrt::Windows::System::VirtualKeyModifiers keyModifiers) noexcept {
|
|
1182
1271
|
namespace Composition = winrt::Microsoft::ReactNative::Composition;
|
|
1183
1272
|
|
|
1184
|
-
RootComponentView()
|
|
1273
|
+
auto *rootView = RootComponentView();
|
|
1274
|
+
if (!rootView)
|
|
1275
|
+
return;
|
|
1276
|
+
rootView->UseKeyboardForProgrammaticFocus(false);
|
|
1185
1277
|
|
|
1186
1278
|
// Clears any active text selection when left pointer is pressed
|
|
1187
1279
|
if (pointerPoint.Properties().PointerUpdateKind() != Composition::Input::PointerUpdateKind::RightButtonPressed) {
|
|
1188
|
-
|
|
1280
|
+
rootView->ClearCurrentTextSelection();
|
|
1189
1281
|
}
|
|
1190
1282
|
|
|
1191
1283
|
PointerId pointerId = pointerPoint.PointerId();
|
|
1192
1284
|
|
|
1193
|
-
auto staleTouch =
|
|
1194
|
-
return pair.second.touch.identifier == pointerId;
|
|
1195
|
-
});
|
|
1285
|
+
auto staleTouch = m_activeTouches.find(pointerId);
|
|
1196
1286
|
|
|
1197
1287
|
if (staleTouch != m_activeTouches.end()) {
|
|
1198
|
-
// A pointer with this ID
|
|
1199
|
-
//
|
|
1200
|
-
|
|
1288
|
+
// A previous pointer with this ID was never properly released (e.g., app lost focus,
|
|
1289
|
+
// pointer left window). Cancel the stale touch and clean it up so the new press can proceed.
|
|
1290
|
+
// Copy and erase before dispatching to avoid holding a reference into m_activeTouches
|
|
1291
|
+
// across DispatchSynthesizedTouchCancelForActiveTouch, which calls HandleIncomingPointerEvent
|
|
1292
|
+
// and iterates m_activeTouches internally.
|
|
1293
|
+
ActiveTouch staleTouchCopy = std::move(staleTouch->second);
|
|
1294
|
+
m_activeTouches.erase(staleTouch);
|
|
1295
|
+
if (staleTouchCopy.eventEmitter) {
|
|
1296
|
+
DispatchSynthesizedTouchCancelForActiveTouch(staleTouchCopy, pointerPoint, keyModifiers);
|
|
1297
|
+
}
|
|
1201
1298
|
}
|
|
1202
1299
|
|
|
1203
1300
|
const auto eventType = TouchEventType::Start;
|
|
@@ -1218,7 +1315,18 @@ void CompositionEventHandler::onPointerPressed(
|
|
|
1218
1315
|
->OnPointerPressed(args);
|
|
1219
1316
|
|
|
1220
1317
|
ActiveTouch activeTouch{0};
|
|
1221
|
-
|
|
1318
|
+
switch (pointerPoint.PointerDeviceType()) {
|
|
1319
|
+
case Composition::Input::PointerDeviceType::Touch:
|
|
1320
|
+
activeTouch.touchType = UITouchType::Touch;
|
|
1321
|
+
break;
|
|
1322
|
+
case Composition::Input::PointerDeviceType::Pen:
|
|
1323
|
+
activeTouch.touchType = UITouchType::Pen;
|
|
1324
|
+
break;
|
|
1325
|
+
case Composition::Input::PointerDeviceType::Mouse:
|
|
1326
|
+
default:
|
|
1327
|
+
activeTouch.touchType = UITouchType::Mouse;
|
|
1328
|
+
break;
|
|
1329
|
+
}
|
|
1222
1330
|
|
|
1223
1331
|
// Map PointerUpdateKind to W3C button value
|
|
1224
1332
|
// https://developer.mozilla.org/docs/Web/API/MouseEvent/button
|
|
@@ -1256,14 +1364,27 @@ void CompositionEventHandler::onPointerPressed(
|
|
|
1256
1364
|
targetComponentView = targetComponentView.Parent();
|
|
1257
1365
|
}
|
|
1258
1366
|
|
|
1367
|
+
// Don't register the touch if no eventEmitter was found — inserting a null-emitter entry
|
|
1368
|
+
// into m_activeTouches would block future presses with the same pointer ID.
|
|
1369
|
+
if (!activeTouch.eventEmitter) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1259
1373
|
UpdateActiveTouch(activeTouch, ptScaled, ptLocal);
|
|
1260
1374
|
|
|
1261
1375
|
activeTouch.isPrimary = pointerId == 1;
|
|
1262
|
-
|
|
1376
|
+
// Map the Windows pointer ID to a small identifier (0–19) safe for use as a JS array index.
|
|
1377
|
+
// Windows touch IDs can be arbitrarily large (e.g. 2233), which causes React Native to warn
|
|
1378
|
+
// and corrupts touch state, leaving Pressables stuck after a scroll.
|
|
1379
|
+
// Mouse pointer ID is always 1 (MOUSE_POINTER_ID), which is already within the safe range —
|
|
1380
|
+
// use it directly to preserve stable, predictable identifier assignment for mouse input.
|
|
1381
|
+
activeTouch.touch.identifier = (pointerPoint.PointerDeviceType() == Composition::Input::PointerDeviceType::Mouse)
|
|
1382
|
+
? static_cast<int>(MOUSE_POINTER_ID)
|
|
1383
|
+
: AllocateTouchIdentifier();
|
|
1263
1384
|
|
|
1264
1385
|
// If the pointer has not been marked as hovering over views before the touch started, we register
|
|
1265
1386
|
// that the activeTouch should not maintain its hovered state once the pointer has been lifted.
|
|
1266
|
-
auto currentlyHoveredTags = m_currentlyHoveredViewsPerPointer.find(
|
|
1387
|
+
auto currentlyHoveredTags = m_currentlyHoveredViewsPerPointer.find(pointerId);
|
|
1267
1388
|
if (currentlyHoveredTags == m_currentlyHoveredViewsPerPointer.end() || currentlyHoveredTags->second.empty()) {
|
|
1268
1389
|
activeTouch.shouldLeaveWhenReleased = true;
|
|
1269
1390
|
}
|
|
@@ -1279,11 +1400,12 @@ void CompositionEventHandler::onPointerReleased(
|
|
|
1279
1400
|
winrt::Windows::System::VirtualKeyModifiers keyModifiers) noexcept {
|
|
1280
1401
|
int pointerId = pointerPoint.PointerId();
|
|
1281
1402
|
|
|
1282
|
-
RootComponentView()
|
|
1403
|
+
auto *rootView = RootComponentView();
|
|
1404
|
+
if (!rootView)
|
|
1405
|
+
return;
|
|
1406
|
+
rootView->UseKeyboardForProgrammaticFocus(false);
|
|
1283
1407
|
|
|
1284
|
-
auto activeTouch =
|
|
1285
|
-
return pair.second.touch.identifier == pointerId;
|
|
1286
|
-
});
|
|
1408
|
+
auto activeTouch = m_activeTouches.find(pointerId);
|
|
1287
1409
|
|
|
1288
1410
|
if (activeTouch == m_activeTouches.end()) {
|
|
1289
1411
|
return;
|
|
@@ -1295,8 +1417,13 @@ void CompositionEventHandler::onPointerReleased(
|
|
|
1295
1417
|
facebook::react::Point ptLocal, ptScaled;
|
|
1296
1418
|
getTargetPointerArgs(fabricuiManager, pointerPoint, tag, ptScaled, ptLocal);
|
|
1297
1419
|
|
|
1298
|
-
if (tag == -1)
|
|
1420
|
+
if (tag == -1) {
|
|
1421
|
+
if (activeTouch->second.eventEmitter) {
|
|
1422
|
+
DispatchSynthesizedTouchCancelForActiveTouch(activeTouch->second, pointerPoint, keyModifiers);
|
|
1423
|
+
}
|
|
1424
|
+
m_activeTouches.erase(pointerId);
|
|
1299
1425
|
return;
|
|
1426
|
+
}
|
|
1300
1427
|
|
|
1301
1428
|
auto targetComponentView = fabricuiManager->GetViewRegistry().componentViewDescriptorWithTag(tag).view;
|
|
1302
1429
|
auto args = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerRoutedEventArgs>(
|
|
@@ -1328,7 +1455,7 @@ bool CompositionEventHandler::CapturePointer(
|
|
|
1328
1455
|
}
|
|
1329
1456
|
|
|
1330
1457
|
m_pointerCapturingComponentTag = tag;
|
|
1331
|
-
m_capturedPointers.
|
|
1458
|
+
m_capturedPointers.insert(pointer.PointerId());
|
|
1332
1459
|
return true;
|
|
1333
1460
|
}
|
|
1334
1461
|
|
|
@@ -1343,11 +1470,9 @@ bool CompositionEventHandler::releasePointerCapture(PointerId pointerId, faceboo
|
|
|
1343
1470
|
bool result = false;
|
|
1344
1471
|
|
|
1345
1472
|
if (m_pointerCapturingComponentTag == tag) {
|
|
1346
|
-
|
|
1347
|
-
if (it == m_capturedPointers.end()) {
|
|
1473
|
+
if (m_capturedPointers.erase(pointerId) == 0) {
|
|
1348
1474
|
return false;
|
|
1349
1475
|
}
|
|
1350
|
-
m_capturedPointers.erase(it);
|
|
1351
1476
|
|
|
1352
1477
|
if (std::shared_ptr<FabricUIManager> fabricuiManager =
|
|
1353
1478
|
::Microsoft::ReactNative::FabricUIManager::FromProperties(m_context.Properties())) {
|
|
@@ -1358,7 +1483,7 @@ bool CompositionEventHandler::releasePointerCapture(PointerId pointerId, faceboo
|
|
|
1358
1483
|
->OnPointerCaptureLost();
|
|
1359
1484
|
}
|
|
1360
1485
|
|
|
1361
|
-
if (m_capturedPointers.
|
|
1486
|
+
if (m_capturedPointers.empty()) {
|
|
1362
1487
|
m_pointerCapturingComponentTag = -1;
|
|
1363
1488
|
return true;
|
|
1364
1489
|
}
|
|
@@ -1473,16 +1598,83 @@ bool CompositionEventHandler::IsPointerWithinInitialTree(const ActiveTouch &acti
|
|
|
1473
1598
|
if (!initialComponentView)
|
|
1474
1599
|
return false;
|
|
1475
1600
|
|
|
1476
|
-
auto
|
|
1601
|
+
auto *rootView = RootComponentView();
|
|
1602
|
+
if (!rootView)
|
|
1603
|
+
return false;
|
|
1604
|
+
|
|
1605
|
+
facebook::react::Point ptLocal;
|
|
1606
|
+
auto currentTag = rootView->hitTest(activeTouch.touch.pagePoint, ptLocal);
|
|
1607
|
+
if (currentTag == -1)
|
|
1608
|
+
return false;
|
|
1609
|
+
|
|
1610
|
+
auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(m_context.Properties());
|
|
1611
|
+
if (!fabricuiManager)
|
|
1612
|
+
return false;
|
|
1477
1613
|
|
|
1478
|
-
|
|
1479
|
-
|
|
1614
|
+
auto initialTag = initialComponentView.Tag();
|
|
1615
|
+
auto &viewRegistry = fabricuiManager->GetViewRegistry();
|
|
1616
|
+
auto currentView = viewRegistry.componentViewDescriptorWithTag(currentTag).view;
|
|
1617
|
+
while (currentView) {
|
|
1618
|
+
if (currentView.Tag() == initialTag)
|
|
1480
1619
|
return true;
|
|
1620
|
+
currentView = currentView.Parent();
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// Fallback: if the pointer drifted spatially but the original target
|
|
1624
|
+
// is still structurally within the initial tree, honor the tap.
|
|
1625
|
+
// This provides touch-device tolerance for finger drift.
|
|
1626
|
+
auto targetView = viewRegistry.componentViewDescriptorWithTag(activeTouch.touch.target).view;
|
|
1627
|
+
while (targetView) {
|
|
1628
|
+
if (targetView.Tag() == initialTag)
|
|
1629
|
+
return true;
|
|
1630
|
+
targetView = targetView.Parent();
|
|
1481
1631
|
}
|
|
1482
1632
|
|
|
1483
1633
|
return false;
|
|
1484
1634
|
}
|
|
1485
1635
|
|
|
1636
|
+
void CompositionEventHandler::DispatchSynthesizedTouchCancelForActiveTouch(
|
|
1637
|
+
const ActiveTouch &cancelledTouch,
|
|
1638
|
+
const winrt::Microsoft::ReactNative::Composition::Input::PointerPoint &pointerPoint,
|
|
1639
|
+
winrt::Windows::System::VirtualKeyModifiers keyModifiers) {
|
|
1640
|
+
if (!cancelledTouch.eventEmitter) {
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
facebook::react::PointerEvent pointerEvent =
|
|
1645
|
+
CreatePointerEventFromActiveTouch(cancelledTouch, TouchEventType::Cancel);
|
|
1646
|
+
winrt::Microsoft::ReactNative::ComponentView targetView{nullptr};
|
|
1647
|
+
facebook::react::SharedTouchEventEmitter emitter = cancelledTouch.eventEmitter;
|
|
1648
|
+
auto pointerHandler = [emitter, pointerEvent](std::vector<winrt::Microsoft::ReactNative::ComponentView> &) {
|
|
1649
|
+
emitter->onPointerCancel(pointerEvent);
|
|
1650
|
+
};
|
|
1651
|
+
HandleIncomingPointerEvent(pointerEvent, targetView, pointerPoint, keyModifiers, pointerHandler);
|
|
1652
|
+
|
|
1653
|
+
facebook::react::TouchEvent touchEvent;
|
|
1654
|
+
touchEvent.changedTouches.insert(cancelledTouch.touch);
|
|
1655
|
+
|
|
1656
|
+
for (const auto &pair : m_activeTouches) {
|
|
1657
|
+
if (!pair.second.eventEmitter) {
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
if (touchEvent.changedTouches.find(pair.second.touch) != touchEvent.changedTouches.end()) {
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
touchEvent.touches.insert(pair.second.touch);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
for (const auto &pair : m_activeTouches) {
|
|
1669
|
+
if (pair.second.eventEmitter == cancelledTouch.eventEmitter &&
|
|
1670
|
+
touchEvent.changedTouches.find(pair.second.touch) == touchEvent.changedTouches.end()) {
|
|
1671
|
+
touchEvent.targetTouches.insert(pair.second.touch);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
cancelledTouch.eventEmitter->onTouchCancel(touchEvent);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1486
1678
|
// If we have events that include multiple pointer updates, we should change arg from pointerId to vector<pointerId>
|
|
1487
1679
|
void CompositionEventHandler::DispatchTouchEvent(
|
|
1488
1680
|
TouchEventType eventType,
|
|
@@ -1507,7 +1699,7 @@ void CompositionEventHandler::DispatchTouchEvent(
|
|
|
1507
1699
|
continue;
|
|
1508
1700
|
}
|
|
1509
1701
|
|
|
1510
|
-
if (
|
|
1702
|
+
if (pair.first == pointerId) {
|
|
1511
1703
|
event.changedTouches.insert(activeTouch.touch);
|
|
1512
1704
|
}
|
|
1513
1705
|
uniqueEventEmitters.insert(activeTouch.eventEmitter);
|
|
@@ -1518,16 +1710,19 @@ void CompositionEventHandler::DispatchTouchEvent(
|
|
|
1518
1710
|
bool shouldLeave = (eventType == TouchEventType::End && activeTouch.shouldLeaveWhenReleased) ||
|
|
1519
1711
|
eventType == TouchEventType::Cancel;
|
|
1520
1712
|
if (!shouldLeave) {
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
auto
|
|
1526
|
-
|
|
1713
|
+
auto *rootViewForHit = RootComponentView();
|
|
1714
|
+
if (rootViewForHit) {
|
|
1715
|
+
const auto &viewRegistry = fabricuiManager->GetViewRegistry();
|
|
1716
|
+
facebook::react::Point ptLocal;
|
|
1717
|
+
auto targetTag = rootViewForHit->hitTest(pointerEvent.clientPoint, ptLocal);
|
|
1718
|
+
if (targetTag != -1) {
|
|
1719
|
+
auto targetComponentViewDescriptor = viewRegistry.componentViewDescriptorWithTag(targetTag);
|
|
1720
|
+
targetView = FindClosestFabricManagedTouchableView(targetComponentViewDescriptor.view);
|
|
1721
|
+
}
|
|
1527
1722
|
}
|
|
1528
1723
|
}
|
|
1529
1724
|
|
|
1530
|
-
auto handler = [&activeTouch, eventType, &pointerEvent](
|
|
1725
|
+
auto handler = [this, &activeTouch, eventType, &pointerEvent](
|
|
1531
1726
|
std::vector<winrt::Microsoft::ReactNative::ComponentView> &eventPathViews) {
|
|
1532
1727
|
switch (eventType) {
|
|
1533
1728
|
case TouchEventType::Start:
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#include <winrt/Windows.Devices.Input.h>
|
|
15
15
|
#include <optional>
|
|
16
16
|
#include <set>
|
|
17
|
+
#include <unordered_set>
|
|
17
18
|
|
|
18
19
|
namespace winrt {
|
|
19
20
|
using namespace Windows::UI;
|
|
@@ -79,7 +80,7 @@ class CompositionEventHandler : public std::enable_shared_from_this<CompositionE
|
|
|
79
80
|
bool releasePointerCapture(PointerId pointerId, facebook::react::Tag tag) noexcept;
|
|
80
81
|
|
|
81
82
|
facebook::react::SurfaceId SurfaceId() const noexcept;
|
|
82
|
-
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView
|
|
83
|
+
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *RootComponentView() const noexcept;
|
|
83
84
|
|
|
84
85
|
enum class UITouchType {
|
|
85
86
|
Mouse,
|
|
@@ -141,7 +142,7 @@ class CompositionEventHandler : public std::enable_shared_from_this<CompositionE
|
|
|
141
142
|
ReactTaggedView initialComponentView{nullptr};
|
|
142
143
|
};
|
|
143
144
|
|
|
144
|
-
|
|
145
|
+
bool IsPointerWithinInitialTree(const ActiveTouch &activeTouch) noexcept;
|
|
145
146
|
static bool IsEndishEventType(TouchEventType eventType) noexcept;
|
|
146
147
|
static const char *PointerTypeCStringFromUITouchType(UITouchType type) noexcept;
|
|
147
148
|
static facebook::react::PointerEvent CreatePointerEventFromActiveTouch(
|
|
@@ -150,18 +151,31 @@ class CompositionEventHandler : public std::enable_shared_from_this<CompositionE
|
|
|
150
151
|
static void
|
|
151
152
|
UpdateActiveTouch(ActiveTouch &activeTouch, facebook::react::Point ptScaled, facebook::react::Point ptLocal) noexcept;
|
|
152
153
|
|
|
154
|
+
void DispatchSynthesizedTouchCancelForActiveTouch(
|
|
155
|
+
const ActiveTouch &cancelledTouch,
|
|
156
|
+
const winrt::Microsoft::ReactNative::Composition::Input::PointerPoint &pointerPoint,
|
|
157
|
+
winrt::Windows::System::VirtualKeyModifiers keyModifiers);
|
|
158
|
+
|
|
159
|
+
std::vector<winrt::Microsoft::ReactNative::ComponentView> GetTouchableViewsInPathToRoot(
|
|
160
|
+
const winrt::Microsoft::ReactNative::ComponentView &componentView);
|
|
161
|
+
|
|
153
162
|
void UpdateCursor() noexcept;
|
|
154
163
|
void SetCursor(facebook::react::Cursor cursor, HCURSOR hcur) noexcept;
|
|
155
164
|
|
|
165
|
+
// Allocates a small touch identifier (0–19) that is safe to use as a JS array index.
|
|
166
|
+
// Windows pointer IDs can be arbitrarily large, which causes React Native to warn and
|
|
167
|
+
// back-fill huge arrays, corrupting touch state after scrolling.
|
|
168
|
+
int AllocateTouchIdentifier() noexcept;
|
|
169
|
+
|
|
156
170
|
std::map<PointerId, ActiveTouch> m_activeTouches; // iOS is map of touch event args to ActiveTouch..?
|
|
157
|
-
|
|
171
|
+
int m_touchId = 0; // cycling base used by AllocateTouchIdentifier
|
|
158
172
|
|
|
159
173
|
std::map<PointerId, std::vector<ReactTaggedView>> m_currentlyHoveredViewsPerPointer;
|
|
160
174
|
winrt::weak_ref<winrt::Microsoft::ReactNative::ReactNativeIsland> m_wkRootView;
|
|
161
175
|
winrt::Microsoft::ReactNative::ReactContext m_context;
|
|
162
176
|
|
|
163
177
|
facebook::react::Tag m_pointerCapturingComponentTag{-1}; // Component that has captured input
|
|
164
|
-
std::
|
|
178
|
+
std::unordered_set<PointerId> m_capturedPointers;
|
|
165
179
|
HCURSOR m_hcursor{nullptr};
|
|
166
180
|
bool m_hcursorOwned{false}; // If we create the cursor, so we need to destroy it
|
|
167
181
|
facebook::react::Cursor m_currentCursor{facebook::react::Cursor::Auto};
|