Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Native Touch Passthrough and Better Gesture Recognizing #628

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
2e403ac
9.0.0-AXX-MultiTouch
Feb 17, 2024
2316a9e
Rename Project
Feb 17, 2024
6a9150c
Rename App to Moonlight-ZWM
Feb 17, 2024
8d25d23
Remove "exitSwipeRecognizer" on none-tvOS Target, prevent accidentall…
Feb 17, 2024
8e5c9b5
Resolving bug caused by 64 bit touch event pointer converted to uint3…
Apr 13, 2024
a435b5b
remove unnecessary logs & annotations.
Apr 13, 2024
d7e03e6
Update README.md
TrueZhuangJia Apr 13, 2024
98e6a28
Update README.md
TrueZhuangJia Apr 13, 2024
1c90390
Update README.md
TrueZhuangJia Apr 13, 2024
555726e
Update README.md
TrueZhuangJia Apr 13, 2024
8d751c0
Update README.md
TrueZhuangJia Apr 13, 2024
600fc58
Update README.md
TrueZhuangJia Apr 13, 2024
af37c25
Update README.md
TrueZhuangJia Apr 13, 2024
f997b35
Update README.md
TrueZhuangJia Apr 13, 2024
a6adbfc
Update README.md
TrueZhuangJia Apr 13, 2024
fe73054
Update README.md
TrueZhuangJia Apr 13, 2024
5e35318
Update README.md
TrueZhuangJia Apr 19, 2024
164f5bf
Update README.md
TrueZhuangJia Apr 19, 2024
07af0e4
Update README.md
TrueZhuangJia Apr 19, 2024
023b013
Update README.md
TrueZhuangJia Apr 19, 2024
9add83f
Update README.md
TrueZhuangJia Apr 19, 2024
b451b65
Update README.md
TrueZhuangJia Apr 19, 2024
f08d7c7
Update README.md
TrueZhuangJia Apr 19, 2024
65e7190
Update README.MD
Apr 20, 2024
218b203
Merge branch 'Moonlight-iOS-ZWM' of https://github.com/TrueZhuangJia/…
Apr 20, 2024
8dc445e
TEMP
Apr 30, 2024
fd8cc41
Merged with 9.0.2 modification
Apr 30, 2024
616238e
Add a custom gesture recognizer to trigger session disconnection when…
Apr 30, 2024
a43905d
update Readme.md
Apr 30, 2024
f80e56f
Update README.md
TrueZhuangJia Apr 30, 2024
4faa814
Update README.md
TrueZhuangJia Apr 30, 2024
813a488
Update README.md
TrueZhuangJia Apr 30, 2024
b98ccb2
update ignore
Apr 30, 2024
2e7ffc2
improve custom edge swipe recognizer on detecting start point. Swipe…
May 9, 2024
4e59c33
remove logs
May 9, 2024
0fda662
Improved pointerId mechanism, 0 probability of repetition.
TrueZhuangJia May 12, 2024
4b2ae15
bug fix
TrueZhuangJia May 12, 2024
afc390b
Update README.md
TrueZhuangJia May 13, 2024
6207d77
Re-enable keyboard toggle in native touch mode, with a gesture of 2 t…
TrueZhuangJia May 13, 2024
82de44d
Rewrite CustomEdgeSwipeGestureRecognizer to fix unexpected session di…
TrueZhuangJia May 14, 2024
208688a
Refactor related codes to NativeTouchHandler
TrueZhuangJia May 15, 2024
b1b0be8
Define CustomTapGestureRecognizer to reliably toggle local keyboard, …
TrueZhuangJia May 15, 2024
4987298
Add menu entry for configurable fingers to tap on local keyboard
TrueZhuangJia May 15, 2024
72547b1
Fix [fingers to tap on keyboard] config not loading.
TrueZhuangJia May 15, 2024
f85b736
improve keyboard toggle by adding keyboard notification. minor UI str…
TrueZhuangJia May 16, 2024
0f5ca5d
Add menu entry for swipe&exit distance
TrueZhuangJia May 16, 2024
a51d471
Add menu entry for swipe&exit screen edge, set for CustomEdgeSwipeRec…
TrueZhuangJia May 16, 2024
2b5601d
Add menu entries in iphone storyboard.
TrueZhuangJia May 16, 2024
5d7258a
tweak iphone storyboard
TrueZhuangJia May 16, 2024
8d9e822
assign default values for new setting entries in menu
TrueZhuangJia May 17, 2024
19dc6a6
Update README.md
TrueZhuangJia May 17, 2024
743dad5
allow fingers to tap slider dragged to a position higher than 10, whe…
TrueZhuangJia May 17, 2024
d7aa2d0
Update README.md
TrueZhuangJia May 17, 2024
7d9eb2a
Update README.md
TrueZhuangJia May 18, 2024
6b48083
Update README.md
TrueZhuangJia May 21, 2024
d54205d
Implement view lifting for keyboard invoke.
TrueZhuangJia May 25, 2024
d64c746
add menu entries for streamview lift & keyboard toolbar
TrueZhuangJia May 26, 2024
2674267
Update annotation
TrueZhuangJia May 26, 2024
5b9f292
Update README.md
TrueZhuangJia May 26, 2024
1e0a244
Update README.md
TrueZhuangJia May 26, 2024
7f6c14f
Update README.md
TrueZhuangJia May 26, 2024
746479d
fix view lift bug on iOS14 ipad mini5
TrueZhuangJia May 26, 2024
e5fa7f9
fix view lift not working on first keyboard invoke.
TrueZhuangJia May 27, 2024
b4bef08
Update README.md
TrueZhuangJia May 28, 2024
9b270b2
Update README.md
TrueZhuangJia May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
**/xcschemes/*.xcscheme
Build
DerivedData
*.xccheckout
5 changes: 5 additions & 0 deletions Limelight/Database/DataManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
width:(NSInteger)width
audioConfig:(NSInteger)audioConfig
onscreenControls:(NSInteger)onscreenControls
keyboardToggleFingers:(NSInteger)keyboardToggleFingers
swipeExitScreenEdge:(NSInteger)swipeExitScreenEdge
swipeToExitDistance:(CGFloat)swipeToExitDistance
liftStreamViewForKeyboard:(BOOL)liftStreamViewForKeyboard
showKeyboardToolbar:(BOOL)showKeyboardToolbar
optimizeGames:(BOOL)optimizeGames
multiController:(BOOL)multiController
swapABXYButtons:(BOOL)swapABXYButtons
Expand Down
10 changes: 10 additions & 0 deletions Limelight/Database/DataManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ - (void) saveSettingsWithBitrate:(NSInteger)bitrate
width:(NSInteger)width
audioConfig:(NSInteger)audioConfig
onscreenControls:(NSInteger)onscreenControls
keyboardToggleFingers:(NSInteger)keyboardToggleFingers
swipeExitScreenEdge:(NSInteger)swipeExitScreenEdge
swipeToExitDistance:(CGFloat)swipeToExitDistance
liftStreamViewForKeyboard:(BOOL)liftStreamViewForKeyboard
showKeyboardToolbar:(BOOL)showKeyboardToolbar
optimizeGames:(BOOL)optimizeGames
multiController:(BOOL)multiController
swapABXYButtons:(BOOL)swapABXYButtons
Expand All @@ -77,6 +82,11 @@ - (void) saveSettingsWithBitrate:(NSInteger)bitrate
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.audioConfig = [NSNumber numberWithInteger:audioConfig];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
settingsToSave.keyboardToggleFingers = [NSNumber numberWithInteger:(uint16_t)keyboardToggleFingers];
settingsToSave.swipeExitScreenEdge = [NSNumber numberWithInteger:(uint32_t)swipeExitScreenEdge];
settingsToSave.swipeToExitDistance = [NSNumber numberWithFloat:swipeToExitDistance];
settingsToSave.liftStreamViewForKeyboard = liftStreamViewForKeyboard;
settingsToSave.showKeyboardToolbar = showKeyboardToolbar;
settingsToSave.optimizeGames = optimizeGames;
settingsToSave.multiController = multiController;
settingsToSave.swapABXYButtons = swapABXYButtons;
Expand Down
6 changes: 6 additions & 0 deletions Limelight/Database/TemporarySettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * audioConfig;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSNumber * keyboardToggleFingers;
@property (nonatomic, retain) NSNumber * swipeExitScreenEdge;
@property (nonatomic, retain) NSNumber * swipeToExitDistance;
@property (nonatomic, retain) NSString * uniqueId;
@property (nonatomic) enum {
CODEC_PREF_AUTO,
Expand All @@ -34,6 +37,9 @@
@property (nonatomic) BOOL btMouseSupport;
@property (nonatomic) BOOL absoluteTouchMode;
@property (nonatomic) BOOL statsOverlay;
@property (nonatomic) BOOL liftStreamViewForKeyboard;
@property (nonatomic) BOOL showKeyboardToolbar;


- (id) initFromSettings:(Settings*)settings;

Expand Down
5 changes: 5 additions & 0 deletions Limelight/Database/TemporarySettings.m
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ - (id) initFromSettings:(Settings*)settings {
self.btMouseSupport = settings.btMouseSupport;
self.absoluteTouchMode = settings.absoluteTouchMode;
self.statsOverlay = settings.statsOverlay;
self.keyboardToggleFingers = settings.keyboardToggleFingers;
self.swipeExitScreenEdge = settings.swipeExitScreenEdge;
self.swipeToExitDistance = settings.swipeToExitDistance;
self.liftStreamViewForKeyboard = settings.liftStreamViewForKeyboard;
self.showKeyboardToolbar = settings.showKeyboardToolbar;
#endif
self.uniqueId = settings.uniqueId;

Expand Down
158 changes: 80 additions & 78 deletions Limelight/Input/AbsoluteTouchHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,83 +38,85 @@ - (id)initWithView:(StreamView*)view {
return self;
}

- (void)onLongPressStart:(NSTimer*)timer {
// Raise the left click and start a right click
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// Ignore touch down events with more than one finger
if ([[event allTouches] count] > 1) {
return;
}

UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:view];

// Don't reposition for finger down events within the deadzone. This makes double-clicking easier.
if (touch.timestamp - lastTouchUp.timestamp > DOUBLE_TAP_DEAD_ZONE_DELAY ||
sqrt(pow((touchLocation.x / view.bounds.size.width) - (lastTouchUpLocation.x / view.bounds.size.width), 2) +
pow((touchLocation.y / view.bounds.size.height) - (lastTouchUpLocation.y / view.bounds.size.height), 2)) > DOUBLE_TAP_DEAD_ZONE_DELTA) {
[view updateCursorLocation:touchLocation isMouse:NO];
}

// Press the left button down
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);

// Start the long press timer
longPressTimer = [NSTimer scheduledTimerWithTimeInterval:LONG_PRESS_ACTIVATION_DELAY
target:self
selector:@selector(onLongPressStart:)
userInfo:nil
repeats:NO];

lastTouchDown = touch;
lastTouchDownLocation = touchLocation;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// Ignore touch move events with more than one finger
if ([[event allTouches] count] > 1) {
return;
}

UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:view];

if (sqrt(pow((touchLocation.x / view.bounds.size.width) - (lastTouchDownLocation.x / view.bounds.size.width), 2) +
pow((touchLocation.y / view.bounds.size.height) - (lastTouchDownLocation.y / view.bounds.size.height), 2)) > LONG_PRESS_ACTIVATION_DELTA) {
// Moved too far since touch down. Cancel the long press timer.
[longPressTimer invalidate];
longPressTimer = nil;
}

[view updateCursorLocation:[[touches anyObject] locationInView:view] isMouse:NO];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Only fire this logic if all touches have ended
if ([[event allTouches] count] == [touches count]) {
// Cancel the long press timer
[longPressTimer invalidate];
longPressTimer = nil;

// Left button up on finger up
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);

// Raise right button too in case we triggered a long press gesture
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);

// Remember this last touch for touch-down deadzoning
lastTouchUp = [touches anyObject];
lastTouchUpLocation = [lastTouchUp locationInView:view];
}
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
// Treat this as a normal touchesEnded event
[self touchesEnded:touches withEvent:event];
}
//- (void)onLongPressStart:(NSTimer*)timer {
// // Raise the left click and start a right click
// LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
// LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
//}
//
//- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// // Ignore touch down events with more than one finger
// return;
// if ([[event allTouches] count] > 1) {
// return;
// }
//
// UITouch* touch = [touches anyObject];
// CGPoint touchLocation = [touch locationInView:view];
//
// // Don't reposition for finger down events within the deadzone. This makes double-clicking easier.
// if (touch.timestamp - lastTouchUp.timestamp > DOUBLE_TAP_DEAD_ZONE_DELAY ||
// sqrt(pow((touchLocation.x / view.bounds.size.width) - (lastTouchUpLocation.x / view.bounds.size.width), 2) +
// pow((touchLocation.y / view.bounds.size.height) - (lastTouchUpLocation.y / view.bounds.size.height), 2)) > DOUBLE_TAP_DEAD_ZONE_DELTA) {
// [view updateCursorLocation:touchLocation isMouse:NO];
// }
//
// // Press the left button down
// LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
//
// // Start the long press timer
// longPressTimer = [NSTimer scheduledTimerWithTimeInterval:LONG_PRESS_ACTIVATION_DELAY
// target:self
// selector:@selector(onLongPressStart:)
// userInfo:nil
// repeats:NO];
//
// lastTouchDown = touch;
// lastTouchDownLocation = touchLocation;
//}
//
//- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// // Ignore touch move events with more than one finger
// return;
// if ([[event allTouches] count] > 1) {
// return;
// }
//
// UITouch* touch = [touches anyObject];
// CGPoint touchLocation = [touch locationInView:view];
//
// if (sqrt(pow((touchLocation.x / view.bounds.size.width) - (lastTouchDownLocation.x / view.bounds.size.width), 2) +
// pow((touchLocation.y / view.bounds.size.height) - (lastTouchDownLocation.y / view.bounds.size.height), 2)) > LONG_PRESS_ACTIVATION_DELTA) {
// // Moved too far since touch down. Cancel the long press timer.
// [longPressTimer invalidate];
// longPressTimer = nil;
// }
//
// [view updateCursorLocation:[[touches anyObject] locationInView:view] isMouse:NO];
//}
//
//- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// // Only fire this logic if all touches have ended
// if ([[event allTouches] count] == [touches count]) {
// // Cancel the long press timer
// [longPressTimer invalidate];
// longPressTimer = nil;
//
// // Left button up on finger up
// LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
//
// // Raise right button too in case we triggered a long press gesture
// LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
//
// // Remember this last touch for touch-down deadzoning
// lastTouchUp = [touches anyObject];
// lastTouchUpLocation = [lastTouchUp locationInView:view];
// }
//}
//
//- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
// // Treat this as a normal touchesEnded event
// [self touchesEnded:touches withEvent:event];
//}

@end
22 changes: 22 additions & 0 deletions Limelight/Input/CustomTapGestureRecognizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// CustomTapGestureRecognizer.h
// Moonlight
//
// Created by ZWM on 2024/5/15.
// Copyright © 2024 Moonlight Game Streaming Project. All rights reserved.
//

#ifndef CustomTapGestureRecognizer_h
#define CustomTapGestureRecognizer_h



@interface CustomTapGestureRecognizer : UIGestureRecognizer

@property (nonatomic, assign) uint8_t numberOfTouchesRequired;
@property (nonatomic, assign) double tapDownTimeThreshold;
@property (atomic, readonly) CGFloat lowestTouchPointHeight;


@end
#endif /* CustomTapGestureRecognizer_h */
57 changes: 57 additions & 0 deletions Limelight/Input/CustomTapGestureRecognizer.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// CustomTapGestureRecognizer.m
// Moonlight
//
// Created by ZWM on 2024/5/15.
// Copyright © 2024 Moonlight Game Streaming Project. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "CustomTapGestureRecognizer.h"

@implementation CustomTapGestureRecognizer

static NSTimeInterval multiFingerDownTime;
static bool multiFingerDown;
static CGFloat screenHeightInPoints;
static CGFloat lowestTouchPointYCoord = 0.0;

- (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action {
self = [super initWithTarget:target action:action];
screenHeightInPoints = CGRectGetHeight([[UIScreen mainScreen] bounds]);
return self;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// Check if the number of touches and taps meets the required criteria
if ([[event allTouches] count] == _numberOfTouchesRequired) {
multiFingerDownTime = CACurrentMediaTime();
multiFingerDown = true;

for(UITouch *touch in [event allTouches]){
if(lowestTouchPointYCoord < [touch locationInView:self.view].y) lowestTouchPointYCoord = [touch locationInView:self.view].y;
}
_lowestTouchPointHeight = screenHeightInPoints - lowestTouchPointYCoord;
self.state = UIGestureRecognizerStatePossible;
}
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// [super touchesEnded:touches withEvent:event];
if(multiFingerDown && [[event allTouches] count] == [touches count]){
multiFingerDown = false;
if((CACurrentMediaTime() - multiFingerDownTime) < _tapDownTimeThreshold / 1000){
lowestTouchPointYCoord = 0.0; //reset for next recognition
self.state = UIGestureRecognizerStateRecognized;
}
}
}

+ (CGFloat)lowestTouchPointHeight{
@synchronized (self){
return self.lowestTouchPointHeight;
}
}

@end
27 changes: 27 additions & 0 deletions Limelight/Input/NativeTouchHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// NativeTouchHandler.h
// Moonlight
//
// Created by ZWM on 2024/5/14.
// Copyright © 2024 Moonlight Game Streaming Project. All rights reserved.
//

#import "StreamView.h"

NS_ASSUME_NONNULL_BEGIN

@interface NativeTouchHandler : UIResponder

+ (NSMutableDictionary* )initializePointerIdDict;
+ (NSMutableSet* )initializePointerIdSet;
+ (void)populatePointerId:(UITouch*)event;
+ (void)removePointerId:(UITouch*)event;
+ (uint32_t) retrievePointerIdFromDict:(UITouch*)event;


-(id)initWithView:(StreamView*)view;

@end

NS_ASSUME_NONNULL_END

Loading