implementation of auto gyro mode

This commit is contained in:
TrueZhuanjia committed 2025-07-06 22:36:18 +08:00
1 parent 578ad81b8a
commit 0f6f105ec1
3 files changed
+146 -128

No files matched your search

+1 -1
View File
@@ -53,6 +53,6 @@
-(NSUInteger) getConnectedGamepadCount; -(NSUInteger) getConnectedGamepadCount;
-(void)updateConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate; -(void)updateControllerSupport:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate;
@end @end
+143 -125
View File
@@ -67,17 +67,17 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
-(void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor -(void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor
{ {
VoidController* controller = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; VoidController* voidController = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]];
if (controller == nil && controllerNumber == 0 && _oscEnabled) { if (voidController == nil && controllerNumber == 0 && _oscEnabled) {
// TODO: Rumble emulation for OSC // TODO: Rumble emulation for OSC
} }
if (controller == nil) { if (voidController == nil) {
// No connected controller for this player // No connected controller for this player
return; return;
} }
[controller.lowFreqMotor setMotorAmplitude:lowFreqMotor]; [voidController.lowFreqMotor setMotorAmplitude:lowFreqMotor];
[controller.highFreqMotor setMotorAmplitude:highFreqMotor]; [voidController.highFreqMotor setMotorAmplitude:highFreqMotor];
} }
-(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger -(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger
@@ -110,102 +110,100 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
uint8_t motionType = motionTypeObj.intValue; uint8_t motionType = motionTypeObj.intValue;
NSLog(@"controller obj controllerNumber %d", voidController.controllerNumber); NSLog(@"controller obj controllerNumber %d", voidController.controllerNumber);
if(_gyroMode != AlwaysController || voidController == _oscController){
NSLog(@"device gyro mode, motionType: %d", motionType);
#if !TARGET_OS_TV //tvOS has no device motion #if !TARGET_OS_TV //tvOS has no device motion
if(voidController == _oscController){ if(voidController == _oscController){
//Player has no controller *or* no motion for controller 1 *or* wants to override controller 1 motion with device motion //Player has no controller *or* no motion for controller 1 *or* wants to override controller 1 motion with device motion
if(!voidController.motionManager) { if(!voidController.motionManager) {
voidController.motionManager = [[CMMotionManager alloc] init]; voidController.motionManager = [[CMMotionManager alloc] init];
} }
NSLog(@"device gyro mode 666, motionType: %d", motionType); NSLog(@"device gyro mode 666, motionType: %d", motionType);
switch (motionType) { switch (motionType) {
case LI_MOTION_TYPE_ACCEL: case LI_MOTION_TYPE_ACCEL:
[voidController.accelTimer invalidate]; [voidController.accelTimer invalidate];
voidController.accelTimer = nil; voidController.accelTimer = nil;
// Reset the last motion sample // Reset the last motion sample
CMAcceleration emptyDeviceAccelSample = {}; CMAcceleration emptyDeviceAccelSample = {};
voidController.lastDeviceAccelSample = emptyDeviceAccelSample; voidController.lastDeviceAccelSample = emptyDeviceAccelSample;
{dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"setup device built-in gyro accelTimer");
voidController.hasAccelerometer = YES;
voidController.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) {
// Don't send duplicate samples
CMAcceleration lastDeviceAccelSample = voidController.lastDeviceAccelSample;
CMAcceleration deviceAccelSample = voidController.motionManager.deviceMotion.userAcceleration;
//userAcceleration does not contain gravity, add gravity to x, y and z values:
deviceAccelSample.x += voidController.motionManager.deviceMotion.gravity.x * self->_gyroSensitivity;
deviceAccelSample.y += voidController.motionManager.deviceMotion.gravity.y * self->_gyroSensitivity;
deviceAccelSample.z += voidController.motionManager.deviceMotion.gravity.z * self->_gyroSensitivity;
{dispatch_async(dispatch_get_main_queue(), ^{ if (memcmp(&deviceAccelSample, &lastDeviceAccelSample, sizeof(deviceAccelSample)) == 0) {
NSLog(@"setup device built-in gyro accelTimer"); return;
voidController.hasAccelerometer = YES; }
voidController.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) { voidController.lastDeviceAccelSample = deviceAccelSample;
// Don't send duplicate samples
CMAcceleration lastDeviceAccelSample = voidController.lastDeviceAccelSample; // Convert g to m/s^2
CMAcceleration deviceAccelSample = voidController.motionManager.deviceMotion.userAcceleration; if(UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation == 4){ //check for landscape left or landscape right
//userAcceleration does not contain gravity, add gravity to x, y and z values: LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
deviceAccelSample.x += voidController.motionManager.deviceMotion.gravity.x * self->_gyroSensitivity; LI_MOTION_TYPE_ACCEL,
deviceAccelSample.y += voidController.motionManager.deviceMotion.gravity.y * self->_gyroSensitivity; deviceAccelSample.y * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.z += voidController.motionManager.deviceMotion.gravity.z * self->_gyroSensitivity; deviceAccelSample.z * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.x * -9.80665f * self->_gyroSensitivity);
if (memcmp(&deviceAccelSample, &lastDeviceAccelSample, sizeof(deviceAccelSample)) == 0) { }
else{
LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_ACCEL,
deviceAccelSample.y * +9.80665f * self->_gyroSensitivity,
deviceAccelSample.z * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.x * +9.80665f * self->_gyroSensitivity);
}
}];
});}
break;
case LI_MOTION_TYPE_GYRO:
[voidController.gyroTimer invalidate];
voidController.gyroTimer = nil;
// Reset the last motion sample
CMRotationRate emptyDeviceGyroSample = {};
voidController.lastDeviceGyroSample = emptyDeviceGyroSample;
[voidController.motionManager startDeviceMotionUpdates];
NSLog(@"setup device built-in gyro gyroTimer");
voidController.hasGyroscope = YES;
voidController.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) {
// Don't send duplicate samples
CMRotationRate lastDeviceGyroSample = voidController.lastDeviceGyroSample;
CMRotationRate deviceGyroSample = voidController.motionManager.deviceMotion.rotationRate;
if (memcmp(&deviceGyroSample, &lastDeviceGyroSample, sizeof(deviceGyroSample)) == 0) {
return; return;
} }
voidController.lastDeviceAccelSample = deviceAccelSample; voidController.lastDeviceGyroSample = deviceGyroSample;
// Convert g to m/s^2
if(UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation == 4){ //check for landscape left or landscape right
LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_ACCEL,
deviceAccelSample.y * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.z * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.x * -9.80665f * self->_gyroSensitivity);
}
else{
LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_ACCEL,
deviceAccelSample.y * +9.80665f * self->_gyroSensitivity,
deviceAccelSample.z * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.x * +9.80665f * self->_gyroSensitivity);
}
}];
});}
break;
case LI_MOTION_TYPE_GYRO:
[voidController.gyroTimer invalidate];
voidController.gyroTimer = nil;
// Reset the last motion sample // Convert rad/s to deg/s
CMRotationRate emptyDeviceGyroSample = {}; NSLog(@"sending built-in gyro data, accelSample data 00: %f, playerIndex: %d",deviceGyroSample.x, voidController.playerIndex);
voidController.lastDeviceGyroSample = emptyDeviceGyroSample; if(UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation == 4){//check for landscape left or landscape right
[voidController.motionManager startDeviceMotionUpdates]; LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_GYRO,
NSLog(@"setup device built-in gyro gyroTimer"); deviceGyroSample.y * 57.2957795f * self->_gyroSensitivity,
voidController.hasGyroscope = YES; deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity,
voidController.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) { deviceGyroSample.x * 57.2957795f * self->_gyroSensitivity);
}
// Don't send duplicate samples else{
CMRotationRate lastDeviceGyroSample = voidController.lastDeviceGyroSample; LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
CMRotationRate deviceGyroSample = voidController.motionManager.deviceMotion.rotationRate; LI_MOTION_TYPE_GYRO,
if (memcmp(&deviceGyroSample, &lastDeviceGyroSample, sizeof(deviceGyroSample)) == 0) { deviceGyroSample.y * -57.2957795f * self->_gyroSensitivity,
return; deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity,
} deviceGyroSample.x * -57.2957795f * self->_gyroSensitivity);
voidController.lastDeviceGyroSample = deviceGyroSample; }
}];
// Convert rad/s to deg/s break;
NSLog(@"sending built-in gyro data, accelSample data 00: %f, playerIndex: %d",deviceGyroSample.x, voidController.playerIndex);
if(UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation == 4){//check for landscape left or landscape right
LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_GYRO,
deviceGyroSample.y * 57.2957795f * self->_gyroSensitivity,
deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity,
deviceGyroSample.x * 57.2957795f * self->_gyroSensitivity);
}
else{
LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_GYRO,
deviceGyroSample.y * -57.2957795f * self->_gyroSensitivity,
deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity,
deviceGyroSample.x * -57.2957795f * self->_gyroSensitivity);
}
}];
break;
}
} }
} }
#endif #endif
else{ else{
NSLog(@"controller obj timer update: controller timer "); NSLog(@"controller obj timer update: controller timer ");
@@ -879,18 +877,18 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
if (useLegacyPausedHandler) { if (useLegacyPausedHandler) {
controller.controllerPausedHandler = ^(GCController *controller) { controller.controllerPausedHandler = ^(GCController *controller) {
VoidController* limeController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; VoidController* voidController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
// Get off the main thread // Get off the main thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self setButtonFlag:limeController flags:PLAY_FLAG]; [self setButtonFlag:voidController flags:PLAY_FLAG];
[self updateFinished:limeController]; [self updateFinished:voidController];
// Pause for 100 ms // Pause for 100 ms
usleep(100 * 1000); usleep(100 * 1000);
[self clearButtonFlag:limeController flags:PLAY_FLAG]; [self clearButtonFlag:voidController flags:PLAY_FLAG];
[self updateFinished:limeController]; [self updateFinished:voidController];
}); });
}; };
} }
@@ -1348,7 +1346,12 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
_gyroSensitivity = currentSettings.gyroSensitivity.floatValue; _gyroSensitivity = currentSettings.gyroSensitivity.floatValue;
} }
- (void)updateConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate { - (void)stopTimerForAllControllers{
[self stopTimerForController:_oscController];
for(VoidController* controller in _voidControllers.allValues) [self stopTimerForController:controller];
}
- (void)updateControllerSupport:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate {
NSLog(@"update config call"); NSLog(@"update config call");
_gyroMode = streamConfig.gyroMode; _gyroMode = streamConfig.gyroMode;
@@ -1362,12 +1365,13 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
if (@available(iOS 14.0, tvOS 14.0, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
switch(_gyroMode){ switch(_gyroMode){
case GyroModeOff: case GyroModeOff:
[self updateTimerStateForController:_oscController]; [self stopTimerForAllControllers];
for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller];
break; break;
case GyroModeAuto: case GyroModeAuto:
[self stopTimerForController:_oscController]; [self stopTimerForAllControllers];
for(VoidController* controller in _voidControllers.allValues) [self stopTimerForController:controller]; [_voidControllers removeAllObjects];
[self assignControllers];
//if(_voidControllers.count == 0) [self assignControllers];
if(_voidControllers.count == 0) [self updateTimerStateForController:_oscController]; if(_voidControllers.count == 0) [self updateTimerStateForController:_oscController];
else for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller]; else for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller];
// to be filled // to be filled
@@ -1375,14 +1379,12 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
case AlwaysDevice: case AlwaysDevice:
//[self stopTimerForController:_oscController]; //[self stopTimerForController:_oscController];
for(VoidController* controller in _voidControllers.allValues){ for(VoidController* controller in _voidControllers.allValues){
NSLog(@"stop external controller timer %@", controller);
[self stopTimerForController:controller]; [self stopTimerForController:controller];
} }
[self updateTimerStateForController:_oscController]; [self updateTimerStateForController:_oscController];
break; break;
case AlwaysController: case AlwaysController:
[self stopTimerForController:_oscController]; [self stopTimerForAllControllers];
for(VoidController* controller in _voidControllers.allValues) [self stopTimerForController:controller];
for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller]; for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller];
break; break;
} }
@@ -1439,16 +1441,20 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
} }
//[self->_activeGCControllers addObject:controller]; //[self->_activeGCControllers addObject:controller];
VoidController* limeController = [self assignController:controller]; VoidController* voidController = [self assignController:controller];
if (limeController) { if (voidController) {
// Register callbacks on the new controller // Register callbacks on the new controller
[self registerControllerCallbacks:controller]; [self registerControllerCallbacks:controller];
// Report the controller arrival to the host if we're connected // Report the controller arrival to the host if we're connected
[self reportControllerArrival:limeController]; [self reportControllerArrival:voidController];
// Re-evaluate the on-screen control mode // Re-evaluate the on-screen control mode
//[self updateAutoOnScreenControlMode]; //[self updateAutoOnScreenControlMode];
if(self->_gyroMode == GyroModeAuto || self->_gyroMode == AlwaysController){
[self stopTimerForController:self->_oscController];
[self updateTimerStateForController:voidController];
}
// Notify the delegate // Notify the delegate
[self->_delegate gamepadPresenceChanged]; [self->_delegate gamepadPresenceChanged];
@@ -1475,6 +1481,8 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
VoidController* voidController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; VoidController* voidController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
if (voidController) { if (voidController) {
[self stopTimerForController:voidController];
// Stop haptics on this controller // Stop haptics on this controller
[self cleanupControllerHaptics:voidController]; [self cleanupControllerHaptics:voidController];
@@ -1493,7 +1501,11 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[self updateFinished:voidController]; [self updateFinished:voidController];
// Re-evaluate the on-screen control mode // Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode]; //[self updateAutoOnScreenControlMode];
[self->_voidControllers removeObjectForKey:@(controller.playerIndex)];
if(self->_voidControllers.allValues.count == 0 && self->_gyroMode == GyroModeAuto) [self updateTimerStateForController:self->_oscController];
// Notify the delegate // Notify the delegate
[self->_delegate gamepadPresenceChanged]; [self->_delegate gamepadPresenceChanged];
@@ -1552,9 +1564,9 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[self updateCommonConfig:streamConfig]; [self updateCommonConfig:streamConfig];
for(VoidController* controller in _voidControllers.allValues){ for(VoidController* voidController in _voidControllers.allValues){
NSLog(@"stop external controller timer %@", controller); NSLog(@"stop external controller timer %@", voidController);
[self stopTimerForController:controller]; [self stopTimerForController:voidController];
} }
[self updateTimerStateForController:_oscController]; [self updateTimerStateForController:_oscController];
@@ -1581,26 +1593,32 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
dispatch_get_main_queue(), ^{ dispatch_get_main_queue(), ^{
self->_gyroMode = self->_streamConfig.gyroMode; self->_gyroMode = self->_streamConfig.gyroMode;
if(self->_gyroMode == AlwaysController){ if(self->_gyroMode == AlwaysController){
[self stopTimerForController:self->_oscController]; [self stopTimerForAllControllers];
for(VoidController* voidController in self->_voidControllers.allValues) [self stopTimerForController:voidController];
for(VoidController* voidController in self->_voidControllers.allValues) [self updateTimerStateForController:voidController]; for(VoidController* voidController in self->_voidControllers.allValues) [self updateTimerStateForController:voidController];
//for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller]; }
if(self->_gyroMode == GyroModeAuto){
if(self->_voidControllers.count == 0) [self assignControllers];
if(self->_voidControllers.count == 0) nil;
else{
[self stopTimerForAllControllers];
for(VoidController* voidController in self->_voidControllers.allValues) [self updateTimerStateForController:voidController];
}
} }
}); });
}); });
} }
-(void)stopTimerForController:(VoidController* )controller{ -(void)stopTimerForController:(VoidController* )voidController{
if (@available(iOS 14.0, *)) { if (@available(iOS 14.0, *)) {
NSLog(@"stop controller obj: %@, hasAcc %d, hasGyro %d", controller, controller.hasAccelerometer, controller.hasGyroscope); NSLog(@"stop controller obj: %@, hasAcc %d, hasGyro %d", voidController, voidController.hasAccelerometer, voidController.hasGyroscope);
// return; // return;
if(controller.hasAccelerometer){ if(voidController.hasAccelerometer){
[controller.accelTimer invalidate]; [voidController.accelTimer invalidate];
controller.accelTimer = nil; voidController.accelTimer = nil;
} }
if(controller.hasGyroscope){ if(voidController.hasGyroscope){
[controller.gyroTimer invalidate]; [voidController.gyroTimer invalidate];
controller.gyroTimer = nil; voidController.gyroTimer = nil;
} }
} }
} }
@@ -197,7 +197,7 @@
[self.mainFrameViewcontroller reloadStreamConfig]; // reload streamconfig [self.mainFrameViewcontroller reloadStreamConfig]; // reload streamconfig
NSLog(@"viewJustloaded: %d", viewJustLoaded); NSLog(@"viewJustloaded: %d", viewJustLoaded);
if(!viewJustLoaded) [_controllerSupport updateConfig:self.streamConfig delegate:self]; if(!viewJustLoaded) [_controllerSupport updateControllerSupport:self.streamConfig delegate:self];
else viewJustLoaded = false; else viewJustLoaded = false;
// reload controllerSupport obj, this is mandatory for OSC reload,especially when the stream view is launched without OSC // reload controllerSupport obj, this is mandatory for OSC reload,especially when the stream view is launched without OSC
[_streamView setupStreamView:_controllerSupport interactionDelegate:self config:self.streamConfig streamFrameTopLayerView:self.view]; //reinitiate setupStreamView process. [_streamView setupStreamView:_controllerSupport interactionDelegate:self config:self.streamConfig streamFrameTopLayerView:self.view]; //reinitiate setupStreamView process.
@@ -220,7 +220,7 @@
} }
-(void)automaticallyStartSendingGyroEvents{ -(void)automaticallyStartSendingGyroEvents{
[_controllerSupport updateConfig:self.streamConfig delegate:self];// reload controllerSupport obj, this is mandatory for OSC reload,especially when the stream view is launched without OSC [_controllerSupport updateControllerSupport:self.streamConfig delegate:self];// reload controllerSupport obj, this is mandatory for OSC reload,especially when the stream view is launched without OSC
} }