You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
6.1 KiB
244 lines
6.1 KiB
#import "RNGestureHandlerPointerTracker.h"
|
|
#import "RNGestureHandler.h"
|
|
|
|
#import <React/UIView+React.h>
|
|
|
|
@implementation RNGestureHandlerPointerTracker {
|
|
__weak RNGestureHandler *_gestureHandler;
|
|
UITouch *_trackedPointers[MAX_POINTERS_COUNT];
|
|
int _trackedPointersCount;
|
|
}
|
|
|
|
- (id)initWithGestureHandler:(id)gestureHandler
|
|
{
|
|
_gestureHandler = gestureHandler;
|
|
_trackedPointersCount = 0;
|
|
_changedPointersData = nil;
|
|
_allPointersData = nil;
|
|
|
|
for (int i = 0; i < MAX_POINTERS_COUNT; i++) {
|
|
_trackedPointers[i] = nil;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (int)registerTouch:(UITouch *)touch
|
|
{
|
|
for (int index = 0; index < MAX_POINTERS_COUNT; index++) {
|
|
if (_trackedPointers[index] == nil) {
|
|
_trackedPointers[index] = touch;
|
|
return index;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
- (int)unregisterTouch:(UITouch *)touch
|
|
{
|
|
for (int index = 0; index < MAX_POINTERS_COUNT; index++) {
|
|
if (_trackedPointers[index] == touch) {
|
|
_trackedPointers[index] = nil;
|
|
return index;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
- (int)findTouchIndex:(UITouch *)touch
|
|
{
|
|
for (int index = 0; index < MAX_POINTERS_COUNT; index++) {
|
|
if (_trackedPointers[index] == touch) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
- (int)registeredTouchesCount
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < MAX_POINTERS_COUNT; i++) {
|
|
if (_trackedPointers[i] != nil) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
- (NSDictionary *)extractPointerData:(int)index forTouch:(UITouch *)touch
|
|
{
|
|
CGPoint relativePos = [touch locationInView:_gestureHandler.recognizer.view];
|
|
CGPoint absolutePos = [touch locationInView:_gestureHandler.recognizer.view.window];
|
|
|
|
return @{
|
|
@"id" : @(index),
|
|
@"x" : @(relativePos.x),
|
|
@"y" : @(relativePos.y),
|
|
@"absoluteX" : @(absolutePos.x),
|
|
@"absoluteY" : @(absolutePos.y)
|
|
};
|
|
}
|
|
|
|
- (void)extractAllTouches
|
|
{
|
|
int registeredTouches = [self registeredTouchesCount];
|
|
|
|
NSDictionary *data[registeredTouches];
|
|
int nextIndex = 0;
|
|
|
|
for (int i = 0; i < MAX_POINTERS_COUNT; i++) {
|
|
UITouch *touch = _trackedPointers[i];
|
|
if (touch != nil) {
|
|
data[nextIndex++] = [self extractPointerData:i forTouch:touch];
|
|
}
|
|
}
|
|
|
|
_allPointersData = [[NSArray alloc] initWithObjects:data count:registeredTouches];
|
|
}
|
|
|
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
if (!_gestureHandler.needsPointerData) {
|
|
return;
|
|
}
|
|
|
|
_eventType = RNGHTouchEventTypePointerDown;
|
|
|
|
NSDictionary *data[touches.count];
|
|
|
|
for (int i = 0; i < [touches count]; i++) {
|
|
UITouch *touch = [[touches allObjects] objectAtIndex:i];
|
|
int index = [self registerTouch:touch];
|
|
if (index >= 0) {
|
|
_trackedPointersCount++;
|
|
}
|
|
|
|
data[i] = [self extractPointerData:index forTouch:touch];
|
|
}
|
|
|
|
_changedPointersData = [[NSArray alloc] initWithObjects:data count:[touches count]];
|
|
// extract all touches last to include the ones that were just added
|
|
[self extractAllTouches];
|
|
[self sendEvent];
|
|
}
|
|
|
|
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
if (!_gestureHandler.needsPointerData) {
|
|
return;
|
|
}
|
|
|
|
_eventType = RNGHTouchEventTypePointerMove;
|
|
|
|
NSDictionary *data[touches.count];
|
|
|
|
for (int i = 0; i < [touches count]; i++) {
|
|
UITouch *touch = [[touches allObjects] objectAtIndex:i];
|
|
int index = [self findTouchIndex:touch];
|
|
data[i] = [self extractPointerData:index forTouch:touch];
|
|
}
|
|
|
|
_changedPointersData = [[NSArray alloc] initWithObjects:data count:[touches count]];
|
|
[self extractAllTouches];
|
|
[self sendEvent];
|
|
}
|
|
|
|
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
if (!_gestureHandler.needsPointerData) {
|
|
return;
|
|
}
|
|
|
|
// extract all touches first to include the ones that were just lifted
|
|
[self extractAllTouches];
|
|
|
|
_eventType = RNGHTouchEventTypePointerUp;
|
|
|
|
NSDictionary *data[touches.count];
|
|
|
|
for (int i = 0; i < [touches count]; i++) {
|
|
UITouch *touch = [[touches allObjects] objectAtIndex:i];
|
|
int index = [self unregisterTouch:touch];
|
|
if (index >= 0) {
|
|
_trackedPointersCount--;
|
|
}
|
|
|
|
data[i] = [self extractPointerData:index forTouch:touch];
|
|
}
|
|
|
|
_changedPointersData = [[NSArray alloc] initWithObjects:data count:[touches count]];
|
|
[self sendEvent];
|
|
}
|
|
|
|
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
if (!_gestureHandler.needsPointerData) {
|
|
return;
|
|
}
|
|
|
|
[self reset];
|
|
}
|
|
|
|
- (void)reset
|
|
{
|
|
if (!_gestureHandler.needsPointerData) {
|
|
return;
|
|
}
|
|
|
|
if (_trackedPointersCount == 0) {
|
|
// gesture has finished because all pointers were lifted, reset event type to send state change event
|
|
_eventType = RNGHTouchEventTypeUndetermined;
|
|
} else {
|
|
// turns out that the gesture may be made to fail without calling touchesCancelled in that case there
|
|
// are still tracked pointers but the recognizer state is already set to UIGestureRecognizerStateFailed
|
|
// we need to clear the pointers and send info about their cancellation
|
|
[self cancelPointers];
|
|
}
|
|
|
|
[_gestureHandler reset];
|
|
}
|
|
|
|
- (void)cancelPointers
|
|
{
|
|
// extract all touches first to include the ones that were just cancelled
|
|
[self extractAllTouches];
|
|
|
|
int registeredTouches = [self registeredTouchesCount];
|
|
|
|
if (registeredTouches > 0) {
|
|
int nextIndex = 0;
|
|
NSDictionary *data[registeredTouches];
|
|
|
|
for (int i = 0; i < MAX_POINTERS_COUNT; i++) {
|
|
UITouch *touch = _trackedPointers[i];
|
|
if (touch != nil) {
|
|
data[nextIndex++] = [self extractPointerData:i forTouch:touch];
|
|
[self unregisterTouch:touch];
|
|
}
|
|
}
|
|
|
|
_eventType = RNGHTouchEventTypeCancelled;
|
|
_changedPointersData = [[NSArray alloc] initWithObjects:data count:registeredTouches];
|
|
[self sendEvent];
|
|
_trackedPointersCount = 0;
|
|
}
|
|
}
|
|
|
|
- (void)sendEvent
|
|
{
|
|
// it may happen that the gesture recognizer is reset after it's been unbound from the view,
|
|
// it that recognizer tried to send event, the app would crash because the target of the event
|
|
// would be nil.
|
|
if (!_gestureHandler.needsPointerData || _gestureHandler.recognizer.view.reactTag == nil) {
|
|
return;
|
|
}
|
|
|
|
[_gestureHandler sendTouchEventInState:[_gestureHandler state]
|
|
forViewWithTag:_gestureHandler.recognizer.view.reactTag];
|
|
}
|
|
|
|
@end
|