switch between built-in & controller gyros

This commit is contained in:
TrueZhuanjia committed 2025-07-06 21:12:57 +08:00
1 parent 3cbdba78d6
commit 578ad81b8a
7 files changed
+400 -189

No files matched your search

+7 -7
View File
@@ -49,7 +49,7 @@
988FCD41293B091B003050E2 /* KeyboardInputField.m in Sources */ = {isa = PBXBuildFile; fileRef = 988FCD40293B091B003050E2 /* KeyboardInputField.m */; }; 988FCD41293B091B003050E2 /* KeyboardInputField.m in Sources */ = {isa = PBXBuildFile; fileRef = 988FCD40293B091B003050E2 /* KeyboardInputField.m */; };
9890CF6B203B7EE1006C4B06 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9890CF6A203B7EE1006C4B06 /* libxml2.tbd */; }; 9890CF6B203B7EE1006C4B06 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9890CF6A203B7EE1006C4B06 /* libxml2.tbd */; };
9896219723D15C7000211983 /* X1Kit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9896219623D15C7000211983 /* X1Kit.swift */; }; 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 */; }; 98CFB82F1CAD481B0048EF74 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98AB2E841CAD46840089BB98 /* libmoonlight-common.a */; };
98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */; }; 98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */; };
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856F1C0ED0E800F6CC00 /* TemporarySettings.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 = "<group>"; }; 988FCD40293B091B003050E2 /* KeyboardInputField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeyboardInputField.m; sourceTree = "<group>"; };
9890CF6A203B7EE1006C4B06 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = usr/lib/libxml2.tbd; sourceTree = SDKROOT; }; 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 = "<group>"; }; 9896219623D15C7000211983 /* X1Kit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = X1Kit.swift; path = X1Kit/Sources/X1Kit/X1Kit.swift; sourceTree = "<group>"; };
9897B6A0221260EF00966419 /* Controller.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; }; 9897B6A0221260EF00966419 /* VoidController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VoidController.m; sourceTree = "<group>"; };
9897B6A32212610800966419 /* Controller.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; }; 9897B6A32212610800966419 /* VoidController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoidController.h; sourceTree = "<group>"; };
98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "moonlight-common/moonlight-common.xcodeproj"; sourceTree = "<group>"; }; 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "moonlight-common/moonlight-common.xcodeproj"; sourceTree = "<group>"; };
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; }; 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 = "<group>"; }; 98D5856B1C0EA79600F6CC00 /* TemporaryHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryHost.h; path = Database/TemporaryHost.h; sourceTree = "<group>"; };
@@ -559,8 +559,8 @@
FB4678EC1A50C40900377732 /* OnScreenControls.m */, FB4678EC1A50C40900377732 /* OnScreenControls.m */,
FB1A674B2131E65900507771 /* KeyboardSupport.h */, FB1A674B2131E65900507771 /* KeyboardSupport.h */,
FB1A674C2131E65900507771 /* KeyboardSupport.m */, FB1A674C2131E65900507771 /* KeyboardSupport.m */,
9897B6A0221260EF00966419 /* Controller.m */, 9897B6A0221260EF00966419 /* VoidController.m */,
9897B6A32212610800966419 /* Controller.h */, 9897B6A32212610800966419 /* VoidController.h */,
9827E7A22514366900F25707 /* HapticContext.m */, 9827E7A22514366900F25707 /* HapticContext.m */,
9827E7A7251436EA00F25707 /* HapticContext.h */, 9827E7A7251436EA00F25707 /* HapticContext.h */,
840751B12BF49B5A0096B657 /* CustomTapGestureRecognizer.h */, 840751B12BF49B5A0096B657 /* CustomTapGestureRecognizer.h */,
@@ -874,7 +874,7 @@
847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */, 847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */,
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */, FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */,
189AD29A2DE7446000E24B88 /* HostCollectionViewController.m in Sources */, 189AD29A2DE7446000E24B88 /* HostCollectionViewController.m in Sources */,
9897B6A1221260EF00966419 /* Controller.m in Sources */, 9897B6A1221260EF00966419 /* VoidController.m in Sources */,
84351B112C29ACCB00A77989 /* OSCProfilesManager.m in Sources */, 84351B112C29ACCB00A77989 /* OSCProfilesManager.m in Sources */,
FB89462919F646E200339C8A /* mkcert.c in Sources */, FB89462919F646E200339C8A /* mkcert.c in Sources */,
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */, FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */,
@@ -1135,7 +1135,7 @@
"$(PROJECT_DIR)/libs/FFmpeg/lib/iOS-Sim", "$(PROJECT_DIR)/libs/FFmpeg/lib/iOS-Sim",
); );
MARKETING_VERSION = 0.0.1; 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)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
+12 -12
View File
@@ -7,7 +7,7 @@
// //
#import "StreamConfiguration.h" #import "StreamConfiguration.h"
#import "Controller.h" #import "VoidController.h"
@class OnScreenControls; @class OnScreenControls;
@@ -16,7 +16,7 @@
- (void)gamepadPresenceChanged; - (void)gamepadPresenceChanged;
- (void)mousePresenceChanged; - (void)mousePresenceChanged;
- (void)streamExitRequested; - (void)streamExitRequested;
- (void)automaticallyStartSendingBuiltinGyroEvents; - (void)automaticallyStartSendingGyroEvents;
@end @end
@@ -27,20 +27,20 @@
-(void) initAutoOnScreenControlMode:(OnScreenControls*)osc; -(void) initAutoOnScreenControlMode:(OnScreenControls*)osc;
-(void) cleanup; -(void) cleanup;
-(Controller*) getOscController; -(VoidController*) getOscController;
-(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y; -(void) updateLeftStick:(VoidController*)controller x:(short)x y:(short)y;
-(void) updateRightStick:(Controller*)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) updateLeftTrigger:(VoidController*)controller left:(unsigned char)left;
-(void) updateRightTrigger:(Controller*)controller right:(unsigned char)right; -(void) updateRightTrigger:(VoidController*)controller right:(unsigned char)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;
-(void) updateButtonFlags:(Controller*)controller flags:(int)flags; -(void) updateButtonFlags:(VoidController*)controller flags:(int)flags;
-(void) setButtonFlag:(Controller*)controller flags:(int)flags; -(void) setButtonFlag:(VoidController*)controller flags:(int)flags;
-(void) clearButtonFlag:(Controller*)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) 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; -(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger;
+366 -162
View File
@@ -10,7 +10,7 @@
// //
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "Controller.h" #import "VoidController.h"
#import "OnScreenControls.h" #import "OnScreenControls.h"
@@ -34,9 +34,9 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
id _keyboardDisconnectObserver; id _keyboardDisconnectObserver;
NSLock *_controllerStreamLock; NSLock *_controllerStreamLock;
NSMutableDictionary *_controllers; NSMutableDictionary *_voidControllers;
id<ControllerSupportDelegate> _delegate; id<ControllerSupportDelegate> _delegate;
StreamConfiguration* streamConfig; StreamConfiguration* _streamConfig;
float accumulatedDeltaX; float accumulatedDeltaX;
float accumulatedDeltaY; float accumulatedDeltaY;
@@ -44,7 +44,8 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
float accumulatedScrollY; float accumulatedScrollY;
OnScreenControls *_osc; OnScreenControls *_osc;
Controller *_oscController; VoidController *_oscController;
NSMutableSet* _activeGCControllers;
#define EMULATING_SELECT 0x1 #define EMULATING_SELECT 0x1
#define EMULATING_SPECIAL 0x2 #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 -(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) { if (controller == nil && controllerNumber == 0 && _oscEnabled) {
// TODO: Rumble emulation for OSC // 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 -(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) { if (controller == nil && controllerNumber == 0 && _oscEnabled) {
// TODO: Trigger rumble emulation for OSC // TODO: Trigger rumble emulation for OSC
} }
@@ -93,62 +94,68 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[controller.rightTriggerMotor setMotorAmplitude:rightTrigger]; [controller.rightTriggerMotor setMotorAmplitude:rightTrigger];
} }
-(void)updateTimerStateForController:(Controller* )controller{ -(void)updateTimerStateForController:(VoidController* )voidController{
if (@available(iOS 14.0, tvOS 14.0, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
NSLog(@"controller obj timer update");
if(_gyroMode == GyroModeOff){ if(_gyroMode == GyroModeOff){
[self stopTimerForController:controller]; [self stopTimerForController:voidController];
return; 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; uint8_t motionType = motionTypeObj.intValue;
NSLog(@"controller obj controllerNumber %d", voidController.controllerNumber);
if(_gyroMode != AlwaysController && controller.controllerNumber < 2){ if(_gyroMode != AlwaysController || voidController == _oscController){
#if !TARGET_OS_TV //tvOS has no device motion
if(controller.gamepad.motion == nil || _gyroMode == AlwaysDevice){
//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];
}
NSLog(@"device gyro mode, motionType: %d", motionType); NSLog(@"device gyro mode, motionType: %d", motionType);
#if !TARGET_OS_TV //tvOS has no device motion
if(voidController == _oscController){
//Player has no controller *or* no motion for controller 1 *or* wants to override controller 1 motion with device motion
if(!voidController.motionManager) {
voidController.motionManager = [[CMMotionManager alloc] init];
}
NSLog(@"device gyro mode 666, motionType: %d", motionType);
switch (motionType) { switch (motionType) {
case LI_MOTION_TYPE_ACCEL: case LI_MOTION_TYPE_ACCEL:
[controller.accelTimer invalidate]; [voidController.accelTimer invalidate];
controller.accelTimer = nil; voidController.accelTimer = nil;
// Reset the last motion sample // Reset the last motion sample
CMAcceleration emptyDeviceAccelSample = {}; CMAcceleration emptyDeviceAccelSample = {};
controller.lastDeviceAccelSample = emptyDeviceAccelSample; voidController.lastDeviceAccelSample = emptyDeviceAccelSample;
{dispatch_async(dispatch_get_main_queue(), ^{ {dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"setup device built-in gyro accelTimer"); 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 // Don't send duplicate samples
CMAcceleration lastDeviceAccelSample = controller.lastDeviceAccelSample; CMAcceleration lastDeviceAccelSample = voidController.lastDeviceAccelSample;
CMAcceleration deviceAccelSample = controller.motionManager.deviceMotion.userAcceleration; CMAcceleration deviceAccelSample = voidController.motionManager.deviceMotion.userAcceleration;
//userAcceleration does not contain gravity, add gravity to x, y and z values: //userAcceleration does not contain gravity, add gravity to x, y and z values:
deviceAccelSample.x += controller.motionManager.deviceMotion.gravity.x * self->_gyroSensitivity; deviceAccelSample.x += voidController.motionManager.deviceMotion.gravity.x * self->_gyroSensitivity;
deviceAccelSample.y += controller.motionManager.deviceMotion.gravity.y * self->_gyroSensitivity; deviceAccelSample.y += voidController.motionManager.deviceMotion.gravity.y * self->_gyroSensitivity;
deviceAccelSample.z += controller.motionManager.deviceMotion.gravity.z * self->_gyroSensitivity; deviceAccelSample.z += voidController.motionManager.deviceMotion.gravity.z * self->_gyroSensitivity;
if (memcmp(&deviceAccelSample, &lastDeviceAccelSample, sizeof(deviceAccelSample)) == 0) { if (memcmp(&deviceAccelSample, &lastDeviceAccelSample, sizeof(deviceAccelSample)) == 0) {
return; return;
} }
controller.lastDeviceAccelSample = deviceAccelSample; voidController.lastDeviceAccelSample = deviceAccelSample;
// Convert g to m/s^2 // Convert g to m/s^2
if(UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation == 4){ //check for landscape left or landscape right 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, LI_MOTION_TYPE_ACCEL,
deviceAccelSample.y * -9.80665f * self->_gyroSensitivity, deviceAccelSample.y * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.z * -9.80665f * self->_gyroSensitivity, deviceAccelSample.z * -9.80665f * self->_gyroSensitivity,
deviceAccelSample.x * -9.80665f * self->_gyroSensitivity); deviceAccelSample.x * -9.80665f * self->_gyroSensitivity);
} }
else{ else{
LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_ACCEL, LI_MOTION_TYPE_ACCEL,
deviceAccelSample.y * +9.80665f * self->_gyroSensitivity, deviceAccelSample.y * +9.80665f * self->_gyroSensitivity,
deviceAccelSample.z * -9.80665f * self->_gyroSensitivity, deviceAccelSample.z * -9.80665f * self->_gyroSensitivity,
@@ -158,35 +165,37 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
});} });}
break; break;
case LI_MOTION_TYPE_GYRO: case LI_MOTION_TYPE_GYRO:
[controller.gyroTimer invalidate]; [voidController.gyroTimer invalidate];
controller.gyroTimer = nil; voidController.gyroTimer = nil;
// Reset the last motion sample // Reset the last motion sample
CMRotationRate emptyDeviceGyroSample = {}; CMRotationRate emptyDeviceGyroSample = {};
controller.lastDeviceGyroSample = emptyDeviceGyroSample; voidController.lastDeviceGyroSample = emptyDeviceGyroSample;
[controller.motionManager startDeviceMotionUpdates]; [voidController.motionManager startDeviceMotionUpdates];
NSLog(@"setup device built-in gyro gyroTimer"); 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 // Don't send duplicate samples
CMRotationRate lastDeviceGyroSample = controller.lastDeviceGyroSample; CMRotationRate lastDeviceGyroSample = voidController.lastDeviceGyroSample;
CMRotationRate deviceGyroSample = controller.motionManager.deviceMotion.rotationRate; CMRotationRate deviceGyroSample = voidController.motionManager.deviceMotion.rotationRate;
if (memcmp(&deviceGyroSample, &lastDeviceGyroSample, sizeof(deviceGyroSample)) == 0) { if (memcmp(&deviceGyroSample, &lastDeviceGyroSample, sizeof(deviceGyroSample)) == 0) {
return; return;
} }
controller.lastDeviceGyroSample = deviceGyroSample; voidController.lastDeviceGyroSample = deviceGyroSample;
// Convert rad/s to deg/s // 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 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, LI_MOTION_TYPE_GYRO,
deviceGyroSample.y * 57.2957795f * self->_gyroSensitivity, deviceGyroSample.y * 57.2957795f * self->_gyroSensitivity,
deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity, deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity,
deviceGyroSample.x * 57.2957795f * self->_gyroSensitivity); deviceGyroSample.x * 57.2957795f * self->_gyroSensitivity);
} }
else{ else{
LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, LiSendControllerMotionEvent((uint8_t)voidController.controllerNumber,
LI_MOTION_TYPE_GYRO, LI_MOTION_TYPE_GYRO,
deviceGyroSample.y * -57.2957795f * self->_gyroSensitivity, deviceGyroSample.y * -57.2957795f * self->_gyroSensitivity,
deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity, deviceGyroSample.z * 57.2957795f * self->_gyroSensitivity,
@@ -199,98 +208,140 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
} }
#endif #endif
else{ else{
NSLog(@"controller obj timer update: controller timer ");
switch (motionType) { switch (motionType) {
case LI_MOTION_TYPE_ACCEL: case LI_MOTION_TYPE_ACCEL:
[controller.accelTimer invalidate]; [voidController.accelTimer invalidate];
controller.accelTimer = nil; voidController.accelTimer = nil;
NSLog(@"LI_MOTION_TYPE_ACCEL: setup controller gyro accelTimer");
if (controller.reportRateHz && controller.gamepad.motion.hasGravityAndUserAcceleration) { if (voidController.reportRateHz && voidController.gamepad.motion.hasGravityAndUserAcceleration) {
// Reset the last motion sample // Reset the last motion sample
GCAcceleration emptyAccelSample = {}; GCAcceleration emptyAccelSample = {};
controller.lastAccelSample = emptyAccelSample; voidController.lastAccelSample = emptyAccelSample;
NSLog(@"setup controller gyro accelTimer"); NSLog(@"setup controller gyro accelTimer");
controller.accelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / controller.reportRateHz repeats:YES block:^(NSTimer *timer) { 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 // Don't send duplicate samples
GCAcceleration lastAccelSample = controller.lastAccelSample; NSLog(@"gyro not returned here, gyro obj:%@", voidController);
GCAcceleration accelSample = controller.gamepad.motion.acceleration; GCAcceleration lastAccelSample = voidController.lastAccelSample;
GCAcceleration accelSample = voidController.gamepad.motion.acceleration;
if (memcmp(&accelSample, &lastAccelSample, sizeof(accelSample)) == 0) { if (memcmp(&accelSample, &lastAccelSample, sizeof(accelSample)) == 0) {
return; return;
} }
controller.lastAccelSample = accelSample; voidController.lastAccelSample = accelSample;
// Convert g to m/s^2 // Convert g to m/s^2
LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, 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, LI_MOTION_TYPE_ACCEL,
accelSample.x * -9.80665f * self->_gyroSensitivity, accelSample.x * -9.80665f * self->_gyroSensitivity,
accelSample.y * -9.80665f * self->_gyroSensitivity, accelSample.y * -9.80665f * self->_gyroSensitivity,
accelSample.z * -9.80665f * self->_gyroSensitivity); accelSample.z * -9.80665f * self->_gyroSensitivity);
}]; }];
});
} }
break; break;
case LI_MOTION_TYPE_GYRO: case LI_MOTION_TYPE_GYRO:
[controller.gyroTimer invalidate]; [voidController.gyroTimer invalidate];
controller.gyroTimer = nil; voidController.gyroTimer = nil;
if (controller.reportRateHz && controller.gamepad.motion.hasRotationRate) { if (voidController.reportRateHz && voidController.gamepad.motion.hasRotationRate) {
// Reset the last motion sample // Reset the last motion sample
GCRotationRate emptyGyroSample = {}; GCRotationRate emptyGyroSample = {};
controller.lastGyroSample = emptyGyroSample; voidController.lastGyroSample = emptyGyroSample;
NSLog(@"setup controller gyro gyroTimer"); NSLog(@"setup controller gyro gyroTimer, controller obj: %@, reportRate %d", voidController, voidController.reportRateHz);
controller.gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / controller.reportRateHz repeats:YES block:^(NSTimer *timer) { 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(), ^{
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 // Don't send duplicate samples
GCRotationRate lastGyroSample = controller.lastGyroSample; NSLog(@"gyro not returned here, voidcon obj:%@, gcCon obj %@", voidController, voidController.gamepad);
GCRotationRate gyroSample = controller.gamepad.motion.rotationRate; GCRotationRate lastGyroSample = voidController.lastGyroSample;
GCRotationRate gyroSample = voidController.gamepad.motion.rotationRate;
if (memcmp(&gyroSample, &lastGyroSample, sizeof(gyroSample)) == 0) { if (memcmp(&gyroSample, &lastGyroSample, sizeof(gyroSample)) == 0) {
NSLog(@"gyro returned here");
return; return;
} }
controller.lastGyroSample = gyroSample; voidController.lastGyroSample = gyroSample;
// Convert rad/s to deg/s // Convert rad/s to deg/s
LiSendControllerMotionEvent((uint8_t)controller.controllerNumber, 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, LI_MOTION_TYPE_GYRO,
gyroSample.x * 57.2957795f * self->_gyroSensitivity, gyroSample.x * 57.2957795f * self->_gyroSensitivity,
gyroSample.z * 57.2957795f * self->_gyroSensitivity, gyroSample.z * 57.2957795f * self->_gyroSensitivity,
gyroSample.y * -57.2957795f * self->_gyroSensitivity); gyroSample.y * -57.2957795f * self->_gyroSensitivity);
}]; }];
// });
});}
} }
break; 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 { - (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz {
if (@available(iOS 14.0, tvOS 14.0, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
NSLog(@"gyroMode: %ld", (long)_gyroMode); NSLog(@"gyroMode: %ld", (long)_gyroMode);
Controller* controller = [_controllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; VoidController* voidController = [_voidControllers objectForKey:[NSNumber numberWithInteger:controllerNumber]];
//using device motion //using device motion
if (controller == nil) { if (voidController == nil || _gyroMode == AlwaysDevice) {
// No connected controller for this player, use the _oscController instead // 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)];
controller.reportRateHz = reportRateHz;
controller.controllerNumber = controllerNumber;
NSLog(@"device gyro codes, %@, add motion type: %d, %@", controller.motionTypes, motionType, controller);
if(controller != _oscController) [self updateTimerStateForController:controller]; voidController.controllerNumber = controllerNumber;
NSLog(@"device gyro codes, %@, add motion type: %d, gyro obj: %@, is osc: %d", voidController.motionTypes, motionType, voidController, voidController == _oscController);
if(voidController == _oscController) [self updateTimerStateForController:voidController];
// [self updateTimerStateForController:voidController];
// built-in gyro will be fired somewhere else // 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 { -(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, *)) { 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) { if (controller == nil) {
// No connected controller for this player // No connected controller for this player
return; 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) { @synchronized(controller) {
controller.lastLeftStickX = x; 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) { @synchronized(controller) {
controller.lastRightStickX = x; 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) { @synchronized(controller) {
controller.lastLeftTrigger = left; controller.lastLeftTrigger = left;
} }
} }
-(void) updateRightTrigger:(Controller*)controller right:(unsigned char)right -(void) updateRightTrigger:(VoidController*)controller right:(unsigned char)right
{ {
@synchronized(controller) { @synchronized(controller) {
controller.lastRightTrigger = right; 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) { @synchronized(controller) {
controller.lastLeftTrigger = left; 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))) { if ((controller.emulatingButtonFlags & EMULATING_SELECT) && (releasedButtons & (LB_FLAG | PLAY_FLAG))) {
controller.lastButtonFlags &= ~BACK_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 // Special button combos for select and special
if (controller.lastButtonFlags & PLAY_FLAG) { 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) { @synchronized(controller) {
controller.lastButtonFlags = flags; 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) { @synchronized(controller) {
controller.lastButtonFlags |= flags; 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) { @synchronized(controller) {
controller.lastButtonFlags &= ~flags; controller.lastButtonFlags &= ~flags;
@@ -437,7 +488,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
return (_multiController ? _controllerNumbers : 1) | (_oscEnabled ? 1 : 0); return (_multiController ? _controllerNumbers : 1) | (_oscEnabled ? 1 : 0);
} }
-(void) updateFinished:(Controller*)controller -(void) updateFinished:(VoidController*)controller
{ {
BOOL exitRequested = NO; 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.lowFreqMotor = [HapticContext createContextForLowFreqMotor:controller.gamepad];
controller.highFreqMotor = [HapticContext createContextForHighFreqMotor: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]; controller.rightTriggerMotor = [HapticContext createContextForRightTrigger:controller.gamepad];
} }
-(void) cleanupControllerHaptics:(Controller*) controller -(void) cleanupControllerHaptics:(VoidController*) controller
{ {
[controller.lowFreqMotor cleanup]; [controller.lowFreqMotor cleanup];
[controller.highFreqMotor cleanup]; [controller.highFreqMotor cleanup];
@@ -549,7 +600,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[controller.rightTriggerMotor cleanup]; [controller.rightTriggerMotor cleanup];
} }
-(void) cleanupControllerMotion:(Controller*) controller -(void) cleanupControllerMotion:(VoidController*) controller
{ {
if (@available(iOS 14.0, tvOS 14.0, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
// Stop sensor sampling timers // 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 (@available(iOS 14.0, tvOS 14.0, *)) {
if (controller.gamepad.battery) { 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, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
[controller.batteryTimer invalidate]; [controller.batteryTimer invalidate];
} }
} }
-(BOOL) reportControllerArrival:(Controller*) limeController -(BOOL) reportControllerArrival:(VoidController*) limeController
{ {
// Only report arrival once // Only report arrival once
if (limeController.reportedArrival) { if (limeController.reportedArrival) {
@@ -770,7 +821,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
return YES; 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; 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) { if (useLegacyPausedHandler) {
controller.controllerPausedHandler = ^(GCController *controller) { 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 // 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), ^{
@@ -854,7 +905,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
} }
controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) { 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 leftStickX, leftStickY;
short rightStickX, rightStickY; short rightStickX, rightStickY;
unsigned char leftTrigger, rightTrigger; unsigned char leftTrigger, rightTrigger;
@@ -1109,26 +1160,46 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[self updateAutoOnScreenControlMode]; [self updateAutoOnScreenControlMode];
} }
-(Controller*) assignController:(GCController*)controller { -(VoidController* )controllerHasBeenAssignedDeprecated:(GCController*)controller{
for (int i = 0; i < 4; i++) { if(controller.playerIndex == 0) return nil;
if (!(_controllerNumbers & (1 << i))) { if(controller.playerIndex > 0){
_controllerNumbers |= (1 << i); for(VoidController* voidController in _voidControllers){
controller.playerIndex = i; if(voidController.gamepad == controller) return voidController;
}
}
return nil;
}
Controller* limeController = [[Controller alloc] init];
limeController.playerIndex = i; - (void)updateVoidController:(VoidController* )voidController withGCController:(GCController* )controller{
limeController.supportedEmulationFlags = EMULATING_SPECIAL | EMULATING_SELECT; voidController.playerIndex = controller.playerIndex == -1 ? 0 : (uint8_t) controller.playerIndex;
limeController.gamepad = controller; 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 // If this is player 0, it shares state with the OSC
limeController.mergedWithController = _oscController; voidController.mergedWithController = _oscController;
_oscController.mergedWithController = limeController; _oscController.mergedWithController = voidController;
if (@available(iOS 13.0, tvOS 13.0, *)) { if (@available(iOS 13.0, tvOS 13.0, *)) {
if (controller.extendedGamepad != nil && if (controller.extendedGamepad != nil &&
controller.extendedGamepad.buttonOptions != nil) { controller.extendedGamepad.buttonOptions != nil) {
// Disable select button emulation since we have a physical select button // Disable select button emulation since we have a physical select button
limeController.supportedEmulationFlags &= ~EMULATING_SELECT; voidController.supportedEmulationFlags &= ~EMULATING_SELECT;
} }
} }
@@ -1136,24 +1207,59 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
if (controller.extendedGamepad != nil && if (controller.extendedGamepad != nil &&
controller.extendedGamepad.buttonHome != nil) { controller.extendedGamepad.buttonHome != nil) {
// Disable special button emulation since we have a physical special button // Disable special button emulation since we have a physical special button
limeController.supportedEmulationFlags &= ~EMULATING_SPECIAL; voidController.supportedEmulationFlags &= ~EMULATING_SPECIAL;
} }
} }
// Prepare controller haptics for use // Prepare controller haptics for use
[self initializeControllerHaptics:limeController]; [self initializeControllerHaptics:voidController];
}
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
-(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;
[self updateVoidController:voidController withGCController:controller];
// if(![_controllers.allValues containsObject:limeController])
[_voidControllers setObject:voidController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
Log(LOG_I, @"Assigning controller index: %d", i); Log(LOG_I, @"Assigning controller index: %d", i);
return limeController;
return voidController;
} }
} }
return nil; return nil;
} }
-(Controller*) getOscController { -(VoidController*) getOscController {
return _oscController; return _oscController;
} }
@@ -1208,15 +1314,31 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
-(NSUInteger) getConnectedGamepadCount -(NSUInteger) getConnectedGamepadCount
{ {
return _controllers.count; return _voidControllers.count;
} }
-(void)updateConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)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; _multiController = streamConfig.multiController;
_swapABXYButtons = streamConfig.swapABXYButtons; _swapABXYButtons = streamConfig.swapABXYButtons;
_gyroMode = streamConfig.gyroMode;
if(!_oscController) _oscController = [[Controller alloc] init];
_oscController.playerIndex = 0; _oscController.playerIndex = 0;
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
@@ -1224,21 +1346,81 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
TemporarySettings* currentSettings = [dataMan getSettings]; TemporarySettings* currentSettings = [dataMan getSettings];
_oscEnabled = true; _oscEnabled = true;
_gyroSensitivity = currentSettings.gyroSensitivity.floatValue; _gyroSensitivity = currentSettings.gyroSensitivity.floatValue;
}
- (void)updateConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)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, @"Number of supported controllers connected: %d", [ControllerSupport getGamepadCount]);
Log(LOG_I, @"Multi-controller: %d", _multiController); Log(LOG_I, @"Multi-controller: %d", _multiController);
for (GCController* controller in [GCController controllers]) {
if ([ControllerSupport isSupportedGamepad:controller]) {
[self assignController:controller];
[self registerControllerCallbacks:controller];
// Note: We cannot report controller arrival to the host here, if (@available(iOS 14.0, tvOS 14.0, *)) {
// because the connection has not been established yet. 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(), ^{
// [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<ControllerSupportDelegate>)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); _captureMouse = (streamConfig.localMousePointerMode == 0);
if (@available(iOS 14.0, tvOS 14.0, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
for (GCMouse* mouse in [GCMouse mice]) { for (GCMouse* mouse in [GCMouse mice]) {
@@ -1256,7 +1438,8 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
return; return;
} }
Controller* limeController = [self assignController:controller]; //[self->_activeGCControllers addObject:controller];
VoidController* limeController = [self assignController:controller];
if (limeController) { if (limeController) {
// Register callbacks on the new controller // Register callbacks on the new controller
[self registerControllerCallbacks:controller]; [self registerControllerCallbacks:controller];
@@ -1265,12 +1448,12 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
[self reportControllerArrival:limeController]; [self reportControllerArrival:limeController];
// Re-evaluate the on-screen control mode // Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode]; //[self updateAutoOnScreenControlMode];
// Notify the delegate // Notify the delegate
[self->_delegate gamepadPresenceChanged]; [self->_delegate gamepadPresenceChanged];
} }
}]; }];
_controllerDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { _controllerDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Log(LOG_I, @"Controller disconnected!"); Log(LOG_I, @"Controller disconnected!");
@@ -1283,28 +1466,31 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
} }
[self unregisterControllerCallbacks:controller]; [self unregisterControllerCallbacks:controller];
if([self->_activeGCControllers containsObject:controller]){
[self->_activeGCControllers removeObject:controller];
self->_controllerNumbers &= ~(1 << controller.playerIndex); self->_controllerNumbers &= ~(1 << controller.playerIndex);
}
Log(LOG_I, @"Unassigning controller index: %ld", (long)controller.playerIndex); Log(LOG_I, @"Unassigning controller index: %ld", (long)controller.playerIndex);
Controller* limeController = [self->_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; VoidController* voidController = [self->_voidControllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
if (limeController) { if (voidController) {
// Stop haptics on this controller // Stop haptics on this controller
[self cleanupControllerHaptics:limeController]; [self cleanupControllerHaptics:voidController];
// Stop motion reports on this controller // Stop motion reports on this controller
[self cleanupControllerMotion:limeController]; [self cleanupControllerMotion:voidController];
// Stop battery reports on this controller // Stop battery reports on this controller
[self cleanupControllerBattery:limeController]; [self cleanupControllerBattery:voidController];
// Disassociate this controller from any controllers merged with it // Disassociate this controller from any controllers merged with it
if (limeController.mergedWithController) { if (voidController.mergedWithController) {
assert(limeController.mergedWithController.mergedWithController == limeController); if(voidController.mergedWithController.mergedWithController == voidController) voidController.mergedWithController.mergedWithController = nil;
limeController.mergedWithController.mergedWithController = nil;
} }
// Inform the server of the updated active gamepads before removing this controller // 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 // Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode]; [self updateAutoOnScreenControlMode];
@@ -1315,6 +1501,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
}]; }];
if (@available(iOS 14.0, tvOS 14.0, *)) { if (@available(iOS 14.0, tvOS 14.0, *)) {
_mouseConnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { _mouseConnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Log(LOG_I, @"Mouse connected!"); Log(LOG_I, @"Mouse connected!");
@@ -1355,51 +1542,67 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
// Re-evaluate the on-screen control mode // Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode]; [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];
for(Controller* controller in _controllers) [self updateTimerStateForController:controller];
if(_controllers.count == 0) [self updateTimerStateForController:_oscController];
} }
}
-(id)initWithConfig:(StreamConfiguration*)streamConfig delegate:(id<ControllerSupportDelegate>)delegate
{
self = [super init]; _oscController = [[VoidController alloc] init];
_delegate = delegate; _gyroMode = AlwaysDevice;
_controllerStreamLock = [[NSLock alloc] init];
_controllers = [[NSMutableDictionary alloc] init]; [self updateCommonConfig:streamConfig];
_controllerNumbers = 0;
[self updateConfig:streamConfig delegate:delegate]; 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; return self;
} }
-(void) connectionEstablished{ -(void)connectionEstablished{
for (Controller* controller in [_controllers allValues]){ [self updateTimerStateForController:self->_oscController];
// 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)),
dispatch_get_main_queue(), ^{
[self setButtonFlag:self->_oscController flags:A_FLAG]; [self setButtonFlag:self->_oscController flags:A_FLAG];
[self updateFinished:self->_oscController]; [self updateFinished:self->_oscController];
[self clearButtonFlag:self->_oscController flags:A_FLAG]; [self clearButtonFlag:self->_oscController flags:A_FLAG];
[self updateFinished:self->_oscController]; [self updateFinished:self->_oscController];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{ 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->_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->_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{ -(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 invalidate];
controller.accelTimer = nil; controller.accelTimer = nil;
}
if(controller.hasGyroscope){
[controller.gyroTimer invalidate]; [controller.gyroTimer invalidate];
controller.gyroTimer = nil; controller.gyroTimer = nil;
}
}
} }
-(void) cleanup -(void) cleanup
@@ -1420,13 +1623,14 @@ static const double MOUSE_SPEED_DIVISOR = 1.25;
_controllerNumbers = 0; _controllerNumbers = 0;
for (Controller* controller in [_controllers allValues]) { [self stopTimerForController:_oscController];
for (VoidController* controller in [_voidControllers allValues]) {
[self stopTimerForController:controller]; [self stopTimerForController:controller];
[self cleanupControllerHaptics:controller]; [self cleanupControllerHaptics:controller];
[self cleanupControllerMotion:controller]; [self cleanupControllerMotion:controller];
[self cleanupControllerBattery:controller]; [self cleanupControllerBattery:controller];
} }
[_controllers removeAllObjects]; [_voidControllers removeAllObjects];
#if !TARGET_OS_TV #if !TARGET_OS_TV
[self cleanupControllerMotion:_oscController]; [self cleanupControllerMotion:_oscController];
+2 -2
View File
@@ -11,7 +11,7 @@
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "CustomTapGestureRecognizer.h" #import "CustomTapGestureRecognizer.h"
#import "Controller.h" #import "VoidController.h"
#include "Limelight.h" #include "Limelight.h"
#if !TARGET_OS_TV #if !TARGET_OS_TV
#import <CoreMotion/CoreMotion.h> #import <CoreMotion/CoreMotion.h>
@@ -70,7 +70,7 @@ static NSSet *validPositionButtonNames;
BOOL _visible; BOOL _visible;
ControllerSupport *_controllerSupport; ControllerSupport *_controllerSupport;
Controller *_controller; VoidController *_controller;
NSMutableArray* _deadTouches; NSMutableArray* _deadTouches;
BOOL _swapABXY; BOOL _swapABXY;
BOOL _largerStickLR1; BOOL _largerStickLR1;
@@ -14,7 +14,7 @@
@import CoreMotion; @import CoreMotion;
#endif #endif
@interface Controller : NSObject @interface VoidController : NSObject
typedef struct { typedef struct {
float lastX; float lastX;
@@ -64,11 +64,13 @@ typedef NS_ENUM(NSInteger, ControllerDeviceBatteryState) {
@property (nonatomic) float lastBatteryLevel; @property (nonatomic) float lastBatteryLevel;
@property (nonatomic) BOOL reportedArrival; @property (nonatomic) BOOL reportedArrival;
@property (nonatomic) Controller* _Nullable mergedWithController; @property (nonatomic) VoidController* _Nullable mergedWithController;
@property(nonatomic, strong) NSMutableSet* _Nullable motionTypes; @property(nonatomic, strong) NSMutableSet* _Nullable motionTypes;
@property(nonatomic, assign) uint16_t reportRateHz; @property(nonatomic, assign) uint16_t reportRateHz;
@property(nonatomic, assign) uint16_t controllerNumber; @property(nonatomic, assign) uint16_t controllerNumber;
@property(nonatomic, assign) BOOL hasAccelerometer;
@property(nonatomic, assign) BOOL hasGyroscope;
@end @end
@@ -6,8 +6,8 @@
// Copyright © 2019 Moonlight Game Streaming Project. All rights reserved. // Copyright © 2019 Moonlight Game Streaming Project. All rights reserved.
// //
#include "Controller.h" #include "VoidController.h"
@implementation Controller @implementation VoidController
@end @end
@@ -57,6 +57,7 @@
StreamView *_streamView; StreamView *_streamView;
UIScrollView *_scrollView; UIScrollView *_scrollView;
BOOL _userIsInteracting; BOOL _userIsInteracting;
bool viewJustLoaded;
CGSize _keyboardSize; CGSize _keyboardSize;
UIWindow *_extWindow; UIWindow *_extWindow;
UIView *_streamVideoRenderView; 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->_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 [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. [_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 // we got self.view passed to streamView class as the topLayerView, will be useful in many cases
[self->_streamView reloadOnScreenControlsRealtimeWith:(ControllerSupport*)_controllerSupport [self->_streamView reloadOnScreenControlsRealtimeWith:(ControllerSupport*)_controllerSupport
@@ -215,7 +219,7 @@
NSLog(@"streamview gestures: %d", (uint32_t)[_streamView.gestureRecognizers count]); 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 [_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 - (void)viewDidLoad
{ {
viewJustLoaded = true;
[super viewDidLoad]; [super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:YES]; [self.navigationController setNavigationBarHidden:YES animated:YES];