From f09c7be18db8ad072d3b0238e3679fa700f43b18 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Thu, 20 Jun 2024 22:52:38 +0800 Subject: [PATCH] NativeTouchHandler improvement, general coding improvements. --- Limelight/Input/NativeTouchHandler.h | 3 +- Limelight/Input/NativeTouchHandler.m | 61 +++++++++++++++++----- Limelight/Input/NativeTouchPointer.h | 8 ++- Limelight/Input/NativeTouchPointer.m | 77 ++++++---------------------- Limelight/Input/StreamView.m | 2 +- 5 files changed, 70 insertions(+), 81 deletions(-) diff --git a/Limelight/Input/NativeTouchHandler.h b/Limelight/Input/NativeTouchHandler.h index dea03c26..b2147d28 100644 --- a/Limelight/Input/NativeTouchHandler.h +++ b/Limelight/Input/NativeTouchHandler.h @@ -15,8 +15,7 @@ NS_ASSUME_NONNULL_BEGIN @interface NativeTouchHandler : UIResponder -- (id)initWith:(StreamView*)view and:(TemporarySettings*)settings; - +- (id)initWithView:(StreamView*)view andSettings:(TemporarySettings*)settings; @end diff --git a/Limelight/Input/NativeTouchHandler.m b/Limelight/Input/NativeTouchHandler.m index 29e11f5d..6c31b67b 100644 --- a/Limelight/Input/NativeTouchHandler.m +++ b/Limelight/Input/NativeTouchHandler.m @@ -15,39 +15,80 @@ #include - @implementation NativeTouchHandler { StreamView* streamView; TemporarySettings* currentSettings; bool activateCoordSelector; + // Use a Dictionary to store UITouch object's memory address as key, and pointerId as value,字典存放UITouch对象地址和pointerId映射关系 + // pointerId will be generated from a pre-defined pool + // Use a NSSet store active pointerId, + NSMutableDictionary *pointerIdDict; //pointerId Dict for active touches. + NSMutableSet *activePointerIds; //pointerId Set for active touches. + NSMutableSet *pointerIdPool; //pre-defined pool of pointerIds. + NSMutableSet *unassignedPointerIds; } -- (id)initWith:(StreamView*)view and:(TemporarySettings*)settings{ - self = [self init]; +- (id)initWithView:(StreamView*)view andSettings:(TemporarySettings*)settings{ + self = [super init]; self->streamView = view; self->currentSettings = settings; self->activateCoordSelector = currentSettings.pointerVelocityModeDivider.floatValue != 1.0; + + pointerIdDict = [NSMutableDictionary dictionary]; + pointerIdPool = [NSMutableSet set]; + for (uint8_t i = 0; i < 10; i++) { //ipadOS supports upto 11 finger touches + [pointerIdPool addObject:@(i)]; + } + activePointerIds = [NSMutableSet set]; + [NativeTouchPointer setPointerVelocityDivider:settings.pointerVelocityModeDivider.floatValue]; [NativeTouchPointer setPointerVelocityFactor:settings.touchPointerVelocityFactor.floatValue]; - [NativeTouchPointer initContextWith:streamView]; + [NativeTouchPointer initContextWithView:streamView]; return self; } +// generate & populate pointerId into NSDict & NSSet, called in touchesBegan +- (void)populatePointerId:(UITouch*)touch{ + uintptr_t memAddrValue = (uintptr_t)touch; + unassignedPointerIds = [pointerIdPool mutableCopy]; //reset unassignedPointerIds + [unassignedPointerIds minusSet:activePointerIds]; + uint8_t pointerId = [[unassignedPointerIds anyObject] intValue]; + [pointerIdDict setObject:@(pointerId) forKey:@(memAddrValue)]; + [activePointerIds addObject:@(pointerId)]; +} + +// remove pointerId in touchesEnded or touchesCancelled +- (void)removePointerId:(UITouch*)touch{ + uintptr_t memAddrValue = (uintptr_t)touch; + NSNumber* pointerIdObj = [pointerIdDict objectForKey:@(memAddrValue)]; + if(pointerIdObj != nil){ + [activePointerIds removeObject:pointerIdObj]; + [pointerIdDict removeObjectForKey:@(memAddrValue)]; + } +} + +// 从字典中获取UITouch事件对应的pointerId +// called in method of sendTouchEvent +- (uint32_t) retrievePointerIdFromDict:(UITouch*)touch{ + return [[pointerIdDict objectForKey:@((uintptr_t)touch)] unsignedIntValue]; +} + + - (void)sendTouchEvent:(UITouch*)touch withTouchtype:(uint8_t)touchType{ CGPoint targetCoords; if(activateCoordSelector && touch.phase == UITouchPhaseMoved) targetCoords = [NativeTouchPointer selectCoordsFor:touch]; // coordinates of touch pointer replaced to relative ones here. else targetCoords = [touch locationInView:streamView]; CGPoint location = [streamView adjustCoordinatesForVideoArea:targetCoords]; CGSize videoSize = [streamView getVideoAreaSize]; - LiSendTouchEvent(touchType,[NativeTouchPointer retrievePointerIdFromDict:touch],location.x / videoSize.width, location.y / videoSize.height,(touch.force / touch.maximumPossibleForce) / sin(touch.altitudeAngle),0.0f, 0.0f,[streamView getRotationFromAzimuthAngle:[touch azimuthAngleInView:streamView]]); + LiSendTouchEvent(touchType,[self retrievePointerIdFromDict:touch],location.x / videoSize.width, location.y / videoSize.height,(touch.force / touch.maximumPossibleForce) / sin(touch.altitudeAngle),0.0f, 0.0f,[streamView getRotationFromAzimuthAngle:[touch azimuthAngleInView:streamView]]); } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch* touch in touches){ - [NativeTouchPointer populatePointerId:touch]; //generate & populate pointerId + [self populatePointerId:touch]; //generate & populate pointerId if(activateCoordSelector) [NativeTouchPointer populatePointerObjIntoDict:touch]; [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_DOWN]; } @@ -66,18 +107,14 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch* touch in touches){ [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_UP]; //send touch event before remove pointerId - [NativeTouchPointer removePointerId:touch]; //then remove pointerId + [self removePointerId:touch]; //then remove pointerId if(activateCoordSelector) [NativeTouchPointer removePointerObjFromDict:touch]; } return; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - for (UITouch* touch in touches){ - [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_UP]; //send touch event before remove pointerId - [NativeTouchPointer removePointerId:touch]; //then remove pointerId - if(activateCoordSelector) [NativeTouchPointer removePointerObjFromDict:touch]; - } + [self touchesEnded:touches withEvent:event]; } diff --git a/Limelight/Input/NativeTouchPointer.h b/Limelight/Input/NativeTouchPointer.h index 37959e7e..8c06bdd3 100644 --- a/Limelight/Input/NativeTouchPointer.h +++ b/Limelight/Input/NativeTouchPointer.h @@ -12,10 +12,8 @@ NS_ASSUME_NONNULL_BEGIN @interface NativeTouchPointer : NSObject -+ (void)initContextWith:(StreamView *)view; -+ (void)populatePointerId:(UITouch*)touch; -+ (void)removePointerId:(UITouch*)touch; -+ (uint32_t) retrievePointerIdFromDict:(UITouch*)touch; ++ (void)initContextWithView:(StreamView *)view; + + (void)setPointerVelocityDivider:(CGFloat)dividerLocation; + (void)setPointerVelocityFactor:(CGFloat)velocityFactor; + (void)populatePointerObjIntoDict:(UITouch*)touch; @@ -24,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN + (CGPoint)selectCoordsFor:(UITouch *)touch; -- (instancetype)initWith:(UITouch *)touch; +- (instancetype)initWithTouch:(UITouch *)touch; @end diff --git a/Limelight/Input/NativeTouchPointer.m b/Limelight/Input/NativeTouchPointer.m index 36a98852..1803875d 100644 --- a/Limelight/Input/NativeTouchPointer.m +++ b/Limelight/Input/NativeTouchPointer.m @@ -15,12 +15,7 @@ // pointer instance with coordinate manipulation. -// Use a Dictionary to store UITouch object's memory address as key, and pointerId as value,字典存放UITouch对象地址和pointerId映射关系 -// pointerId will be generated from electronic noise, by arc4_random, pointerId,由随机噪声生成 -// Use a NSSet store pointerId, for quick repeition inquiry, NSSet存放活跃的pointerId合集,用于快速查找,以防重复. -static NSMutableDictionary *pointerIdDict; //pointerId Dict for native touch. -static NSMutableSet *pointerIdSet; //pointerIdSet for native touch. -static NSMutableDictionary *pointerDict; +static NSMutableDictionary *pointerObjDict; static CGFloat pointerVelocityFactor; static CGFloat pointerVelocityDivider; @@ -34,8 +29,6 @@ StreamView *streamView; CGPoint previousPoint; CGPoint latestRelativePoint; CGPoint previousRelativePoint; - // CGFloat velocityX; - // CGFloat velocityY; } + (void)setPointerVelocityDivider:(CGFloat)dividerLocation{ @@ -47,54 +40,50 @@ StreamView *streamView; } -- (instancetype)initWith:(UITouch *)touch{ - self = [self init]; - self->initialPoint = [touch locationInView:streamView]; - self->latestPoint = self->initialPoint; - self->latestRelativePoint = self->initialPoint; - return self; - } +- (instancetype)initWithTouch:(UITouch *)touch{ + self = [super init]; + self->initialPoint = [touch locationInView:streamView]; + self->latestPoint = self->initialPoint; + self->latestRelativePoint = self->initialPoint; + return self; +} - (void)updatePointerCoords:(UITouch *)touch{ previousPoint = latestPoint; latestPoint = [touch locationInView:streamView]; - // velocityX = latestPoint.x - previousPoint.x; - // velocityY = latestPoint.y - previousPoint.y; previousRelativePoint = latestRelativePoint; latestRelativePoint.x = previousRelativePoint.x + pointerVelocityFactor * (latestPoint.x - previousPoint.x); latestRelativePoint.y = previousRelativePoint.y + pointerVelocityFactor * (latestPoint.y - previousPoint.y); } -+ (void)initContextWith:(StreamView *)view{ ++ (void)initContextWithView:(StreamView *)view{ streamView = view; - pointerIdDict = [NSMutableDictionary dictionary]; - pointerIdSet = [NSMutableSet set]; - pointerDict = [NSMutableDictionary dictionary]; + pointerObjDict = [NSMutableDictionary dictionary]; pointerVelocityDividerLocationByPoints = CGRectGetWidth([[UIScreen mainScreen] bounds]) * pointerVelocityDivider; NSLog(@"pointerVelocityDivider: %.2f", pointerVelocityDivider); NSLog(@"pointerVelocityDividerLocationByPoints: %.2f", pointerVelocityDividerLocationByPoints); } + (void)populatePointerObjIntoDict:(UITouch*)touch{ - [pointerDict setObject:[[NativeTouchPointer alloc] initWith:touch] forKey:@((uint64_t)touch)]; + [pointerObjDict setObject:[[NativeTouchPointer alloc] initWithTouch:touch] forKey:@((uintptr_t)touch)]; } + (void)removePointerObjFromDict:(UITouch*)touch{ - uint64_t eventAddrValue = (uint64_t)touch; - NativeTouchPointer* pointer = [pointerDict objectForKey:@(eventAddrValue)]; + uintptr_t memAddrValue = (uintptr_t)touch; + NativeTouchPointer* pointer = [pointerObjDict objectForKey:@(memAddrValue)]; if(pointer != nil){ - [pointerDict removeObjectForKey:@(eventAddrValue)]; + [pointerObjDict removeObjectForKey:@(memAddrValue)]; } } + (void)updatePointerObjInDict:(UITouch *)touch{ - [[pointerDict objectForKey:@((uint64_t)touch)] updatePointerCoords:touch]; + [[pointerObjDict objectForKey:@((uintptr_t)touch)] updatePointerCoords:touch]; } + (CGPoint)selectCoordsFor:(UITouch *)touch{ - NativeTouchPointer *pointer = [pointerDict objectForKey:@((uint64_t)touch)]; + NativeTouchPointer *pointer = [pointerObjDict objectForKey:@((uintptr_t)touch)]; if((pointer -> initialPoint).x > pointerVelocityDividerLocationByPoints){ //if first contact coords locates on the right side of divider. return pointer->latestRelativePoint; } @@ -103,39 +92,5 @@ StreamView *streamView; -// 随机生成pointerId并填入NSDict和NSSet -// generate & populate pointerId into NSDict & NSSet, called in UITouchPhaseBegan -+ (void)populatePointerId:(UITouch*)touch{ - uint64_t eventAddrValue = (uint64_t)touch; - uint32_t randomPointerId = arc4random_uniform(UINT32_MAX); // generate pointerId from eletronic noise. - for(;;){ - if([pointerIdSet containsObject:@(randomPointerId)]) randomPointerId = arc4random_uniform(UINT32_MAX); // in case of new pointerId collides with existing ones, generate again. - else{ // populate pointerId into NSDict & NSSet. - [pointerIdDict setObject:@(randomPointerId) forKey:@(eventAddrValue)]; - [pointerIdSet addObject:@(randomPointerId)]; - return; - } - } -} - - - -// remove pointerId in UITouchPhaseEnded condition -+ (void)removePointerId:(UITouch*)touch{ - uint64_t eventAddrValue = (uint64_t)touch; - NSNumber* pointerIdObj = [pointerIdDict objectForKey:@(eventAddrValue)]; - if(pointerIdObj != nil){ - [pointerIdSet removeObject:pointerIdObj]; - [pointerIdDict removeObjectForKey:@(eventAddrValue)]; - } -} - -// 从字典中获取UITouch事件对应的pointerId -// call this only when NSDcit & NSSet is up-to-date. -+ (uint32_t) retrievePointerIdFromDict:(UITouch*)touch{ - return [[pointerIdDict objectForKey:@((uint64_t)touch)] unsignedIntValue]; -} - - @end diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index 0a10b9ea..349221c2 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -98,7 +98,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; switch (settings.touchMode.intValue) { case NATIVE_TOUCH_MODE: - self->touchHandler = [[NativeTouchHandler alloc] initWith:self and:settings];break; + self->touchHandler = [[NativeTouchHandler alloc] initWithView:self andSettings:settings];break; case RELATIVE_TOUCH_MODE: self->touchHandler = [[RelativeTouchHandler alloc] initWithView:self]; keyboardToggleRecognizer.immediateTriggering = true; //triggers signal in touchesBegan callback stage