From 578ad81b8a1c5dcf44dc8cbb94ac6545e8a4d15e Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Sun, 6 Jul 2025 21:12:57 +0800 Subject: [PATCH] switch between built-in & controller gyros --- VoidLink.xcodeproj/project.pbxproj | 14 +- VoidLink/Input/ControllerSupport.h | 24 +- VoidLink/Input/ControllerSupport.m | 648 ++++++++++++------ VoidLink/Input/OnScreenControls.m | 4 +- .../Input/{Controller.h => VoidController.h} | 6 +- .../Input/{Controller.m => VoidController.m} | 4 +- .../StreamFrameViewController.m | 9 +- 7 files changed, 460 insertions(+), 249 deletions(-) rename VoidLink/Input/{Controller.h => VoidController.h} (92%) rename VoidLink/Input/{Controller.m => VoidController.m} (73%) diff --git a/VoidLink.xcodeproj/project.pbxproj b/VoidLink.xcodeproj/project.pbxproj index 76f3b940..c55fa126 100644 --- a/VoidLink.xcodeproj/project.pbxproj +++ b/VoidLink.xcodeproj/project.pbxproj @@ -49,7 +49,7 @@ 988FCD41293B091B003050E2 /* KeyboardInputField.m in Sources */ = {isa = PBXBuildFile; fileRef = 988FCD40293B091B003050E2 /* KeyboardInputField.m */; }; 9890CF6B203B7EE1006C4B06 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9890CF6A203B7EE1006C4B06 /* libxml2.tbd */; }; 9896219723D15C7000211983 /* X1Kit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9896219623D15C7000211983 /* X1Kit.swift */; }; - 9897B6A1221260EF00966419 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 9897B6A0221260EF00966419 /* Controller.m */; }; + 9897B6A1221260EF00966419 /* VoidController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9897B6A0221260EF00966419 /* VoidController.m */; }; 98CFB82F1CAD481B0048EF74 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98AB2E841CAD46840089BB98 /* libmoonlight-common.a */; }; 98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */; }; 98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */; }; @@ -208,8 +208,8 @@ 988FCD40293B091B003050E2 /* KeyboardInputField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeyboardInputField.m; sourceTree = ""; }; 9890CF6A203B7EE1006C4B06 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = usr/lib/libxml2.tbd; sourceTree = SDKROOT; }; 9896219623D15C7000211983 /* X1Kit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = X1Kit.swift; path = X1Kit/Sources/X1Kit/X1Kit.swift; sourceTree = ""; }; - 9897B6A0221260EF00966419 /* Controller.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = ""; }; - 9897B6A32212610800966419 /* Controller.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = ""; }; + 9897B6A0221260EF00966419 /* VoidController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VoidController.m; sourceTree = ""; }; + 9897B6A32212610800966419 /* VoidController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoidController.h; sourceTree = ""; }; 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "moonlight-common/moonlight-common.xcodeproj"; sourceTree = ""; }; 98B9CE6C27B2144B00B473C4 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS15.2.sdk/System/Library/Frameworks/AVKit.framework; sourceTree = DEVELOPER_DIR; }; 98D5856B1C0EA79600F6CC00 /* TemporaryHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryHost.h; path = Database/TemporaryHost.h; sourceTree = ""; }; @@ -559,8 +559,8 @@ FB4678EC1A50C40900377732 /* OnScreenControls.m */, FB1A674B2131E65900507771 /* KeyboardSupport.h */, FB1A674C2131E65900507771 /* KeyboardSupport.m */, - 9897B6A0221260EF00966419 /* Controller.m */, - 9897B6A32212610800966419 /* Controller.h */, + 9897B6A0221260EF00966419 /* VoidController.m */, + 9897B6A32212610800966419 /* VoidController.h */, 9827E7A22514366900F25707 /* HapticContext.m */, 9827E7A7251436EA00F25707 /* HapticContext.h */, 840751B12BF49B5A0096B657 /* CustomTapGestureRecognizer.h */, @@ -874,7 +874,7 @@ 847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */, FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */, 189AD29A2DE7446000E24B88 /* HostCollectionViewController.m in Sources */, - 9897B6A1221260EF00966419 /* Controller.m in Sources */, + 9897B6A1221260EF00966419 /* VoidController.m in Sources */, 84351B112C29ACCB00A77989 /* OSCProfilesManager.m in Sources */, FB89462919F646E200339C8A /* mkcert.c in Sources */, FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */, @@ -1135,7 +1135,7 @@ "$(PROJECT_DIR)/libs/FFmpeg/lib/iOS-Sim", ); MARKETING_VERSION = 0.0.1; - PRODUCT_BUNDLE_IDENTIFIER = com.voidlink.tf.debug7.iOS; + PRODUCT_BUNDLE_IDENTIFIER = com.voidlink.tf.debug10.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/VoidLink/Input/ControllerSupport.h b/VoidLink/Input/ControllerSupport.h index 28ec0da6..1064c524 100644 --- a/VoidLink/Input/ControllerSupport.h +++ b/VoidLink/Input/ControllerSupport.h @@ -7,7 +7,7 @@ // #import "StreamConfiguration.h" -#import "Controller.h" +#import "VoidController.h" @class OnScreenControls; @@ -16,7 +16,7 @@ - (void)gamepadPresenceChanged; - (void)mousePresenceChanged; - (void)streamExitRequested; -- (void)automaticallyStartSendingBuiltinGyroEvents; +- (void)automaticallyStartSendingGyroEvents; @end @@ -27,20 +27,20 @@ -(void) initAutoOnScreenControlMode:(OnScreenControls*)osc; -(void) cleanup; --(Controller*) getOscController; +-(VoidController*) getOscController; --(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y; --(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y; +-(void) updateLeftStick:(VoidController*)controller x:(short)x y:(short)y; +-(void) updateRightStick:(VoidController*)controller x:(short)x y:(short)y; --(void) updateLeftTrigger:(Controller*)controller left:(unsigned char)left; --(void) updateRightTrigger:(Controller*)controller right:(unsigned char)right; --(void) updateTriggers:(Controller*)controller left:(unsigned char)left right:(unsigned char)right; +-(void) updateLeftTrigger:(VoidController*)controller left:(unsigned char)left; +-(void) updateRightTrigger:(VoidController*)controller right:(unsigned char)right; +-(void) updateTriggers:(VoidController*)controller left:(unsigned char)left right:(unsigned char)right; --(void) updateButtonFlags:(Controller*)controller flags:(int)flags; --(void) setButtonFlag:(Controller*)controller flags:(int)flags; --(void) clearButtonFlag:(Controller*)controller flags:(int)flags; +-(void) updateButtonFlags:(VoidController*)controller flags:(int)flags; +-(void) setButtonFlag:(VoidController*)controller flags:(int)flags; +-(void) clearButtonFlag:(VoidController*)controller flags:(int)flags; --(void) updateFinished:(Controller*)controller; +-(void) updateFinished:(VoidController*)controller; -(void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor; -(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger; diff --git a/VoidLink/Input/ControllerSupport.m b/VoidLink/Input/ControllerSupport.m index adb84c74..5290a1b1 100644 --- a/VoidLink/Input/ControllerSupport.m +++ b/VoidLink/Input/ControllerSupport.m @@ -10,7 +10,7 @@ // #import "ControllerSupport.h" -#import "Controller.h" +#import "VoidController.h" #import "OnScreenControls.h" @@ -34,9 +34,9 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; id _keyboardDisconnectObserver; NSLock *_controllerStreamLock; - NSMutableDictionary *_controllers; + NSMutableDictionary *_voidControllers; id _delegate; - StreamConfiguration* streamConfig; + StreamConfiguration* _streamConfig; float accumulatedDeltaX; float accumulatedDeltaY; @@ -44,7 +44,8 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; float accumulatedScrollY; OnScreenControls *_osc; - Controller *_oscController; + VoidController *_oscController; + NSMutableSet* _activeGCControllers; #define EMULATING_SELECT 0x1 #define EMULATING_SPECIAL 0x2 @@ -66,7 +67,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; -(void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor { - Controller* controller = [_controllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; + VoidController* controller = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; if (controller == nil && controllerNumber == 0 && _oscEnabled) { // TODO: Rumble emulation for OSC } @@ -81,7 +82,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; -(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger { - Controller* controller = [_controllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; + VoidController* controller = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; if (controller == nil && controllerNumber == 0 && _oscEnabled) { // TODO: Trigger rumble emulation for OSC } @@ -93,62 +94,68 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [controller.rightTriggerMotor setMotorAmplitude:rightTrigger]; } --(void)updateTimerStateForController:(Controller* )controller{ +-(void)updateTimerStateForController:(VoidController* )voidController{ if (@available(iOS 14.0, tvOS 14.0, *)) { - + NSLog(@"controller obj timer update"); if(_gyroMode == GyroModeOff){ - [self stopTimerForController:controller]; + [self stopTimerForController:voidController]; return; } - for(NSNumber* motionTypeObj in controller.motionTypes){ + if(voidController.gamepad.motion.hasAttitudeAndRotationRate) [voidController.motionTypes addObject:@(LI_MOTION_TYPE_ACCEL)]; + if(voidController.gamepad.motion.hasRotationRate) [voidController.motionTypes addObject:@(LI_MOTION_TYPE_GYRO)]; + NSLog(@"voidCon reportHz: %d", voidController.reportRateHz); + + for(NSNumber* motionTypeObj in voidController.motionTypes){ uint8_t motionType = motionTypeObj.intValue; - - if(_gyroMode != AlwaysController && controller.controllerNumber < 2){ - + 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(controller.gamepad.motion == nil || _gyroMode == AlwaysDevice){ + if(voidController == _oscController){ //Player has no controller *or* no motion for controller 1 *or* wants to override controller 1 motion with device motion - if(!controller.motionManager) { - controller.motionManager = [[CMMotionManager alloc] init]; + if(!voidController.motionManager) { + voidController.motionManager = [[CMMotionManager alloc] init]; } - - NSLog(@"device gyro mode, motionType: %d", motionType); + NSLog(@"device gyro mode 666, motionType: %d", motionType); + switch (motionType) { case LI_MOTION_TYPE_ACCEL: - [controller.accelTimer invalidate]; - controller.accelTimer = nil; + [voidController.accelTimer invalidate]; + voidController.accelTimer = nil; // Reset the last motion sample CMAcceleration emptyDeviceAccelSample = {}; - controller.lastDeviceAccelSample = emptyDeviceAccelSample; + voidController.lastDeviceAccelSample = emptyDeviceAccelSample; {dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"setup device built-in gyro accelTimer"); - controller.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / controller.reportRateHz repeats:YES block:^(NSTimer *timer) { + voidController.hasAccelerometer = YES; + voidController.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) { // Don't send duplicate samples - CMAcceleration lastDeviceAccelSample = controller.lastDeviceAccelSample; - CMAcceleration deviceAccelSample = controller.motionManager.deviceMotion.userAcceleration; + 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 += controller.motionManager.deviceMotion.gravity.x * self->_gyroSensitivity; - deviceAccelSample.y += controller.motionManager.deviceMotion.gravity.y * self->_gyroSensitivity; - deviceAccelSample.z += controller.motionManager.deviceMotion.gravity.z * self->_gyroSensitivity; + 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; if (memcmp(&deviceAccelSample, &lastDeviceAccelSample, sizeof(deviceAccelSample)) == 0) { return; } - controller.lastDeviceAccelSample = deviceAccelSample; + voidController.lastDeviceAccelSample = deviceAccelSample; // Convert g to m/s^2 if(UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation == 4){ //check for landscape left or landscape right - LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, + 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)controller.controllerNumber, + LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber, LI_MOTION_TYPE_ACCEL, deviceAccelSample.y * +9.80665f * self->_gyroSensitivity, deviceAccelSample.z * -9.80665f * self->_gyroSensitivity, @@ -158,35 +165,37 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; });} break; case LI_MOTION_TYPE_GYRO: - [controller.gyroTimer invalidate]; - controller.gyroTimer = nil; + [voidController.gyroTimer invalidate]; + voidController.gyroTimer = nil; // Reset the last motion sample CMRotationRate emptyDeviceGyroSample = {}; - controller.lastDeviceGyroSample = emptyDeviceGyroSample; - [controller.motionManager startDeviceMotionUpdates]; + voidController.lastDeviceGyroSample = emptyDeviceGyroSample; + [voidController.motionManager startDeviceMotionUpdates]; NSLog(@"setup device built-in gyro gyroTimer"); - controller.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / controller.reportRateHz repeats:YES block:^(NSTimer *timer) { + voidController.hasGyroscope = YES; + voidController.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) { // Don't send duplicate samples - CMRotationRate lastDeviceGyroSample = controller.lastDeviceGyroSample; - CMRotationRate deviceGyroSample = controller.motionManager.deviceMotion.rotationRate; + CMRotationRate lastDeviceGyroSample = voidController.lastDeviceGyroSample; + CMRotationRate deviceGyroSample = voidController.motionManager.deviceMotion.rotationRate; if (memcmp(&deviceGyroSample, &lastDeviceGyroSample, sizeof(deviceGyroSample)) == 0) { - return; + return; } - controller.lastDeviceGyroSample = deviceGyroSample; + voidController.lastDeviceGyroSample = deviceGyroSample; // Convert rad/s to deg/s + 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)controller.controllerNumber, + 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)controller.controllerNumber, + LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber, LI_MOTION_TYPE_GYRO, deviceGyroSample.y * -57.2957795f * self->_gyroSensitivity, deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity, @@ -199,98 +208,140 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } #endif else{ + NSLog(@"controller obj timer update: controller timer "); switch (motionType) { case LI_MOTION_TYPE_ACCEL: - [controller.accelTimer invalidate]; - controller.accelTimer = nil; - NSLog(@"LI_MOTION_TYPE_ACCEL: setup controller gyro accelTimer"); + [voidController.accelTimer invalidate]; + voidController.accelTimer = nil; - if (controller.reportRateHz && controller.gamepad.motion.hasGravityAndUserAcceleration) { + if (voidController.reportRateHz && voidController.gamepad.motion.hasGravityAndUserAcceleration) { // Reset the last motion sample GCAcceleration emptyAccelSample = {}; - controller.lastAccelSample = emptyAccelSample; + voidController.lastAccelSample = emptyAccelSample; NSLog(@"setup controller gyro accelTimer"); - controller.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / controller.reportRateHz repeats:YES block:^(NSTimer *timer) { - // Don't send duplicate samples - GCAcceleration lastAccelSample = controller.lastAccelSample; - GCAcceleration accelSample = controller.gamepad.motion.acceleration; - if (memcmp(&accelSample, &lastAccelSample, sizeof(accelSample)) == 0) { - return; - } - controller.lastAccelSample = accelSample; - - // Convert g to m/s^2 - LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, - LI_MOTION_TYPE_ACCEL, - accelSample.x * -9.80665f * self->_gyroSensitivity, - accelSample.y * -9.80665f * self->_gyroSensitivity, - accelSample.z * -9.80665f * self->_gyroSensitivity); - }]; + dispatch_sync(dispatch_get_main_queue(), ^{ + voidController.hasAccelerometer = YES; + voidController.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) { + // Don't send duplicate samples + NSLog(@"gyro not returned here, gyro obj:%@", voidController); + GCAcceleration lastAccelSample = voidController.lastAccelSample; + GCAcceleration accelSample = voidController.gamepad.motion.acceleration; + + if (memcmp(&accelSample, &lastAccelSample, sizeof(accelSample)) == 0) { + return; + } + voidController.lastAccelSample = accelSample; + + // Convert g to m/s^2 + NSLog(@"sending controller gyro data, accelSample data 00: %f, playerIndex: %ld, obj: %@",accelSample.x, (long)voidController.gamepad.playerIndex, voidController); + LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber, + LI_MOTION_TYPE_ACCEL, + accelSample.x * -9.80665f * self->_gyroSensitivity, + accelSample.y * -9.80665f * self->_gyroSensitivity, + accelSample.z * -9.80665f * self->_gyroSensitivity); + }]; + }); } break; case LI_MOTION_TYPE_GYRO: - [controller.gyroTimer invalidate]; - controller.gyroTimer = nil; + [voidController.gyroTimer invalidate]; + voidController.gyroTimer = nil; - if (controller.reportRateHz && controller.gamepad.motion.hasRotationRate) { + if (voidController.reportRateHz && voidController.gamepad.motion.hasRotationRate) { // Reset the last motion sample GCRotationRate emptyGyroSample = {}; - controller.lastGyroSample = emptyGyroSample; - NSLog(@"setup controller gyro gyroTimer"); - controller.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / controller.reportRateHz repeats:YES block:^(NSTimer *timer) { - // Don't send duplicate samples - GCRotationRate lastGyroSample = controller.lastGyroSample; - GCRotationRate gyroSample = controller.gamepad.motion.rotationRate; - if (memcmp(&gyroSample, &lastGyroSample, sizeof(gyroSample)) == 0) { - return; - } - controller.lastGyroSample = gyroSample; + voidController.lastGyroSample = emptyGyroSample; + NSLog(@"setup controller gyro gyroTimer, controller obj: %@, reportRate %d", voidController, voidController.reportRateHz); + NSLog(@"setup controller gyro gyroTimer, controller obj num in dict: %lu", (unsigned long)[[_voidControllers allValues] count]); + //dispatch_sync(dispatch_get_main_queue(), ^{ + {dispatch_async(dispatch_get_main_queue(), ^{ - // Convert rad/s to deg/s - LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, - LI_MOTION_TYPE_GYRO, - gyroSample.x * 57.2957795f * self->_gyroSensitivity, - gyroSample.z * 57.2957795f * self->_gyroSensitivity, - gyroSample.y * -57.2957795f * self->_gyroSensitivity); - }]; + NSLog(@"controller obj: %@", voidController); + + voidController.hasGyroscope = YES; + voidController.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / voidController.reportRateHz repeats:YES block:^(NSTimer *timer) { + // Don't send duplicate samples + NSLog(@"gyro not returned here, voidcon obj:%@, gcCon obj %@", voidController, voidController.gamepad); + GCRotationRate lastGyroSample = voidController.lastGyroSample; + GCRotationRate gyroSample = voidController.gamepad.motion.rotationRate; + if (memcmp(&gyroSample, &lastGyroSample, sizeof(gyroSample)) == 0) { + NSLog(@"gyro returned here"); + return; + } + voidController.lastGyroSample = gyroSample; + + // Convert rad/s to deg/s + NSLog(@"sending controller gyro data, gyroSample data 00: %f, playerIndex: %ld, obj: %@",gyroSample.x, (long)voidController.gamepad.playerIndex, voidController); + LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber, + LI_MOTION_TYPE_GYRO, + gyroSample.x * 57.2957795f * self->_gyroSensitivity, + gyroSample.z * 57.2957795f * self->_gyroSensitivity, + gyroSample.y * -57.2957795f * self->_gyroSensitivity); + }]; + // }); + });} } break; } } } + + NSLog(@"controller obj timer, motionTypes: %lu", (unsigned long)voidController.motionTypes.count); + + // Set the motion sensor state if they require manual activation + [self updateSensorSateForController:voidController]; + //controller.gamepad.motion.sensorsActive = YES; + NSLog(@"sensor active: %d", voidController.gamepad.motion.sensorsActive); } } +- (void)updateSensorSateForController:(VoidController* )voidController{ + if (@available(iOS 14.0, *)) { + if (voidController.gamepad.motion.sensorsRequireManualActivation) { + if ((voidController.hasGyroscope || voidController.hasAccelerometer) && _gyroMode != GyroModeOff) { + voidController.gamepad.motion.sensorsActive = YES; + } + else { + voidController.gamepad.motion.sensorsActive = NO; + } + } + } +} - (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz { if (@available(iOS 14.0, tvOS 14.0, *)) { NSLog(@"gyroMode: %ld", (long)_gyroMode); - Controller* controller = [_controllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; + VoidController* voidController = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; //using device motion - if (controller == nil) { + if (voidController == nil || _gyroMode == AlwaysDevice) { // No connected controller for this player, use the _oscController instead - controller = _oscController; + voidController = _oscController; + if(!voidController.motionTypes){ + voidController.motionTypes = [[NSMutableSet alloc] init]; + } + [voidController.motionTypes addObject:@(motionType)]; + + voidController.hasGyroscope = NO; + voidController.hasAccelerometer = NO; + voidController.reportRateHz = reportRateHz; } - if(!controller.motionTypes){ - controller.motionTypes = [[NSMutableSet alloc] init]; - } - [controller.motionTypes addObject:@(motionType)]; + + + voidController.controllerNumber = controllerNumber; + NSLog(@"device gyro codes, %@, add motion type: %d, gyro obj: %@, is osc: %d", voidController.motionTypes, motionType, voidController, voidController == _oscController); - controller.reportRateHz = reportRateHz; - controller.controllerNumber = controllerNumber; - NSLog(@"device gyro codes, %@, add motion type: %d, %@", controller.motionTypes, motionType, controller); - - if(controller != _oscController) [self updateTimerStateForController:controller]; + if(voidController == _oscController) [self updateTimerStateForController:voidController]; + // [self updateTimerStateForController:voidController]; // built-in gyro will be fired somewhere else } } -(void) setControllerLed:(uint16_t)controllerNumber r:(uint8_t)r g:(uint8_t)g b:(uint8_t)b { if (@available(iOS 14.0, tvOS 14.0, *)) { - Controller* controller = [_controllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; + VoidController* controller = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; if (controller == nil) { // No connected controller for this player return; @@ -305,7 +356,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y +-(void) updateLeftStick:(VoidController*)controller x:(short)x y:(short)y { @synchronized(controller) { controller.lastLeftStickX = x; @@ -313,7 +364,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y +-(void) updateRightStick:(VoidController*)controller x:(short)x y:(short)y { @synchronized(controller) { controller.lastRightStickX = x; @@ -321,21 +372,21 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) updateLeftTrigger:(Controller*)controller left:(unsigned char)left +-(void) updateLeftTrigger:(VoidController*)controller left:(unsigned char)left { @synchronized(controller) { controller.lastLeftTrigger = left; } } --(void) updateRightTrigger:(Controller*)controller right:(unsigned char)right +-(void) updateRightTrigger:(VoidController*)controller right:(unsigned char)right { @synchronized(controller) { controller.lastRightTrigger = right; } } --(void) updateTriggers:(Controller*) controller left:(unsigned char)left right:(unsigned char)right +-(void) updateTriggers:(VoidController*) controller left:(unsigned char)left right:(unsigned char)right { @synchronized(controller) { controller.lastLeftTrigger = left; @@ -343,7 +394,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) handleSpecialCombosReleased:(Controller*)controller releasedButtons:(int)releasedButtons +-(void) handleSpecialCombosReleased:(VoidController*)controller releasedButtons:(int)releasedButtons { if ((controller.emulatingButtonFlags & EMULATING_SELECT) && (releasedButtons & (LB_FLAG | PLAY_FLAG))) { controller.lastButtonFlags &= ~BACK_FLAG; @@ -367,7 +418,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) handleSpecialCombosPressed:(Controller*)controller pressedButtons:(int)pressedButtons +-(void) handleSpecialCombosPressed:(VoidController*)controller pressedButtons:(int)pressedButtons { // Special button combos for select and special if (controller.lastButtonFlags & PLAY_FLAG) { @@ -400,7 +451,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) updateButtonFlags:(Controller*)controller flags:(int)flags +-(void) updateButtonFlags:(VoidController*)controller flags:(int)flags { @synchronized(controller) { controller.lastButtonFlags = flags; @@ -416,7 +467,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) setButtonFlag:(Controller*)controller flags:(int)flags +-(void) setButtonFlag:(VoidController*)controller flags:(int)flags { @synchronized(controller) { controller.lastButtonFlags |= flags; @@ -424,7 +475,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) clearButtonFlag:(Controller*)controller flags:(int)flags +-(void) clearButtonFlag:(VoidController*)controller flags:(int)flags { @synchronized(controller) { controller.lastButtonFlags &= ~flags; @@ -437,7 +488,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; return (_multiController ? _controllerNumbers : 1) | (_oscEnabled ? 1 : 0); } --(void) updateFinished:(Controller*)controller +-(void) updateFinished:(VoidController*)controller { BOOL exitRequested = NO; @@ -533,7 +584,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) initializeControllerHaptics:(Controller*) controller +-(void) initializeControllerHaptics:(VoidController*) controller { controller.lowFreqMotor = [HapticContext createContextForLowFreqMotor:controller.gamepad]; controller.highFreqMotor = [HapticContext createContextForHighFreqMotor:controller.gamepad]; @@ -541,7 +592,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; controller.rightTriggerMotor = [HapticContext createContextForRightTrigger:controller.gamepad]; } --(void) cleanupControllerHaptics:(Controller*) controller +-(void) cleanupControllerHaptics:(VoidController*) controller { [controller.lowFreqMotor cleanup]; [controller.highFreqMotor cleanup]; @@ -549,7 +600,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [controller.rightTriggerMotor cleanup]; } --(void) cleanupControllerMotion:(Controller*) controller +-(void) cleanupControllerMotion:(VoidController*) controller { if (@available(iOS 14.0, tvOS 14.0, *)) { // Stop sensor sampling timers @@ -563,7 +614,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) initializeControllerBattery:(Controller*) controller +-(void) initializeControllerBattery:(VoidController*) controller { if (@available(iOS 14.0, tvOS 14.0, *)) { if (controller.gamepad.battery) { @@ -602,14 +653,14 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } } --(void) cleanupControllerBattery:(Controller*) controller +-(void) cleanupControllerBattery:(VoidController*) controller { if (@available(iOS 14.0, tvOS 14.0, *)) { [controller.batteryTimer invalidate]; } } --(BOOL) reportControllerArrival:(Controller*) limeController +-(BOOL) reportControllerArrival:(VoidController*) limeController { // Only report arrival once if (limeController.reportedArrival) { @@ -770,7 +821,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; return YES; } --(void) handleControllerTouchpad:(Controller*)controller touch:(GCControllerDirectionPad*)touch index:(int)index +-(void) handleControllerTouchpad:(VoidController*)controller touch:(GCControllerDirectionPad*)touch index:(int)index { controller_touch_context_t context = index == 0 ? controller.primaryTouch : controller.secondaryTouch; @@ -828,7 +879,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; if (useLegacyPausedHandler) { controller.controllerPausedHandler = ^(GCController *controller) { - Controller* limeController = [self->_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; + VoidController* limeController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; // Get off the main thread dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ @@ -854,7 +905,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) { - Controller* limeController = [self->_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]]; + VoidController* limeController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]]; short leftStickX, leftStickY; short rightStickX, rightStickY; unsigned char leftTrigger, rightTrigger; @@ -1109,51 +1160,106 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self updateAutoOnScreenControlMode]; } --(Controller*) assignController:(GCController*)controller { +-(VoidController* )controllerHasBeenAssignedDeprecated:(GCController*)controller{ + if(controller.playerIndex == 0) return nil; + if(controller.playerIndex > 0){ + for(VoidController* voidController in _voidControllers){ + if(voidController.gamepad == controller) return voidController; + } + } + return nil; +} + + +- (void)updateVoidController:(VoidController* )voidController withGCController:(GCController* )controller{ + voidController.playerIndex = controller.playerIndex == -1 ? 0 : (uint8_t) controller.playerIndex; + voidController.motionTypes = [[NSMutableSet alloc] init]; + voidController.supportedEmulationFlags = EMULATING_SPECIAL | EMULATING_SELECT; + voidController.gamepad = controller; + voidController.hasAccelerometer = NO; + voidController.hasGyroscope = NO; + + + if(voidController.gamepad.motion.hasAttitudeAndRotationRate){ + [voidController.motionTypes addObject:@(LI_MOTION_TYPE_ACCEL)]; + voidController.hasAccelerometer = YES; + 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 this is player 0, it shares state with the OSC + voidController.mergedWithController = _oscController; + _oscController.mergedWithController = voidController; + + if (@available(iOS 13.0, tvOS 13.0, *)) { + if (controller.extendedGamepad != nil && + controller.extendedGamepad.buttonOptions != nil) { + // Disable select button emulation since we have a physical select button + voidController.supportedEmulationFlags &= ~EMULATING_SELECT; + } + } + + if (@available(iOS 14.0, tvOS 14.0, *)) { + if (controller.extendedGamepad != nil && + controller.extendedGamepad.buttonHome != nil) { + // Disable special button emulation since we have a physical special button + voidController.supportedEmulationFlags &= ~EMULATING_SPECIAL; + } + } + + // Prepare controller haptics for use + [self initializeControllerHaptics:voidController]; +} + + +-(VoidController* )assignController:(GCController*)controller { + NSLog(@"run assignController"); + + bool newGCControllerArrival = ![_activeGCControllers containsObject:controller]; + + if(!newGCControllerArrival){ + VoidController* voidController = [_voidControllers objectForKey:@(controller.playerIndex)]; + if(!voidController) { + NSLog(@"blablabla6666666"); + voidController = [[VoidController alloc] init]; + } + [self updateVoidController:voidController withGCController:controller]; + [_voidControllers setObject:voidController forKey:[NSNumber numberWithInteger:voidController.playerIndex]]; + return voidController; + } + + for (int i = 0; i < 4; i++) { if (!(_controllerNumbers & (1 << i))) { _controllerNumbers |= (1 << i); + + VoidController* voidController = [[VoidController alloc] init]; + + + [_activeGCControllers addObject:controller]; controller.playerIndex = i; + voidController.playerIndex = i; - Controller* limeController = [[Controller alloc] init]; - limeController.playerIndex = i; - limeController.supportedEmulationFlags = EMULATING_SPECIAL | EMULATING_SELECT; - limeController.gamepad = controller; - - // If this is player 0, it shares state with the OSC - limeController.mergedWithController = _oscController; - _oscController.mergedWithController = limeController; + [self updateVoidController:voidController withGCController:controller]; - if (@available(iOS 13.0, tvOS 13.0, *)) { - if (controller.extendedGamepad != nil && - controller.extendedGamepad.buttonOptions != nil) { - // Disable select button emulation since we have a physical select button - limeController.supportedEmulationFlags &= ~EMULATING_SELECT; - } - } - - if (@available(iOS 14.0, tvOS 14.0, *)) { - if (controller.extendedGamepad != nil && - controller.extendedGamepad.buttonHome != nil) { - // Disable special button emulation since we have a physical special button - limeController.supportedEmulationFlags &= ~EMULATING_SPECIAL; - } - } - - // Prepare controller haptics for use - [self initializeControllerHaptics:limeController]; - - [_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]]; + // if(![_controllers.allValues containsObject:limeController]) + [_voidControllers setObject:voidController forKey:[NSNumber numberWithInteger:controller.playerIndex]]; Log(LOG_I, @"Assigning controller index: %d", i); - return limeController; + + return voidController; + } } return nil; } --(Controller*) getOscController { +-(VoidController*) getOscController { return _oscController; } @@ -1208,15 +1314,31 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; -(NSUInteger) getConnectedGamepadCount { - return _controllers.count; + return _voidControllers.count; } --(void)updateConfig:(StreamConfiguration*)streamConfig delegate:(id)delegate { +- (void)assignControllers{ + for (GCController* controller in [GCController controllers]) { + NSLog(@"controller count: iterating"); + + if ([ControllerSupport isSupportedGamepad:controller]) { + NSLog(@"controller count: is supported,is contained by dict: %d", [_activeGCControllers containsObject:controller]); + NSLog(@"controller obj +1 in dic"); + [self assignController:controller]; + NSLog(@"controller obj num in dict: %lu", (unsigned long)_voidControllers.allValues.count); + [self registerControllerCallbacks:controller]; + // Note: We cannot report controller arrival to the host here, + // because the connection has not been established yet.play + } + } + NSLog(@"device gyro codes,update gyroMode: %d, controller count: %lu", _gyroMode, (unsigned long)_voidControllers.count); +} + +- (void)updateCommonConfig:(StreamConfiguration* )streamConfig{ + _streamConfig = streamConfig; _multiController = streamConfig.multiController; _swapABXYButtons = streamConfig.swapABXYButtons; - _gyroMode = streamConfig.gyroMode; - if(!_oscController) _oscController = [[Controller alloc] init]; _oscController.playerIndex = 0; DataManager* dataMan = [[DataManager alloc] init]; @@ -1224,39 +1346,100 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; TemporarySettings* currentSettings = [dataMan getSettings]; _oscEnabled = true; _gyroSensitivity = currentSettings.gyroSensitivity.floatValue; +} + +- (void)updateConfig:(StreamConfiguration*)streamConfig delegate:(id)delegate { + NSLog(@"update config call"); + _gyroMode = streamConfig.gyroMode; + + [self updateCommonConfig:streamConfig]; Log(LOG_I, @"Number of supported controllers connected: %d", [ControllerSupport getGamepadCount]); Log(LOG_I, @"Multi-controller: %d", _multiController); - for (GCController* controller in [GCController controllers]) { - if ([ControllerSupport isSupportedGamepad:controller]) { - [self assignController:controller]; - [self registerControllerCallbacks:controller]; + + if (@available(iOS 14.0, tvOS 14.0, *)) { + switch(_gyroMode){ + case GyroModeOff: + [self updateTimerStateForController:_oscController]; + for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller]; + break; + case GyroModeAuto: + [self stopTimerForController:_oscController]; + for(VoidController* controller in _voidControllers.allValues) [self stopTimerForController:controller]; + if(_voidControllers.count == 0) [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){ + NSLog(@"stop external controller timer %@", controller); + [self stopTimerForController:controller]; + } + [self updateTimerStateForController:_oscController]; + break; + case AlwaysController: + [self stopTimerForController:_oscController]; + for(VoidController* controller in _voidControllers.allValues) [self stopTimerForController:controller]; + for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller]; + break; + } + if(_gyroMode != GyroModeOff){ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ - // Note: We cannot report controller arrival to the host here, - // because the connection has not been established yet. + // [self->_delegate automaticallyStartSendingGyroEvents]; // this will discontine any control events sent to the remote side for a instant. anyway it works out as signature describes + }); } } + + + + [self assignControllers]; + + + + NSLog(@"controllerNumbers: %d", _controllerNumbers); + + for(VoidController* controller in _voidControllers.allValues){ + NSLog(@"controller obj in dict: %@", controller); + } +} + +-(id)initWithConfig:(StreamConfiguration*)streamConfig delegate:(id)delegate +{ + self = [super init]; + + NSLog(@"controller support init"); + + _delegate = delegate; + _controllerStreamLock = [[NSLock alloc] init]; + _voidControllers = [[NSMutableDictionary alloc] init]; + _activeGCControllers = [[NSMutableSet alloc] init]; + _controllerNumbers = 0; + _captureMouse = (streamConfig.localMousePointerMode == 0); if (@available(iOS 14.0, tvOS 14.0, *)) { - for (GCMouse* mouse in [GCMouse mice]) { - [self registerMouseCallbacks:mouse]; + for (GCMouse* mouse in [GCMouse mice]) { + [self registerMouseCallbacks:mouse]; + } } - } _controllerConnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Log(LOG_I, @"Controller connected!"); - - GCController* controller = note.object; - - if (![ControllerSupport isSupportedGamepad:controller]) { - // Ignore micro gamepads and motion controllers - return; - } - - Controller* limeController = [self assignController:controller]; + Log(LOG_I, @"Controller connected!"); + + GCController* controller = note.object; + + if (![ControllerSupport isSupportedGamepad:controller]) { + // Ignore micro gamepads and motion controllers + return; + } + + //[self->_activeGCControllers addObject:controller]; + VoidController* limeController = [self assignController:controller]; if (limeController) { // Register callbacks on the new controller [self registerControllerCallbacks:controller]; @@ -1265,12 +1448,12 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self reportControllerArrival:limeController]; // Re-evaluate the on-screen control mode - [self updateAutoOnScreenControlMode]; + //[self updateAutoOnScreenControlMode]; // Notify the delegate [self->_delegate gamepadPresenceChanged]; } - }]; +}]; _controllerDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { Log(LOG_I, @"Controller disconnected!"); @@ -1283,28 +1466,31 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; } [self unregisterControllerCallbacks:controller]; - self->_controllerNumbers &= ~(1 << controller.playerIndex); + + if([self->_activeGCControllers containsObject:controller]){ + [self->_activeGCControllers removeObject:controller]; + self->_controllerNumbers &= ~(1 << controller.playerIndex); + } Log(LOG_I, @"Unassigning controller index: %ld", (long)controller.playerIndex); - Controller* limeController = [self->_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; - if (limeController) { + VoidController* voidController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; + if (voidController) { // Stop haptics on this controller - [self cleanupControllerHaptics:limeController]; + [self cleanupControllerHaptics:voidController]; // Stop motion reports on this controller - [self cleanupControllerMotion:limeController]; + [self cleanupControllerMotion:voidController]; // Stop battery reports on this controller - [self cleanupControllerBattery:limeController]; + [self cleanupControllerBattery:voidController]; // Disassociate this controller from any controllers merged with it - if (limeController.mergedWithController) { - assert(limeController.mergedWithController.mergedWithController == limeController); - limeController.mergedWithController.mergedWithController = nil; + if (voidController.mergedWithController) { + if(voidController.mergedWithController.mergedWithController == voidController) voidController.mergedWithController.mergedWithController = nil; } // Inform the server of the updated active gamepads before removing this controller - [self updateFinished:limeController]; + [self updateFinished:voidController]; // Re-evaluate the on-screen control mode [self updateAutoOnScreenControlMode]; @@ -1315,6 +1501,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; }]; if (@available(iOS 14.0, tvOS 14.0, *)) { + _mouseConnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { Log(LOG_I, @"Mouse connected!"); @@ -1322,7 +1509,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; // Register for mouse events [self registerMouseCallbacks: mouse]; - + // Re-evaluate the on-screen control mode [self updateAutoOnScreenControlMode]; @@ -1336,7 +1523,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; // Unregister for mouse events [self unregisterMouseCallbacks: mouse]; - + // Re-evaluate the on-screen control mode [self updateAutoOnScreenControlMode]; @@ -1351,55 +1538,71 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; }]; _keyboardDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCKeyboardDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { Log(LOG_I, @"Keyboard disconnected!"); - + // Re-evaluate the on-screen control mode [self updateAutoOnScreenControlMode]; }]; - NSLog(@"device gyro codes,update gyroMode: %d, controller count: %lu", _gyroMode, (unsigned long)_controllers.count); - - for(Controller* controller in _controllers) [self updateTimerStateForController:controller]; - if(_controllers.count == 0) [self updateTimerStateForController:_oscController]; + //for(Controller* controller in _controllers) [self updateTimerStateForController:controller]; } -} + --(id)initWithConfig:(StreamConfiguration*)streamConfig delegate:(id)delegate -{ - self = [super init]; - _delegate = delegate; - _controllerStreamLock = [[NSLock alloc] init]; - _controllers = [[NSMutableDictionary alloc] init]; - _controllerNumbers = 0; - [self updateConfig:streamConfig delegate:delegate]; + + _oscController = [[VoidController alloc] init]; + _gyroMode = AlwaysDevice; + + [self updateCommonConfig:streamConfig]; + + for(VoidController* controller in _voidControllers.allValues){ + NSLog(@"stop external controller timer %@", controller); + [self stopTimerForController:controller]; + } + [self updateTimerStateForController:_oscController]; + + [self assignControllers]; + + //[self updateConfig:streamConfig delegate:delegate]; + + return self; } --(void) connectionEstablished{ - for (Controller* controller in [_controllers allValues]){ - // Report the controller arrival to the host if we haven't done so yet - [self reportControllerArrival:controller]; - [self updateTimerStateForController:controller]; - } - //return; - if(_controllers.count ==0 && (_gyroMode == GyroModeAuto || _gyroMode == AlwaysDevice)){ - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), +-(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)), + dispatch_get_main_queue(), ^{ + //[self->_delegate automaticallyStartSendingGyroEvents]; // this will discontine any control events sent to the remote side for a instant. anyway it works out as signature describes + [self updateTimerStateForController:self->_oscController]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [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)(0.5 * NSEC_PER_SEC)), - dispatch_get_main_queue(), ^{ - [self->_delegate automaticallyStartSendingBuiltinGyroEvents]; // this will discontine any control events sent to the remote side for a instant. anyway it works out as signature describes - }); + self->_gyroMode = self->_streamConfig.gyroMode; + if(self->_gyroMode == AlwaysController){ + [self stopTimerForController:self->_oscController]; + for(VoidController* voidController in self->_voidControllers.allValues) [self stopTimerForController:voidController]; + for(VoidController* voidController in self->_voidControllers.allValues) [self updateTimerStateForController:voidController]; + //for(VoidController* controller in _voidControllers.allValues) [self updateTimerStateForController:controller]; + } }); - } + }); } --(void)stopTimerForController:(Controller* )controller{ - [controller.accelTimer invalidate]; - controller.accelTimer = nil; - [controller.gyroTimer invalidate]; - controller.gyroTimer = nil; +-(void)stopTimerForController:(VoidController* )controller{ + if (@available(iOS 14.0, *)) { + NSLog(@"stop controller obj: %@, hasAcc %d, hasGyro %d", controller, controller.hasAccelerometer, controller.hasGyroscope); + // return; + if(controller.hasAccelerometer){ + [controller.accelTimer invalidate]; + controller.accelTimer = nil; + } + if(controller.hasGyroscope){ + [controller.gyroTimer invalidate]; + controller.gyroTimer = nil; + } + } } -(void) cleanup @@ -1420,13 +1623,14 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; _controllerNumbers = 0; - for (Controller* controller in [_controllers allValues]) { + [self stopTimerForController:_oscController]; + for (VoidController* controller in [_voidControllers allValues]) { [self stopTimerForController:controller]; [self cleanupControllerHaptics:controller]; [self cleanupControllerMotion:controller]; [self cleanupControllerBattery:controller]; } - [_controllers removeAllObjects]; + [_voidControllers removeAllObjects]; #if !TARGET_OS_TV [self cleanupControllerMotion:_oscController]; diff --git a/VoidLink/Input/OnScreenControls.m b/VoidLink/Input/OnScreenControls.m index bd799889..241a19b7 100644 --- a/VoidLink/Input/OnScreenControls.m +++ b/VoidLink/Input/OnScreenControls.m @@ -11,7 +11,7 @@ #import "OnScreenControls.h" #import "CustomTapGestureRecognizer.h" -#import "Controller.h" +#import "VoidController.h" #include "Limelight.h" #if !TARGET_OS_TV #import @@ -70,7 +70,7 @@ static NSSet *validPositionButtonNames; BOOL _visible; ControllerSupport *_controllerSupport; - Controller *_controller; + VoidController *_controller; NSMutableArray* _deadTouches; BOOL _swapABXY; BOOL _largerStickLR1; diff --git a/VoidLink/Input/Controller.h b/VoidLink/Input/VoidController.h similarity index 92% rename from VoidLink/Input/Controller.h rename to VoidLink/Input/VoidController.h index d3a042f3..0515af56 100644 --- a/VoidLink/Input/Controller.h +++ b/VoidLink/Input/VoidController.h @@ -14,7 +14,7 @@ @import CoreMotion; #endif -@interface Controller : NSObject +@interface VoidController : NSObject typedef struct { float lastX; @@ -64,11 +64,13 @@ typedef NS_ENUM(NSInteger, ControllerDeviceBatteryState) { @property (nonatomic) float lastBatteryLevel; @property (nonatomic) BOOL reportedArrival; -@property (nonatomic) Controller* _Nullable mergedWithController; +@property (nonatomic) VoidController* _Nullable mergedWithController; @property(nonatomic, strong) NSMutableSet* _Nullable motionTypes; @property(nonatomic, assign) uint16_t reportRateHz; @property(nonatomic, assign) uint16_t controllerNumber; +@property(nonatomic, assign) BOOL hasAccelerometer; +@property(nonatomic, assign) BOOL hasGyroscope; @end diff --git a/VoidLink/Input/Controller.m b/VoidLink/Input/VoidController.m similarity index 73% rename from VoidLink/Input/Controller.m rename to VoidLink/Input/VoidController.m index 7587928b..c1e03032 100644 --- a/VoidLink/Input/Controller.m +++ b/VoidLink/Input/VoidController.m @@ -6,8 +6,8 @@ // Copyright © 2019 Moonlight Game Streaming Project. All rights reserved. // -#include "Controller.h" +#include "VoidController.h" -@implementation Controller +@implementation VoidController @end diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index 96a44430..b4f5eaa6 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -57,6 +57,7 @@ StreamView *_streamView; UIScrollView *_scrollView; BOOL _userIsInteracting; + bool viewJustLoaded; CGSize _keyboardSize; UIWindow *_extWindow; UIView *_streamVideoRenderView; @@ -195,7 +196,10 @@ [self->_streamView disableOnScreenControls]; //don't know why but this must be called outside the streamview class, just put it here. execute in streamview class cause hang [self.mainFrameViewcontroller reloadStreamConfig]; // reload streamconfig - [_controllerSupport updateConfig:self.streamConfig delegate:self];// reload controllerSupport obj, this is mandatory for OSC reload,especially when the stream view is launched without OSC + NSLog(@"viewJustloaded: %d", viewJustLoaded); + if(!viewJustLoaded) [_controllerSupport updateConfig:self.streamConfig delegate:self]; + else viewJustLoaded = false; + // 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. // we got self.view passed to streamView class as the topLayerView, will be useful in many cases [self->_streamView reloadOnScreenControlsRealtimeWith:(ControllerSupport*)_controllerSupport @@ -215,7 +219,7 @@ NSLog(@"streamview gestures: %d", (uint32_t)[_streamView.gestureRecognizers count]); } --(void)automaticallyStartSendingBuiltinGyroEvents{ +-(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 } @@ -347,6 +351,7 @@ - (void)viewDidLoad { + viewJustLoaded = true; [super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES animated:YES];