From 0fef5a389da3cbd2ad39dd4dc9c549d0a27e0e8f Mon Sep 17 00:00:00 2001 From: Acaki Date: Wed, 9 Jul 2025 17:39:55 +0800 Subject: [PATCH] fix: auto gyro mode not working for controllers without gyro --- VoidLink/Input/ControllerSupport.m | 130 +++++++++++++---------------- 1 file changed, 56 insertions(+), 74 deletions(-) diff --git a/VoidLink/Input/ControllerSupport.m b/VoidLink/Input/ControllerSupport.m index 4dc49449..6bf4d96d 100644 --- a/VoidLink/Input/ControllerSupport.m +++ b/VoidLink/Input/ControllerSupport.m @@ -768,6 +768,13 @@ 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 { @@ -1172,9 +1179,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 @@ -1201,7 +1210,6 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self initializeControllerHaptics:voidController]; } - -(VoidController* )assignController:(GCController*)controller { NSLog(@"run assignController"); @@ -1355,46 +1363,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)delegate @@ -1572,52 +1551,19 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; return false; } --(void)connectionEstablished{ +-(void)connectionEstablished { if (_oscEnabled) { - [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)), + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - if(self->_oscEnabled){ - [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(), ^{ - // Stop all existing timers to ensure a clean state. - [self stopTimerForAllControllers]; - - // Read the user's final setting from the stream configuration. - self->_gyroMode = self->_streamConfig.gyroMode; - - switch (self->_gyroMode) { - case AlwaysController: - for (VoidController* voidController in self->_voidControllers.allValues) { - [self updateTimerStateForController:voidController]; - } - break; - case GyroModeAuto: - if ([self externalControllersHaveGyro]) { - for (VoidController* voidController in self->_voidControllers.allValues) { - [self updateTimerStateForController:voidController]; - } - } else { - [self updateTimerStateForController:self->_oscController]; - } - break; - - case AlwaysDevice: - [self updateTimerStateForController:self->_oscController]; - break; - - case GyroModeOff: - break; - } - }); + [self applyGyroModeSetting]; }); } @@ -1636,6 +1582,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];