Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions React/Base/RCTUIKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ UIKIT_STATIC_INLINE CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *path)
//

// UIView
#define RCTPlatformView UIView
#define RCTPlatformView UIView
#define RCTUIView UIView
#define RCTUIScrollView UIScrollView

#define RCTPlatformWindow UIWindow

UIKIT_STATIC_INLINE RCTPlatformView *RCTUIViewHitTestWithEvent(RCTPlatformView *view, CGPoint point, __unused UIEvent *__nullable event)
Expand Down Expand Up @@ -545,3 +544,12 @@ NS_ASSUME_NONNULL_END
@end

#endif

// RCTUITouch

#if !TARGET_OS_OSX
typedef UITouch RCTUITouch;
#else
@interface RCTUITouch : NSEvent
@end
#endif
63 changes: 43 additions & 20 deletions React/Fabric/RCTSurfaceTouchHandler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import "RCTSurfaceTouchHandler.h"

#import <React/RCTUIKit.h> // [macOS]
#import <React/RCTUtils.h>
#import <React/RCTViewComponentView.h>

Expand Down Expand Up @@ -79,10 +80,11 @@ bool operator()(const ActiveTouch &lhs, const ActiveTouch &rhs) const

static void UpdateActiveTouchWithUITouch(
ActiveTouch &activeTouch,
UITouch *uiTouch,
RCTUITouch *uiTouch, // [macOS]
RCTUIView *rootComponentView,
CGPoint rootViewOriginOffset) // [macOS]
{
#if !TARGET_OS_OSX // [macOS]
CGPoint offsetPoint = [uiTouch locationInView:activeTouch.componentView];
CGPoint screenPoint = [uiTouch locationInView:uiTouch.window];
CGPoint pagePoint = [uiTouch locationInView:rootComponentView];
Expand All @@ -97,12 +99,14 @@ static void UpdateActiveTouchWithUITouch(
if (RCTForceTouchAvailable()) {
activeTouch.touch.force = RCTZeroIfNaN(uiTouch.force / uiTouch.maximumPossibleForce);
}
#endif // [macOS]
}

static ActiveTouch CreateTouchWithUITouch(UITouch *uiTouch, RCTUIView *rootComponentView, CGPoint rootViewOriginOffset) // [macOS]
static ActiveTouch CreateTouchWithUITouch(RCTUITouch *uiTouch, RCTUIView *rootComponentView, CGPoint rootViewOriginOffset) // [macOS]
{
ActiveTouch activeTouch = {};

#if !TARGET_OS_OSX // [macOS]
// Find closest Fabric-managed touchable view
RCTUIView *componentView = uiTouch.view; // [macOS]
while (componentView) {
Expand All @@ -117,25 +121,30 @@ static ActiveTouch CreateTouchWithUITouch(UITouch *uiTouch, RCTUIView *rootCompo
}

UpdateActiveTouchWithUITouch(activeTouch, uiTouch, rootComponentView, rootViewOriginOffset);
#endif // [macOS]
return activeTouch;
}

static BOOL AllTouchesAreCancelledOrEnded(NSSet<UITouch *> *touches)
static BOOL AllTouchesAreCancelledOrEnded(NSSet<RCTUITouch *> *touches) // [macOS]
{
for (UITouch *touch in touches) {
for (RCTUITouch *touch in touches) { // [macOS]
#if !TARGET_OS_OSX // [macOS]
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved || touch.phase == UITouchPhaseStationary) {
return NO;
}
#endif // [macOS]
}
return YES;
}

static BOOL AnyTouchesChanged(NSSet<UITouch *> *touches)
static BOOL AnyTouchesChanged(NSSet<RCTUITouch *> *touches) // [macOS]
{
for (UITouch *touch in touches) {
for (RCTUITouch *touch in touches) { // [macOS]
#if !TARGET_OS_OSX // [macOS]
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) {
return YES;
}
#endif // [macOS]
}
return NO;
}
Expand All @@ -158,8 +167,8 @@ @interface RCTSurfaceTouchHandler () <UIGestureRecognizerDelegate>
@end

@implementation RCTSurfaceTouchHandler {
std::unordered_map<__unsafe_unretained UITouch *, ActiveTouch, PointerHasher<__unsafe_unretained UITouch *>>
_activeTouches;
std::unordered_map<__unsafe_unretained RCTUITouch *, ActiveTouch, PointerHasher<__unsafe_unretained RCTUITouch *>>
_activeTouches; // [macOS]

/*
* We hold the view weakly to prevent a retain cycle.
Expand All @@ -175,9 +184,11 @@ - (instancetype)init
// to be used as a top level event delegated recognizer.
// Otherwise, lower-level components not built using React Native,
// will fail to recognize gestures.
#if !TARGET_OS_OSX // [macOS]
self.cancelsTouchesInView = NO;
self.delaysTouchesBegan = NO; // This is default value.
self.delaysTouchesEnded = NO;
#endif // [macOS]

self.delegate = self;
}
Expand All @@ -204,18 +215,18 @@ - (void)detachFromView:(RCTUIView *)view // [macOS]
_rootComponentView = nil;
}

- (void)_registerTouches:(NSSet<UITouch *> *)touches
- (void)_registerTouches:(NSSet<RCTUITouch *> *)touches // [macOS]
{
for (UITouch *touch in touches) {
for (RCTUITouch *touch in touches) { // [macOS]
auto activeTouch = CreateTouchWithUITouch(touch, _rootComponentView, _viewOriginOffset);
activeTouch.touch.identifier = _identifierPool.dequeue();
_activeTouches.emplace(touch, activeTouch);
}
}

- (void)_updateTouches:(NSSet<UITouch *> *)touches
- (void)_updateTouches:(NSSet<RCTUITouch *> *)touches // [macOS]
{
for (UITouch *touch in touches) {
for (RCTUITouch *touch in touches) { // [macOS]
auto iterator = _activeTouches.find(touch);
assert(iterator != _activeTouches.end() && "Inconsistency between local and UIKit touch registries");
if (iterator == _activeTouches.end()) {
Expand All @@ -226,9 +237,9 @@ - (void)_updateTouches:(NSSet<UITouch *> *)touches
}
}

- (void)_unregisterTouches:(NSSet<UITouch *> *)touches
- (void)_unregisterTouches:(NSSet<RCTUITouch *> *)touches // [macOS]
{
for (UITouch *touch in touches) {
for (RCTUITouch *touch in touches) { // [macOS]
auto iterator = _activeTouches.find(touch);
assert(iterator != _activeTouches.end() && "Inconsistency between local and UIKit touch registries");
if (iterator == _activeTouches.end()) {
Expand All @@ -240,12 +251,12 @@ - (void)_unregisterTouches:(NSSet<UITouch *> *)touches
}
}

- (std::vector<ActiveTouch>)_activeTouchesFromTouches:(NSSet<UITouch *> *)touches
- (std::vector<ActiveTouch>)_activeTouchesFromTouches:(NSSet<RCTUITouch *> *)touches // [macOS]
{
std::vector<ActiveTouch> activeTouches;
activeTouches.reserve(touches.count);

for (UITouch *touch in touches) {
for (RCTUITouch *touch in touches) { // [macOS]
auto iterator = _activeTouches.find(touch);
assert(iterator != _activeTouches.end() && "Inconsistency between local and UIKit touch registries");
if (iterator == _activeTouches.end()) {
Expand Down Expand Up @@ -314,8 +325,9 @@ - (void)_dispatchActiveTouches:(std::vector<ActiveTouch>)activeTouches eventType

#pragma mark - `UIResponder`-ish touch-delivery methods

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesBegan:(NSSet<RCTUITouch *> *)touches withEvent:(UIEvent *)event // [macOS]
{
#if !TARGET_OS_OSX // [macOS]
[super touchesBegan:touches withEvent:event];

[self _registerTouches:touches];
Expand All @@ -326,20 +338,24 @@ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
} else if (self.state == UIGestureRecognizerStateBegan) {
self.state = UIGestureRecognizerStateChanged;
}
#endif // [macOS]
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet<RCTUITouch *> *)touches withEvent:(UIEvent *)event // [macOS]
{
#if !TARGET_OS_OSX // [macOS]
[super touchesMoved:touches withEvent:event];

[self _updateTouches:touches];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches] eventType:RCTTouchEventTypeTouchMove];

self.state = UIGestureRecognizerStateChanged;
#endif // [macOS]
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet<RCTUITouch *> *)touches withEvent:(UIEvent *)event // [macOS]
{
#if !TARGET_OS_OSX // [macOS]
[super touchesEnded:touches withEvent:event];

[self _updateTouches:touches];
Expand All @@ -351,10 +367,12 @@ - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
} else if (AnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
#endif // [macOS]
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesCancelled:(NSSet<RCTUITouch *> *)touches withEvent:(UIEvent *)event // [macOS]
{
#if !TARGET_OS_OSX // [macOS]
[super touchesCancelled:touches withEvent:event];

[self _updateTouches:touches];
Expand All @@ -366,6 +384,7 @@ - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
} else if (AnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
#endif // [macOS]
}

- (void)reset
Expand Down Expand Up @@ -395,9 +414,13 @@ - (BOOL)canPreventGestureRecognizer:(__unused UIGestureRecognizer *)preventedGes

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
#if !TARGET_OS_OSX // [macOS]
// We fail in favour of other external gesture recognizers.
// iOS will ask `delegate`'s opinion about this gesture recognizer little bit later.
return ![preventingGestureRecognizer.view isDescendantOfView:self.view];
#else // [macOS
return NO;
#endif // macOS]
}

#pragma mark - UIGestureRecognizerDelegate
Expand Down