PointerVelocity tweak core implementation

This commit is contained in:
True Zhuanjia
2024-05-29 00:54:42 +08:00
parent 9b270b2e90
commit 6c5cd094c3
3 changed files with 101 additions and 35 deletions
+14 -8
View File
@@ -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
+74 -19
View File
@@ -7,9 +7,7 @@
//
#import <Foundation/Foundation.h>
#import "NativeTouchHandler.h"
#include <Limelight.h>
@@ -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<NSNumber *> *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<NSNumber *> *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<NSNumber *> *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];
}
+13 -8
View File
@@ -57,8 +57,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
- (void) setupStreamView:(ControllerSupport*)controllerSupport
interactionDelegate:(id<UserInteractionDelegate>)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];
}