diff --git a/Limelight/Input/NativeTouchHandler.h b/Limelight/Input/NativeTouchHandler.h index d0083c9d..09cbc83b 100644 --- a/Limelight/Input/NativeTouchHandler.h +++ b/Limelight/Input/NativeTouchHandler.h @@ -10,18 +10,24 @@ NS_ASSUME_NONNULL_BEGIN -@interface NativeTouchHandler : UIResponder +@interface TouchPointer : NSObject -+ (NSMutableDictionary* )initializePointerIdDict; -+ (NSMutableSet* )initializePointerIdSet; -+ (void)populatePointerId:(UITouch*)event; -+ (void)removePointerId:(UITouch*)event; -+ (uint32_t) retrievePointerIdFromDict:(UITouch*)event; ++ (void)initContextWith:(StreamView *)view; ++ (void)populatePointerId:(UITouch*)touch; ++ (void)removePointerId:(UITouch*)touch; ++ (uint32_t) retrievePointerIdFromDict:(UITouch*)touch; + ++ (void)populatePointerObjIntoDict:(UITouch*)touch; ++ (void)removePointerObjFromDict:(UITouch*)touch; ++ (void)updatePointerObjInDict:(UITouch *)touch; ++ (CGPoint)selectCoordsFor:(UITouch *)touch; --(id)initWithView:(StreamView*)view; - +- (instancetype)initWith:(UITouch *)touch; @end + + + NS_ASSUME_NONNULL_END diff --git a/Limelight/Input/NativeTouchHandler.m b/Limelight/Input/NativeTouchHandler.m index 3e6818b4..f70adfa4 100644 --- a/Limelight/Input/NativeTouchHandler.m +++ b/Limelight/Input/NativeTouchHandler.m @@ -7,9 +7,7 @@ // #import - #import "NativeTouchHandler.h" - #include @@ -18,31 +16,86 @@ // 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; -@implementation NativeTouchHandler { - StreamView* view; +static CGFloat pointerVelocityFactor = 0.7; +static CGFloat pointerVelocityDivider = 0.5; +static CGFloat pointerVelocityDividerLocation; + +StreamView *streamView; + +@implementation TouchPointer{ + CGPoint initialPoint; + CGPoint latestPoint; + CGPoint previousPoint; + CGPoint latestRelativePoint; + CGPoint previousRelativePoint; + CGFloat velocityX; + CGFloat velocityY; } -- (id)initWithView:(StreamView*)view { - self = [self init]; - self->view = view; - return self; +- (instancetype)initWith:(UITouch *)touch{ + self = [self 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]; + if (pointerVelocityFactor != 1.0f){ + velocityX = latestPoint.x - previousPoint.x; + velocityY = latestPoint.y - previousPoint.y; + previousRelativePoint = latestRelativePoint; + latestRelativePoint.x = previousRelativePoint.x + pointerVelocityFactor * velocityX; + latestRelativePoint.y = previousRelativePoint.y + pointerVelocityFactor * velocityY; + } +} + ++ (void)initContextWith:(StreamView *)view{ + streamView = view; + pointerIdDict = [NSMutableDictionary dictionary]; + pointerIdSet = [NSMutableSet set]; + pointerDict = [NSMutableDictionary dictionary]; + pointerVelocityDividerLocation = CGRectGetHeight([[UIScreen mainScreen] bounds]) *pointerVelocityDivider; +} + ++ (void)populatePointerObjIntoDict:(UITouch*)touch{ + [pointerDict setObject:[[TouchPointer alloc] initWith:touch] forKey:@((uint64_t)touch)]; +} + ++ (void)removePointerObjFromDict:(UITouch*)touch{ + uint64_t eventAddrValue = (uint64_t)touch; + TouchPointer* pointer = [pointerDict objectForKey:@(eventAddrValue)]; + if(pointer != nil){ + [pointerDict removeObjectForKey:@(eventAddrValue)]; + } + +} + ++ (void)updatePointerObjInDict:(UITouch *)touch{ + [[pointerDict objectForKey:@((uint64_t)touch)] updatePointerCoords:touch]; } -+ (NSMutableDictionary* )initializePointerIdDict { - return pointerIdDict = [NSMutableDictionary dictionary]; ++ (CGPoint)selectCoordsFor:(UITouch *)touch{ + if (pointerVelocityFactor != 1.0f){ + TouchPointer *pointer = [pointerDict objectForKey:@((uint64_t)touch)]; + if((pointer -> initialPoint).x > pointerVelocityDividerLocation){ + return pointer->latestRelativePoint; + } + } + return [touch locationInView:streamView]; } -+ (NSMutableSet* )initializePointerIdSet { - return pointerIdSet = [NSMutableSet set]; -} // 随机生成pointerId并填入NSDict和NSSet // generate & populate pointerId into NSDict & NSSet, called in UITouchPhaseBegan -+ (void)populatePointerId:(UITouch*)event{ - uint64_t eventAddrValue = (uint64_t)event; ++ (void)populatePointerId:(UITouch*)touch{ + uint64_t eventAddrValue = (uint64_t)touch; uint32_t randomPointerId = arc4random_uniform(UINT32_MAX); // generate pointerId from eletronic noise. while(true){ if([pointerIdSet containsObject:@(randomPointerId)]) randomPointerId = arc4random_uniform(UINT32_MAX); // in case of new pointerId collides with existing ones, generate again. @@ -54,9 +107,11 @@ static NSMutableSet *pointerIdSet; //pointerIdSet for native touch. } } + + // remove pointerId in UITouchPhaseEnded condition -+ (void)removePointerId:(UITouch*)event{ - uint64_t eventAddrValue = (uint64_t)event; ++ (void)removePointerId:(UITouch*)touch{ + uint64_t eventAddrValue = (uint64_t)touch; NSNumber* pointerIdObj = [pointerIdDict objectForKey:@(eventAddrValue)]; if(pointerIdObj != nil){ [pointerIdSet removeObject:pointerIdObj]; @@ -66,8 +121,8 @@ static NSMutableSet *pointerIdSet; //pointerIdSet for native touch. // 从字典中获取UITouch事件对应的pointerId // call this only when NSDcit & NSSet is up-to-date. -+ (uint32_t) retrievePointerIdFromDict:(UITouch*)event{ - return [[pointerIdDict objectForKey:@((uint64_t)event)] unsignedIntValue]; ++ (uint32_t) retrievePointerIdFromDict:(UITouch*)touch{ + return [[pointerIdDict objectForKey:@((uint64_t)touch)] unsignedIntValue]; } diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index 925514b5..a645238b 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -57,8 +57,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (void) setupStreamView:(ControllerSupport*)controllerSupport interactionDelegate:(id)interactionDelegate config:(StreamConfiguration*)streamConfig { - [NativeTouchHandler initializePointerIdDict]; - [NativeTouchHandler initializePointerIdSet]; + [TouchPointer initContextWith:self]; self->interactionDelegate = interactionDelegate; self->streamAspectRatio = (float)streamConfig.width / (float)streamConfig.height; @@ -333,9 +332,12 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (void)sendTouchEvent:(UITouch*)event touchType:(uint8_t)touchType{ - CGPoint location = [self adjustCoordinatesForVideoArea:[event locationInView:self]]; + CGPoint targetCoords; + if(true) targetCoords = [TouchPointer selectCoordsFor:event]; + else targetCoords = [event locationInView:self]; + CGPoint location = [self adjustCoordinatesForVideoArea:targetCoords]; CGSize videoSize = [self getVideoAreaSize]; - LiSendTouchEvent(touchType,[NativeTouchHandler retrievePointerIdFromDict:event],location.x / videoSize.width, location.y / videoSize.height,(event.force / event.maximumPossibleForce) / sin(event.altitudeAngle),0.0f, 0.0f,[self getRotationFromAzimuthAngle:[event azimuthAngleInView:self]]); + LiSendTouchEvent(touchType,[TouchPointer retrievePointerIdFromDict:event],location.x / videoSize.width, location.y / videoSize.height,(event.force / event.maximumPossibleForce) / sin(event.altitudeAngle),0.0f, 0.0f,[self getRotationFromAzimuthAngle:[event azimuthAngleInView:self]]); } @@ -365,11 +367,13 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; switch (event.phase) { case UITouchPhaseBegan://开始触摸 type = LI_TOUCH_EVENT_DOWN; - [NativeTouchHandler populatePointerId:event]; //获取并记录pointerId + [TouchPointer populatePointerId:event]; //获取并记录pointerId + if(true) [TouchPointer populatePointerObjIntoDict:event]; break; case UITouchPhaseMoved://移动 case UITouchPhaseStationary: type = LI_TOUCH_EVENT_MOVE; + if(true) [TouchPointer updatePointerObjInDict:event]; break; case UITouchPhaseRegionEntered://停留 case UITouchPhaseRegionMoved://停留 @@ -378,17 +382,18 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; case UITouchPhaseCancelled://触摸取消 type = LI_TOUCH_EVENT_CANCEL; [self sendTouchEvent:event touchType:type]; //先发送,再删除 - [NativeTouchHandler removePointerId:event]; //删除pointerId + [TouchPointer removePointerId:event]; //删除pointerId + if(true) [TouchPointer removePointerObjFromDict:event]; return; case UITouchPhaseEnded://触摸结束 type = LI_TOUCH_EVENT_UP; [self sendTouchEvent:event touchType:type]; //先发送,再删除 - [NativeTouchHandler removePointerId:event]; //删除pointerId + [TouchPointer removePointerId:event]; //删除pointerId + if(true) [TouchPointer removePointerObjFromDict:event]; return; default: return; } - [self sendTouchEvent:event touchType:type]; }