From c3c7e670fc949ccbf8de648204bd77791af8d545 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Tue, 18 Jun 2024 02:12:35 +0800 Subject: [PATCH] resolve gesture competition in non-native touch modes --- Limelight/Input/CustomTapGestureRecognizer.h | 1 + Limelight/Input/CustomTapGestureRecognizer.m | 19 ++++++++++++++++--- Limelight/Input/RelativeTouchHandler.m | 2 +- Limelight/Input/StreamView.m | 11 ++++++++--- .../StreamFrameViewController.m | 1 + 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Limelight/Input/CustomTapGestureRecognizer.h b/Limelight/Input/CustomTapGestureRecognizer.h index 687e8596..cc1aaf7a 100644 --- a/Limelight/Input/CustomTapGestureRecognizer.h +++ b/Limelight/Input/CustomTapGestureRecognizer.h @@ -17,6 +17,7 @@ @property (nonatomic, assign) uint8_t numberOfTouchesRequired; +@property (nonatomic, assign) bool immediateTriggering; // trigger the signal on touchesBegan stage if enabled. @property (nonatomic, assign) double tapDownTimeThreshold; // tap down threshold in seconds. @property (nonatomic, readonly) CGFloat lowestTouchPointHeight; @property (nonatomic, readonly) bool gestureCaptured; diff --git a/Limelight/Input/CustomTapGestureRecognizer.m b/Limelight/Input/CustomTapGestureRecognizer.m index ef797089..846e7a50 100644 --- a/Limelight/Input/CustomTapGestureRecognizer.m +++ b/Limelight/Input/CustomTapGestureRecognizer.m @@ -10,8 +10,11 @@ #import #import "CustomTapGestureRecognizer.h" -// The most accurate & reliable tap gesture recognizer of iOS with almost 100% recoginition rate, instances of different numberOfTouchesRequired barely compete with each other. UITapGestureRecognizer of Apple API is just intractable. -// Known issue: not reliable in absolute touch mode, since it competes with 2 finger zoom-in & out gestures from original moonlight +// The most accurate & reliable tap gesture recognizer of iOS: +// - almost 100% recoginition rate. UITapGestureRecognizer of Apple API is just intractable. +// - instances of different numberOfTouchesRequired barely compete with each other, even when immediateTriggering is set to false. +// - set property immediateTriggering = true, ensures no competition with gestures of less fingers in non-native touch mode. + @implementation CustomTapGestureRecognizer static CGFloat screenHeightInPoints; @@ -20,6 +23,10 @@ static CGFloat screenHeightInPoints; self = [super initWithTarget:target action:action]; screenHeightInPoints = CGRectGetHeight([[UIScreen mainScreen] bounds]); lowestTouchPointYCoord = 0.0; + _numberOfTouchesRequired = 3; + _immediateTriggering = false; + _tapDownTimeThreshold = 0.3; + _gestureCaptured = false; return self; } @@ -32,6 +39,11 @@ static CGFloat screenHeightInPoints; if(lowestTouchPointYCoord < [touch locationInView:self.view].y) lowestTouchPointYCoord = [touch locationInView:self.view].y; } _lowestTouchPointHeight = screenHeightInPoints - lowestTouchPointYCoord; + if(_immediateTriggering){ + lowestTouchPointYCoord = 0.0; //reset for next recoginition + self.state = UIGestureRecognizerStateRecognized; + return; + } self.state = UIGestureRecognizerStatePossible; } if ([[event allTouches] count] > _numberOfTouchesRequired) { @@ -42,7 +54,8 @@ static CGFloat screenHeightInPoints; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // [super touchesEnded:touches withEvent:event]; - if ([[event allTouches] count] > _numberOfTouchesRequired) { + if(_immediateTriggering) return; + if([[event allTouches] count] > _numberOfTouchesRequired) { _gestureCaptured = false; self.state = UIGestureRecognizerStateFailed; } else if(_gestureCaptured && [[event allTouches] count] == [touches count]){ diff --git a/Limelight/Input/RelativeTouchHandler.m b/Limelight/Input/RelativeTouchHandler.m index db020714..c32ffe29 100644 --- a/Limelight/Input/RelativeTouchHandler.m +++ b/Limelight/Input/RelativeTouchHandler.m @@ -10,7 +10,7 @@ #import "CustomTapGestureRecognizer.h" #include -#define RIGHTCLICK_TAP_DOWN_TIME_THRESHOLD_S 0.1 +#define RIGHTCLICK_TAP_DOWN_TIME_THRESHOLD_S 0.2 static const int REFERENCE_WIDTH = 1280; diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index be1efbb0..0a10b9ea 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -98,11 +98,16 @@ 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] initWith:self and:settings];break; case RELATIVE_TOUCH_MODE: - self->touchHandler = [[RelativeTouchHandler alloc] initWithView:self]; break; + self->touchHandler = [[RelativeTouchHandler alloc] initWithView:self]; + keyboardToggleRecognizer.immediateTriggering = true; //triggers signal in touchesBegan callback stage + break; case ABSOLUTE_TOUCH_MODE: - self->touchHandler = [[AbsoluteTouchHandler alloc] initWithView:self]; break; + self->touchHandler = [[AbsoluteTouchHandler alloc] initWithView:self]; + keyboardToggleRecognizer.immediateTriggering = true; //triggers signal in touchesBegan callback stage + break; + default: break; } diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index 448ab1e5..fee96e2e 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -196,6 +196,7 @@ _scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame]; #if !TARGET_OS_TV [_scrollView.panGestureRecognizer setMinimumNumberOfTouches:2]; + [_scrollView.panGestureRecognizer setMaximumNumberOfTouches:2]; // reduce competing with keyboardToggleRecognizer in StreamView. #endif [_scrollView setShowsHorizontalScrollIndicator:NO]; [_scrollView setShowsVerticalScrollIndicator:NO];