diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard
index eb385bf3..9923baa9 100644
--- a/Limelight/Base.lproj/iPad.storyboard
+++ b/Limelight/Base.lproj/iPad.storyboard
@@ -554,6 +554,13 @@ ICAgICAgICAgICAgICA
+
@@ -564,6 +571,17 @@ ICAgICAgICAgICAgICA
+
+
+
+
+
+
+
+
+
+
+
@@ -585,6 +603,7 @@ ICAgICAgICAgICAgICA
+
diff --git a/Limelight/Base.lproj/iPhone.storyboard b/Limelight/Base.lproj/iPhone.storyboard
index 1cc95c98..943ff049 100644
--- a/Limelight/Base.lproj/iPhone.storyboard
+++ b/Limelight/Base.lproj/iPhone.storyboard
@@ -580,6 +580,24 @@ ICAgICAgICAgICAgIA
+
+
+
+
+
+
+
+
+
+
+
+
@@ -601,6 +619,7 @@ ICAgICAgICAgICAgIA
+
diff --git a/Limelight/Database/DataManager.h b/Limelight/Database/DataManager.h
index d4708696..eeed64e2 100644
--- a/Limelight/Database/DataManager.h
+++ b/Limelight/Database/DataManager.h
@@ -44,7 +44,8 @@
statsOverlay:(BOOL)statsOverlay
allowPortrait:(BOOL)allowPortrait
resolutionSelected:(NSInteger)resolutionSelected
- externalDisplayMode:(NSInteger)externalDisplayMode;
+ externalDisplayMode:(NSInteger)externalDisplayMode
+ mouseMode:(NSInteger)mouseMode;
- (NSArray*) getHosts;
- (void) updateHost:(TemporaryHost*)host;
diff --git a/Limelight/Database/DataManager.m b/Limelight/Database/DataManager.m
index ef1de168..bc6e1168 100644
--- a/Limelight/Database/DataManager.m
+++ b/Limelight/Database/DataManager.m
@@ -83,7 +83,8 @@
statsOverlay:(BOOL)statsOverlay
allowPortrait:(BOOL)allowPortrait
resolutionSelected:(NSInteger)resolutionSelected
- externalDisplayMode:(NSInteger)externalDisplayMode {
+ externalDisplayMode:(NSInteger)externalDisplayMode
+ mouseMode:(NSInteger)mouseMode {
[_managedObjectContext performBlockAndWait:^{
Settings* settingsToSave = [self retrieveSettings];
@@ -119,6 +120,7 @@
settingsToSave.allowPortrait = allowPortrait;
settingsToSave.resolutionSelected = [NSNumber numberWithInteger:resolutionSelected];
settingsToSave.externalDisplayMode = [NSNumber numberWithInteger:externalDisplayMode];
+ settingsToSave.mouseMode = [NSNumber numberWithInteger:mouseMode];
[self saveData];
}];
}
diff --git a/Limelight/Database/TemporarySettings.h b/Limelight/Database/TemporarySettings.h
index b536d596..c01ee84d 100644
--- a/Limelight/Database/TemporarySettings.h
+++ b/Limelight/Database/TemporarySettings.h
@@ -35,6 +35,7 @@
@property (nonatomic, retain) NSString * uniqueId;
@property (nonatomic, retain) NSNumber * resolutionSelected;
@property (nonatomic, retain) NSNumber * externalDisplayMode;
+@property (nonatomic, retain) NSNumber * mouseMode;
@property (nonatomic) enum {
CODEC_PREF_AUTO,
CODEC_PREF_H264,
diff --git a/Limelight/Database/TemporarySettings.m b/Limelight/Database/TemporarySettings.m
index 837ebbc6..02f81033 100644
--- a/Limelight/Database/TemporarySettings.m
+++ b/Limelight/Database/TemporarySettings.m
@@ -101,6 +101,7 @@
self.allowPortrait = settings.allowPortrait;
self.resolutionSelected = settings.resolutionSelected;
self.externalDisplayMode = settings.externalDisplayMode;
+ self.mouseMode = settings.mouseMode;
#endif
self.uniqueId = settings.uniqueId;
diff --git a/Limelight/Input/ControllerSupport.m b/Limelight/Input/ControllerSupport.m
index e8af49d9..9ceec98f 100644
--- a/Limelight/Input/ControllerSupport.m
+++ b/Limelight/Input/ControllerSupport.m
@@ -46,6 +46,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
char _controllerNumbers;
bool _multiController;
bool _swapABXYButtons;
+ bool _captureMouse;
}
// UPDATE_BUTTON_FLAG(controller, flag, pressed)
@@ -864,20 +865,25 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
}
-(void) registerMouseCallbacks:(GCMouse*) mouse API_AVAILABLE(ios(14.0)) {
- mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput * _Nonnull mouse, float deltaX, float deltaY) {
- self->accumulatedDeltaX += deltaX / MOUSE_SPEED_DIVISOR;
- self->accumulatedDeltaY += -deltaY / MOUSE_SPEED_DIVISOR;
-
- short truncatedDeltaX = (short)self->accumulatedDeltaX;
- short truncatedDeltaY = (short)self->accumulatedDeltaY;
-
- if (truncatedDeltaX != 0 || truncatedDeltaY != 0) {
- LiSendMouseMoveEvent(truncatedDeltaX, truncatedDeltaY);
+ if (_captureMouse){
+ mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput * _Nonnull mouse, float deltaX, float deltaY) {
+ self->accumulatedDeltaX += deltaX / MOUSE_SPEED_DIVISOR;
+ self->accumulatedDeltaY += -deltaY / MOUSE_SPEED_DIVISOR;
- self->accumulatedDeltaX -= truncatedDeltaX;
- self->accumulatedDeltaY -= truncatedDeltaY;
- }
- };
+ short truncatedDeltaX = (short)self->accumulatedDeltaX;
+ short truncatedDeltaY = (short)self->accumulatedDeltaY;
+
+ if (truncatedDeltaX != 0 || truncatedDeltaY != 0) {
+ LiSendMouseMoveEvent(truncatedDeltaX, truncatedDeltaY);
+
+ self->accumulatedDeltaX -= truncatedDeltaX;
+ self->accumulatedDeltaY -= truncatedDeltaY;
+ }
+ };
+ } else {
+ mouse.mouseInput.mouseMovedHandler = nil;
+ }
+
mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
LiSendMouseButtonEvent(pressed ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_LEFT);
@@ -1120,6 +1126,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
}
}
+ _captureMouse = (streamConfig.mouseMode == 0);
if (@available(iOS 14.0, tvOS 14.0, *)) {
for (GCMouse* mouse in [GCMouse mice]) {
[self registerMouseCallbacks:mouse];
diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m
index 70a49db2..ed69488b 100644
--- a/Limelight/Input/StreamView.m
+++ b/Limelight/Input/StreamView.m
@@ -48,6 +48,8 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
double accumulatedMouseDeltaX;
double accumulatedMouseDeltaY;
+ int mouseMode;
+
UIResponder* touchHandler;
id interactionDelegate;
@@ -76,6 +78,8 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
settings = [[[DataManager alloc] init] getSettings];
+ mouseMode = streamConfig.mouseMode;
+
keysDown = [[NSMutableSet alloc] init];
keyInputField = [[KeyboardInputField alloc] initWithFrame:CGRectZero];
[keyInputField setKeyboardType:UIKeyboardTypeDefault];
@@ -869,7 +873,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
regionForRequest:(UIPointerRegionRequest *)request
defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)) {
if (@available(iOS 14.0, *)) {
- if ([GCMouse current] != nil) {
+ if ([GCMouse current] != nil && mouseMode == 0) {
// We'll handle this with GCMouse. Do nothing here.
return nil;
}
@@ -897,8 +901,11 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
}
- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)) {
- // Always hide the mouse cursor over our stream view
- return [UIPointerStyle hiddenPointerStyle];
+ if(mouseMode != 2){
+ return [UIPointerStyle hiddenPointerStyle];
+ }else{
+ return nil;
+ }
}
- (void)mouseWheelMovedContinuous:(UIPanGestureRecognizer *)gesture {
diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents
index bc7f12b1..7cbb880a 100644
--- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents
+++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents
@@ -1,5 +1,5 @@
-
+
@@ -33,6 +33,7 @@
+
diff --git a/Limelight/Stream/StreamConfiguration.h b/Limelight/Stream/StreamConfiguration.h
index 3073ea62..ab1aa33d 100644
--- a/Limelight/Stream/StreamConfiguration.h
+++ b/Limelight/Stream/StreamConfiguration.h
@@ -32,5 +32,6 @@
@property BOOL multiController;
@property BOOL useFramePacing;
@property NSData* serverCert;
+@property int mouseMode;
@end
diff --git a/Limelight/ViewControllers/CustomEdgeSlideGestureRecognizer.m b/Limelight/ViewControllers/CustomEdgeSlideGestureRecognizer.m
index 4703ee4f..0b202d93 100644
--- a/Limelight/ViewControllers/CustomEdgeSlideGestureRecognizer.m
+++ b/Limelight/ViewControllers/CustomEdgeSlideGestureRecognizer.m
@@ -18,7 +18,7 @@ static CGFloat screenWidthInPoints;
- (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action {
self = [super initWithTarget:target action:action];
- screenWidthInPoints = CGRectGetWidth([[UIScreen mainScreen] bounds]); // Get the screen's bounds (in points)
+ screenWidthInPoints = CGRectGetWidth([UIApplication.sharedApplication.windows.firstObject.screen bounds]); // Get the screen's bounds (in points)
_immediateTriggering = false;
_EDGE_TOLERANCE = 15.0f;
return self;
diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m
index fc03be11..2331b8ea 100644
--- a/Limelight/ViewControllers/MainFrameViewController.m
+++ b/Limelight/ViewControllers/MainFrameViewController.m
@@ -670,6 +670,7 @@ static NSMutableSet* hostList;
// multiController must be set before calling getConnectedGamepadMask
_streamConfig.multiController = streamSettings.multiController;
_streamConfig.gamepadMask = [ControllerSupport getConnectedGamepadMask:_streamConfig];
+ _streamConfig.mouseMode = streamSettings.mouseMode.intValue;
// Probe for supported channel configurations
int physicalOutputChannels = (int)[AVAudioSession sharedInstance].maximumOutputNumberOfChannels;
diff --git a/Limelight/ViewControllers/SettingsViewController.h b/Limelight/ViewControllers/SettingsViewController.h
index 360d101e..4e1bc240 100644
--- a/Limelight/ViewControllers/SettingsViewController.h
+++ b/Limelight/ViewControllers/SettingsViewController.h
@@ -58,6 +58,7 @@
@property (nonatomic, strong) MainFrameViewController *mainFrameViewController;
@property (strong, nonatomic) IBOutlet UISegmentedControl *externalDisplayModeSelector;
+@property (strong, nonatomic) IBOutlet UISegmentedControl *mouseModeSelector;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m
index 6672229d..3ba5545b 100644
--- a/Limelight/ViewControllers/SettingsViewController.m
+++ b/Limelight/ViewControllers/SettingsViewController.m
@@ -560,6 +560,7 @@ BOOL isCustomResolution(CGSize res) {
}
[self.externalDisplayModeSelector setSelectedSegmentIndex:currentSettings.externalDisplayMode.integerValue];
+ [self.mouseModeSelector setSelectedSegmentIndex:currentSettings.mouseMode.integerValue];
}
- (void)slideToSettingsScreenEdgeChanged{
@@ -1067,6 +1068,7 @@ BOOL isCustomResolution(CGSize res) {
BOOL allowPortrait = [self.allowPortraitSelector selectedSegmentIndex] == 1;
NSInteger resolutionSelected = [self.resolutionSelector selectedSegmentIndex];
NSInteger externalDisplayMode = [self.externalDisplayModeSelector selectedSegmentIndex];
+ NSInteger mouseMode = [self.mouseModeSelector selectedSegmentIndex];
[dataMan saveSettingsWithBitrate:_bitrate
framerate:framerate
height:height
@@ -1098,7 +1100,8 @@ BOOL isCustomResolution(CGSize res) {
statsOverlay:statsOverlay
allowPortrait:allowPortrait
resolutionSelected:resolutionSelected
- externalDisplayMode:externalDisplayMode];
+ externalDisplayMode:externalDisplayMode
+ mouseMode:mouseMode];
}
- (void)didReceiveMemoryWarning {
diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m
index 07ff44ba..2ec28416 100644
--- a/Limelight/ViewControllers/StreamFrameViewController.m
+++ b/Limelight/ViewControllers/StreamFrameViewController.m
@@ -167,6 +167,7 @@
andConfig:(StreamConfiguration*)_streamConfig]; //reload OSC here.
[self->_streamView reloadOnScreenButtonViews]; //reload keyboard buttons here. the keyboard button view will be added to the streamframe view instead streamview, the highest layer, which saves a lot of reengineering
[self reloadAirPlayConfig];
+ [self mousePresenceChanged];
//reconfig statsOverlay
self->_statsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f
@@ -966,7 +967,7 @@
// Pointer lock breaks the UIKit mouse APIs, which is a problem because
// GCMouse is horribly broken on iOS 14.0 for certain mice. Only lock
// the cursor if there is a GCMouse present.
- return [GCMouse mice].count > 0;
+ return ([GCMouse mice].count > 0) && [_settings mouseMode].intValue == 0;
}
#endif
diff --git a/Limelight/mul.lproj/iPad.xcstrings b/Limelight/mul.lproj/iPad.xcstrings
index 2b332554..9d5fead5 100644
--- a/Limelight/mul.lproj/iPad.xcstrings
+++ b/Limelight/mul.lproj/iPad.xcstrings
@@ -91,6 +91,96 @@
}
}
},
+ "4FU-iP-c6T.segmentTitles[0]" : {
+ "comment" : "Class = \"UISegmentedControl\"; 4FU-iP-c6T.segmentTitles[0] = \"Capture\"; ObjectID = \"4FU-iP-c6T\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Capture"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捕获"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捕获"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捕获"
+ }
+ }
+ }
+ },
+ "4FU-iP-c6T.segmentTitles[1]" : {
+ "comment" : "Class = \"UISegmentedControl\"; 4FU-iP-c6T.segmentTitles[1] = \"Hidden\"; ObjectID = \"4FU-iP-c6T\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Hidden"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "隐藏"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "隐藏"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "隐藏"
+ }
+ }
+ }
+ },
+ "4FU-iP-c6T.segmentTitles[2]" : {
+ "comment" : "Class = \"UISegmentedControl\"; 4FU-iP-c6T.segmentTitles[2] = \"Visible\"; ObjectID = \"4FU-iP-c6T\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Visible"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "可见"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "可见"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "可见"
+ }
+ }
+ }
+ },
"4Qy-hB-oa5.text" : {
"comment" : "Class = \"UILabel\"; text = \"External Display Mode\"; ObjectID = \"4Qy-hB-oa5\";",
"extractionState" : "extracted_with_value",
@@ -2167,6 +2257,36 @@
}
}
},
+ "tAd-bm-2IO.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Mouse Mode\"; ObjectID = \"tAd-bm-2IO\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Mouse Mode"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "鼠标模式"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "鼠标模式"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "鼠标模式"
+ }
+ }
+ }
+ },
"uSS-ev-IFe.configuration.title" : {
"comment" : "Class = \"UIButton\"; configuration.title = \"Go Back to Stream View\"; ObjectID = \"uSS-ev-IFe\";",
"extractionState" : "extracted_with_value",
diff --git a/Limelight/mul.lproj/iPhone.xcstrings b/Limelight/mul.lproj/iPhone.xcstrings
index 26e95e57..2af3742b 100644
--- a/Limelight/mul.lproj/iPhone.xcstrings
+++ b/Limelight/mul.lproj/iPhone.xcstrings
@@ -961,6 +961,96 @@
}
}
},
+ "F96-Um-Q6t.segmentTitles[0]" : {
+ "comment" : "Class = \"UISegmentedControl\"; F96-Um-Q6t.segmentTitles[0] = \"Capture\"; ObjectID = \"F96-Um-Q6t\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Capture"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捕获"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捕获"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捕获"
+ }
+ }
+ }
+ },
+ "F96-Um-Q6t.segmentTitles[1]" : {
+ "comment" : "Class = \"UISegmentedControl\"; F96-Um-Q6t.segmentTitles[1] = \"Hidden\"; ObjectID = \"F96-Um-Q6t\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Hidden"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "隐藏"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "隐藏"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "隐藏"
+ }
+ }
+ }
+ },
+ "F96-Um-Q6t.segmentTitles[2]" : {
+ "comment" : "Class = \"UISegmentedControl\"; F96-Um-Q6t.segmentTitles[2] = \"Visible\"; ObjectID = \"F96-Um-Q6t\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Visible"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "可见"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "可见"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "可见"
+ }
+ }
+ }
+ },
"FqF-bM-afQ.configuration.title" : {
"comment" : "Class = \"UIButton\"; configuration.title = \"Go Back to Stream View\"; ObjectID = \"FqF-bM-afQ\";",
"extractionState" : "extracted_with_value",
@@ -2029,6 +2119,36 @@
}
}
},
+ "VGn-Oc-mKc.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Mouse Mode\"; ObjectID = \"VGn-Oc-mKc\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Mouse Mode"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "鼠标模式"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "鼠标模式"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "鼠标模式"
+ }
+ }
+ }
+ },
"VlN-ZW-1gm.text" : {
"comment" : "Class = \"UILabel\"; text = \"Touch Pointer Velocity: Scaled on 0% of Right Screen \"; ObjectID = \"VlN-ZW-1gm\";",
"extractionState" : "extracted_with_value",