diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerPointerTracker.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerPointerTracker.mm index 2f06e15dbc..cd0d70155a 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerPointerTracker.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerPointerTracker.mm @@ -39,7 +39,14 @@ - (int)registerTouch:(RNGHUITouch *)touch - (int)unregisterTouch:(RNGHUITouch *)touch { for (int index = 0; index < MAX_POINTERS_COUNT; index++) { +#if TARGET_OS_OSX + // A macOS mouse sequence delivers a fresh NSEvent per event, so identity matching + // (valid on iOS, where a UITouch is one stable object for the whole touch) never + // matches. There is only one mouse pointer — match the tracked slot instead. + if (_trackedPointers[index] != nil) { +#else if (_trackedPointers[index] == touch) { +#endif _trackedPointers[index] = nil; return index; } @@ -51,7 +58,12 @@ - (int)unregisterTouch:(RNGHUITouch *)touch - (int)findTouchIndex:(RNGHUITouch *)touch { for (int index = 0; index < MAX_POINTERS_COUNT; index++) { +#if TARGET_OS_OSX + // See unregisterTouch: — identity matching cannot work for NSEvents. + if (_trackedPointers[index] != nil) { +#else if (_trackedPointers[index] == touch) { +#endif return index; } } @@ -159,6 +171,12 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event continue; } +#if TARGET_OS_OSX + // Replace the stored mouse-down event with the latest one so extractAllTouches + // reads the pointer's current position, not where the sequence started. + _trackedPointers[index] = touch; +#endif + data[changedCount++] = [self extractPointerData:index forTouch:touch]; } @@ -177,6 +195,18 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event return; } +#if TARGET_OS_OSX + // Refresh the tracked slot with the ending event so extractAllTouches below reports + // the pointer's final position. On iOS the stored UITouch is a live object that + // always reads its current location; a stored NSEvent is a stale snapshot. + for (RNGHUITouch *touch in touches) { + int index = [self findTouchIndex:touch]; + if (index >= 0) { + _trackedPointers[index] = touch; + } + } +#endif + // extract all touches first to include the ones that were just lifted [self extractAllTouches];