async mouse move event for relative touch handler
This commit is contained in:
1 parent
e0691dcd97
commit
420eebf831
2 files changed
+43
-23
No files matched your search
@@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@interface RelativeTouchHandler : UIResponder
|
@interface RelativeTouchHandler : UIResponder
|
||||||
@property (nonatomic, readonly) CustomTapGestureRecognizer* mouseRightClickTapRecognizer; // this object will be passed to onscreencontrol class for areVirtualControllerTaps flag setting
|
@property (nonatomic, readonly) CustomTapGestureRecognizer* mouseRightClickTapRecognizer; // this object will be passed to onscreencontrol class for areVirtualControllerTaps flag setting
|
||||||
|
@property (nonatomic, strong) CADisplayLink *displayLink;
|
||||||
|
|
||||||
|
|
||||||
+ (void) testMethod;
|
+ (void) testMethod;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const int REFERENCE_WIDTH = 1280;
|
static const int REFERENCE_WIDTH = 1280;
|
||||||
static const int REFERENCE_HEIGHT = 720;
|
static const int REFERENCE_HEIGHT = 720;
|
||||||
static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
||||||
@@ -21,6 +22,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
CGPoint latestMousePointerLocation, initialMousePointerLocation;
|
CGPoint latestMousePointerLocation, initialMousePointerLocation;
|
||||||
CGPoint twoFingerTouchLocation;
|
CGPoint twoFingerTouchLocation;
|
||||||
NSTimeInterval mousePointerTimestamp;
|
NSTimeInterval mousePointerTimestamp;
|
||||||
|
CGRect streamViewBounds;
|
||||||
BOOL mousePointerMoved;
|
BOOL mousePointerMoved;
|
||||||
BOOL quickTapDetected;
|
BOOL quickTapDetected;
|
||||||
BOOL isInMouseWheelScrollingMode;
|
BOOL isInMouseWheelScrollingMode;
|
||||||
@@ -48,6 +50,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
- (id)initWithView:(StreamView*)view andSettings:(TemporarySettings*)settings {
|
- (id)initWithView:(StreamView*)view andSettings:(TemporarySettings*)settings {
|
||||||
self = [self init];
|
self = [self init];
|
||||||
self->streamView = view;
|
self->streamView = view;
|
||||||
|
self->streamViewBounds = view.bounds;
|
||||||
self->currentSettings = settings;
|
self->currentSettings = settings;
|
||||||
// replace righclick recoginizing with my CustomTapGestureRecognizer for better experience, higher recoginizing rate.
|
// replace righclick recoginizing with my CustomTapGestureRecognizer for better experience, higher recoginizing rate.
|
||||||
_mouseRightClickTapRecognizer = [[CustomTapGestureRecognizer alloc] initWithTarget:self action:@selector(mouseRightClick)];
|
_mouseRightClickTapRecognizer = [[CustomTapGestureRecognizer alloc] initWithTarget:self action:@selector(mouseRightClick)];
|
||||||
@@ -67,6 +70,8 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
screenWidthWithThreshold = CGRectGetWidth([[UIScreen mainScreen] bounds]) - EDGE_TOLERANCE;
|
screenWidthWithThreshold = CGRectGetWidth([[UIScreen mainScreen] bounds]) - EDGE_TOLERANCE;
|
||||||
self->touchPointSpawnedAtUpperScreenEdge = false;
|
self->touchPointSpawnedAtUpperScreenEdge = false;
|
||||||
|
|
||||||
|
[self setupDisplayLink];
|
||||||
|
|
||||||
#if TARGET_OS_TV
|
#if TARGET_OS_TV
|
||||||
remotePressRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(remoteButtonPressed:)];
|
remotePressRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(remoteButtonPressed:)];
|
||||||
remotePressRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
|
remotePressRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
|
||||||
@@ -81,6 +86,21 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setupDisplayLink {
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
self.displayLink = [CADisplayLink displayLinkWithTarget:weakSelf selector:@selector(handleDisplayLink:)];
|
||||||
|
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||||
|
self.displayLink.paused = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleDisplayLink:(CADisplayLink *)sender {
|
||||||
|
|
||||||
|
if(!mousePointerMoved && touchLockedForMouseMove != nil){
|
||||||
|
[self sendMouseMoveEvent:touchLockedForMouseMove];
|
||||||
|
NSLog(@"stationary mouse event, %f", CACurrentMediaTime());
|
||||||
|
}
|
||||||
|
mousePointerMoved = false;
|
||||||
|
}
|
||||||
|
|
||||||
- (bool)isOnScreenControllerBeingPressed:(NSSet* )touches{
|
- (bool)isOnScreenControllerBeingPressed:(NSSet* )touches{
|
||||||
for(UITouch* touch in touches){
|
for(UITouch* touch in touches){
|
||||||
@@ -114,7 +134,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
|
|
||||||
|
|
||||||
- (void)mouseRightClick {
|
- (void)mouseRightClick {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
||||||
Log(LOG_D, @"Sending right mouse button press");
|
Log(LOG_D, @"Sending right mouse button press");
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
// Wait 100 ms to simulate a real button press
|
// Wait 100 ms to simulate a real button press
|
||||||
@@ -123,13 +143,13 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
- (BOOL)isConfirmedMove:(CGPoint)currentPoint from:(CGPoint)originalPoint {
|
- (BOOL)isConfirmedMove:(CGPoint)currentPoint from:(CGPoint)originalPoint {
|
||||||
// Movements of greater than 5 pixels are considered confirmed
|
// Movements of greater than 1 point are considered confirmed
|
||||||
return hypotf(originalPoint.x - currentPoint.x, originalPoint.y - currentPoint.y) >= 5;
|
return hypotf(originalPoint.x - currentPoint.x, originalPoint.y - currentPoint.y) >= 1;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
- (BOOL)isAdjacentTouches:(CGPoint)currentPoint from:(CGPoint)originalPoint {
|
- (BOOL)isAdjacentTouches:(CGPoint)currentPoint from:(CGPoint)originalPoint {
|
||||||
// Movements of greater than 5 pixels are considered confirmed
|
|
||||||
return hypotf(originalPoint.x - currentPoint.x, originalPoint.y - currentPoint.y) <= 100;
|
return hypotf(originalPoint.x - currentPoint.x, originalPoint.y - currentPoint.y) <= 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +198,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
|
|
||||||
// we must use [event allTouches] to check if touchLockedForMouseMove is captured, because the UITouch object could be captured by upper layer of UIView(in cases like tap gestures), not passed to the touches callbacks in this class, but still available in [event allTouches]
|
// we must use [event allTouches] to check if touchLockedForMouseMove is captured, because the UITouch object could be captured by upper layer of UIView(in cases like tap gestures), not passed to the touches callbacks in this class, but still available in [event allTouches]
|
||||||
if(candidateTouch != nil && ![[event allTouches] containsObject:touchLockedForMouseMove]){
|
if(candidateTouch != nil && ![[event allTouches] containsObject:touchLockedForMouseMove]){
|
||||||
|
self.displayLink.paused = NO;
|
||||||
touchLockedForMouseMove = candidateTouch;
|
touchLockedForMouseMove = candidateTouch;
|
||||||
NSLog(@"Candidate touch for mouse movement locked");
|
NSLog(@"Candidate touch for mouse movement locked");
|
||||||
mousePointerTimestamp = CACurrentMediaTime();
|
mousePointerTimestamp = CACurrentMediaTime();
|
||||||
@@ -230,11 +251,13 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
}
|
}
|
||||||
touchLockedForMouseMove = nil;
|
touchLockedForMouseMove = nil;
|
||||||
mousePointerMoved = false;
|
mousePointerMoved = false;
|
||||||
|
self.displayLink.paused = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
if([[event allTouches] count] == [touches count]){
|
if([[event allTouches] count] == [touches count]){
|
||||||
isInMouseWheelScrollingMode = false;
|
isInMouseWheelScrollingMode = false;
|
||||||
touchLockedForMouseMove = nil;
|
touchLockedForMouseMove = nil;
|
||||||
|
self.displayLink.paused = YES;
|
||||||
mousePointerMoved = false; // need to reset this anyway
|
mousePointerMoved = false; // need to reset this anyway
|
||||||
[self resetAllPressedFlagsForOnScreenWidgetViews]; // reset all pressed flag for on-screen widget views after all fingers lifted from screen.
|
[self resetAllPressedFlagsForOnScreenWidgetViews]; // reset all pressed flag for on-screen widget views after all fingers lifted from screen.
|
||||||
touchPointSpawnedAtUpperScreenEdge = false;
|
touchPointSpawnedAtUpperScreenEdge = false;
|
||||||
@@ -243,33 +266,29 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
|
|
||||||
|
|
||||||
- (void)sendMouseMoveEvent:(UITouch* )touch{
|
- (void)sendMouseMoveEvent:(UITouch* )touch{
|
||||||
if(touchPointSpawnedAtUpperScreenEdge) return; // we're done here. this touch event will not be sent to the remote PC.
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
||||||
|
if(self->touchPointSpawnedAtUpperScreenEdge) return; // we're done here. this touch event will not be sent to the remote PC.
|
||||||
|
|
||||||
CGPoint currentLocation = [touch locationInView:streamView];
|
CGPoint currentLocation = [touch locationInView:self->streamView];
|
||||||
|
|
||||||
if (latestMousePointerLocation.x != currentLocation.x ||
|
if (self->latestMousePointerLocation.x != currentLocation.x ||
|
||||||
latestMousePointerLocation.y != currentLocation.y)
|
self->latestMousePointerLocation.y != currentLocation.y)
|
||||||
{
|
{
|
||||||
int deltaX = (currentLocation.x - latestMousePointerLocation.x) * (REFERENCE_WIDTH / streamView.bounds.size.width) * currentSettings.mousePointerVelocityFactor.floatValue;
|
int deltaX = (currentLocation.x - self->latestMousePointerLocation.x) * (REFERENCE_WIDTH / self->streamViewBounds.size.width) * self->currentSettings.mousePointerVelocityFactor.floatValue;
|
||||||
int deltaY = (currentLocation.y - latestMousePointerLocation.y) * (REFERENCE_HEIGHT / streamView.bounds.size.height) * currentSettings.mousePointerVelocityFactor.floatValue;
|
int deltaY = (currentLocation.y - self->latestMousePointerLocation.y) * (REFERENCE_HEIGHT / self->streamViewBounds.size.height) * self->currentSettings.mousePointerVelocityFactor.floatValue;
|
||||||
|
|
||||||
if (deltaX != 0 || deltaY != 0) {
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||||
latestMousePointerLocation = currentLocation;
|
self->latestMousePointerLocation = currentLocation;
|
||||||
|
|
||||||
// If we've moved far enough to confirm this wasn't just human/machine error,
|
|
||||||
// mark it as such.
|
|
||||||
if ([self isConfirmedMove:latestMousePointerLocation from:initialMousePointerLocation]) {
|
|
||||||
mousePointerMoved = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// this will turn into a dragging anytime...
|
// this will turn into a dragging anytime...
|
||||||
- (void)sendLongMouseLeftButtonClickEvent{
|
- (void)sendLongMouseLeftButtonClickEvent{
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
||||||
// if (!self->isDragging){
|
// if (!self->isDragging){
|
||||||
Log(LOG_D, @"Sending left mouse button press");
|
Log(LOG_D, @"Sending left mouse button press");
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
@@ -285,7 +304,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendShortMouseLeftButtonClickEvent{
|
- (void)sendShortMouseLeftButtonClickEvent{
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
|
||||||
usleep(50 * 1000);
|
usleep(50 * 1000);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
usleep(50 * 1000);
|
usleep(50 * 1000);
|
||||||
|
|||||||
Reference in new issue
Block a user