Merge branch 'gyroImprovements' into Integration

- disable gyro mode selector when it's unable to perform in-stream hot switch
- make osc enabled when gyroMode is not off
- make it unable to set oscEnabled to false in streaming, to ensure gyro hot switch keeps working.
This commit is contained in:
TrueZhuanjia
2025-07-10 22:19:56 +08:00
5 changed files with 100 additions and 81 deletions
+2
View File
@@ -21,6 +21,8 @@
@interface ControllerSupport : NSObject
@property (readonly) bool shallDisableGyroHotSwitch;
-(id) initWithConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate;
-(void) connectionEstablished;
+90 -79
View File
@@ -25,6 +25,13 @@
static const double MOUSE_SPEED_DIVISOR = 1.25;
@interface ControllerSupport()
@property (assign,nonatomic) bool shallDisableGyroHotSwitch;
@end
@implementation ControllerSupport {
id _controllerConnectObserver;
id _controllerDisconnectObserver;
@@ -768,17 +775,31 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
if (controller.battery) {
capabilities |= LI_CCAP_BATTERY_STATE;
}
bool controllerLacksGyro = (capabilities & LI_CCAP_GYRO) == 0;
if ((_gyroMode == AlwaysDevice) || (_gyroMode == GyroModeAuto && controllerLacksGyro))
{
type = LI_CTYPE_PS;
capabilities |= LI_CCAP_GYRO | LI_CCAP_ACCEL;
}
}
}
else {
// This is a virtual controller corresponding to our OSC
if (_streamConfig.gyroMode != GyroModeOff) {
type = LI_CTYPE_PS;
capabilities = LI_CCAP_GYRO | LI_CCAP_ACCEL;
}
else {
// This is a virtual controller corresponding to our OSC
// TODO: Support various layouts and button labels on the OSC
type = LI_CTYPE_XBOX;
capabilities = 0;
supportedButtonFlags =
PLAY_FLAG | BACK_FLAG | UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG |
LB_FLAG | RB_FLAG | LS_CLK_FLAG | RS_CLK_FLAG | A_FLAG | B_FLAG | X_FLAG | Y_FLAG;
}
// Set the standard supported buttons for the virtual controller.
supportedButtonFlags =
PLAY_FLAG | BACK_FLAG | UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG |
LB_FLAG | RB_FLAG | LS_CLK_FLAG | RS_CLK_FLAG | A_FLAG | B_FLAG | X_FLAG | Y_FLAG;
}
// Report the new controller to the host
@@ -1165,9 +1186,11 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
voidController.reportRateHz = 120;
}
if (@available(iOS 14.0, *)) {
if(voidController.gamepad.motion.hasRotationRate) [voidController.motionTypes addObject:@(LI_MOTION_TYPE_GYRO)];
voidController.hasGyroscope = YES;
voidController.reportRateHz = 120;
if(voidController.gamepad.motion.hasRotationRate) {
[voidController.motionTypes addObject:@(LI_MOTION_TYPE_GYRO)];
voidController.hasGyroscope = YES;
voidController.reportRateHz = 120;
}
}
// If this is player 0, it shares state with the OSC
@@ -1194,7 +1217,6 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[self initializeControllerHaptics:voidController];
}
-(VoidController* )assignController:(GCController*)controller {
NSLog(@"run assignController");
@@ -1318,9 +1340,8 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
_oscController.playerIndex = 0;
DataManager* dataMan = [[DataManager alloc] init];
//_oscEnabled = (OnScreenControlsLevel)[[dataMan getSettings].onscreenControls integerValue] != OnScreenControlsLevelOff;
TemporarySettings* currentSettings = [dataMan getSettings];
_oscEnabled = true;
_oscEnabled = _oscEnabled || (OnScreenControlsLevel)[currentSettings.onscreenControls integerValue] != OnScreenControlsLevelOff || streamConfig.gyroMode != GyroModeOff;
_gyroSensitivity = currentSettings.gyroSensitivity.floatValue;
}
@@ -1349,46 +1370,17 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
Log(LOG_I, @"Number of supported controllers connected: %d", [ControllerSupport getGamepadCount]);
Log(LOG_I, @"Multi-controller: %d", _multiController);
if (@available(iOS 14.0, tvOS 14.0, *)) {
switch(_gyroMode){
case GyroModeOff:
[self stopTimerForAllControllers];
break;
case GyroModeAuto:
[self stopTimerForAllControllers];
[_voidControllers removeAllObjects];
[self assignControllers];
//if(_voidControllers.count == 0) [self assignControllers];
if(_voidControllers.count == 0 || ![self externalControllersHaveGyro]) [self updateTimerStateForController:_oscController];
else for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller];
// to be filled
break;
case AlwaysDevice:
//[self stopTimerForController:_oscController];
for(VoidController* controller in _voidControllers.allValues){
[self stopTimerForController:controller];
}
[self updateTimerStateForController:_oscController];
break;
case AlwaysController:
[self stopTimerForAllControllers];
for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller];
break;
}
}
[self applyGyroModeSetting];
[self assignControllers];
NSLog(@"controllerNumbers: %d", _controllerNumbers);
for(VoidController* controller in _voidControllers.allValues){
NSLog(@"controller obj in dict: %@", controller);
}
[self updateFinished:_oscController];
}
-(id)initWithConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate
@@ -1403,7 +1395,6 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
_activeGCControllers = [[NSMutableSet alloc] init];
_controllerNumbers = 0;
_captureMouse = (streamConfig.localMousePointerMode == 0);
if (@available(iOS 14.0, tvOS 14.0, *)) {
for (GCMouse* mouse in [GCMouse mice]) {
@@ -1553,8 +1544,8 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[self assignControllers];
//[self updateConfig:streamConfig delegate:delegate];
_shallDisableGyroHotSwitch = streamConfig.gyroMode == GyroModeOff && _voidControllers.allValues.count == 0;
NSLog(@"shallDisableGyroHotSwitch %d", _shallDisableGyroHotSwitch);
return self;
}
@@ -1566,40 +1557,24 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
return false;
}
-(void)connectionEstablished{
[self updateTimerStateForController:self->_oscController];
[self setButtonFlag:self->_oscController flags:A_FLAG];
[self updateFinished:self->_oscController];
[self clearButtonFlag:self->_oscController flags:A_FLAG];
[self updateFinished:self->_oscController];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
-(void)connectionEstablished {
for (VoidController* voidController in _voidControllers.allValues) {
[self updateFinished:voidController];
}
if (_oscEnabled) {
[self setButtonFlag:self->_oscController flags:A_FLAG];
[self updateFinished:self->_oscController];
[self clearButtonFlag:self->_oscController flags:A_FLAG];
[self updateFinished:self->_oscController];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self updateTimerStateForController:self->_oscController];
self->_gyroMode = self->_streamConfig.gyroMode;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
self->_gyroMode = self->_streamConfig.gyroMode;
switch (self->_gyroMode) {
case AlwaysController:
[self stopTimerForAllControllers];
for(VoidController* voidController in self->_voidControllers.allValues) [self updateTimerStateForController:voidController];
break;
case GyroModeAuto:
if(self->_voidControllers.count == 0) [self assignControllers];
if(self->_voidControllers.count == 0 || ![self externalControllersHaveGyro]) nil;
else{
[self stopTimerForAllControllers];
for(VoidController* voidController in self->_voidControllers.allValues) [self updateTimerStateForController:voidController];
}
break;
case GyroModeOff:
[self stopTimerForAllControllers];
break;
default:
break;
}
});
[self applyGyroModeSetting];
});
}
@@ -1618,6 +1593,42 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
}
}
- (void)applyGyroModeSetting {
// Stop all timers to ensure a clean slate before applying the new setting.
[self stopTimerForAllControllers];
switch(_gyroMode) {
case AlwaysController:
// Activate timers only for physical controllers.
for (VoidController* voidController in _voidControllers.allValues) {
[self updateTimerStateForController:voidController];
}
break;
case GyroModeAuto:
// Prefer physical controller gyros if they exist.
if ([self externalControllersHaveGyro]) {
for (VoidController* voidController in _voidControllers.allValues) {
[self updateTimerStateForController:voidController];
}
} else {
// Otherwise, fall back to the device gyro.
[self updateTimerStateForController:self->_oscController];
}
break;
case AlwaysDevice:
// Always start the device gyro in this mode.
[self updateTimerStateForController:self->_oscController];
break;
case GyroModeOff:
// Do nothing, all timers are already stopped.
break;
}
}
-(void) cleanup
{
[[NSNotificationCenter defaultCenter] removeObserver:_controllerConnectObserver];
@@ -1135,10 +1135,12 @@ static NSMutableSet* hostList;
[settingsViewController.codecSelector setEnabled:!_settingsExpandedInStreamView];
[settingsViewController.yuv444Switch setEnabled:!_settingsExpandedInStreamView];
[settingsViewController.hdrSwitch setEnabled:!_settingsExpandedInStreamView];
[settingsViewController.gyroModeSelector setEnabled:!_settingsExpandedInStreamView || ![streamFrameViewController shallDisableGyroHotSwitch]];
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.framepacingStack];
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.citrixX1MouseStack];
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.externalDisplayModeStack];
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.audioConfigStack];
}
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position {
@@ -32,5 +32,6 @@
-(void)updatePreferredDisplayMode:(BOOL)streamActive;
-(void)reConfigStreamViewRealtime;
- (void)setUserInteractionEnabledForStreamView:(bool)enabled;
- (bool)shallDisableGyroHotSwitch;
@end
@@ -670,6 +670,10 @@
}
}
- (bool)shallDisableGyroHotSwitch{
return _controllerSupport.shallDisableGyroHotSwitch;
}
- (BOOL) isAirPlaying{
return _extWindow != nil && _extWindow.hidden == NO;
}
@@ -1156,8 +1160,7 @@
}
- (BOOL)prefersHomeIndicatorAutoHidden {
if ([_controllerSupport getConnectedGamepadCount] > 0 &&
[_streamView getCurrentOscState] == OnScreenControlsLevelOff &&
if ( [_streamView getCurrentOscState] == OnScreenControlsLevelOff &&
_userIsInteracting == NO) {
// Autohide the home bar when a gamepad is connected
// and the on-screen controls are disabled. We can't