diff --git a/Limelight/Input/ControllerSupport.h b/Limelight/Input/ControllerSupport.h index 0b7dab4..19056c1 100644 --- a/Limelight/Input/ControllerSupport.h +++ b/Limelight/Input/ControllerSupport.h @@ -11,16 +11,17 @@ @class OnScreenControls; -@protocol InputPresenceDelegate +@protocol ControllerSupportDelegate - (void) gamepadPresenceChanged; - (void) mousePresenceChanged; +- (void) streamExitRequested; @end @interface ControllerSupport : NSObject --(id) initWithConfig:(StreamConfiguration*)streamConfig presenceDelegate:(id)delegate; +-(id) initWithConfig:(StreamConfiguration*)streamConfig delegate:(id)delegate; -(void) initAutoOnScreenControlMode:(OnScreenControls*)osc; -(void) cleanup; diff --git a/Limelight/Input/ControllerSupport.m b/Limelight/Input/ControllerSupport.m index fe5f733..5e302ff 100644 --- a/Limelight/Input/ControllerSupport.m +++ b/Limelight/Input/ControllerSupport.m @@ -29,7 +29,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; NSLock *_controllerStreamLock; NSMutableDictionary *_controllers; - id _presenceDelegate; + id _delegate; float accumulatedDeltaX; float accumulatedDeltaY; @@ -200,13 +200,28 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; -(void) updateFinished:(Controller*)controller { + BOOL exitRequested = NO; + [_controllerStreamLock lock]; @synchronized(controller) { + // Handle Start+Select+L1+R1 gamepad quit combo + if (controller.lastButtonFlags == (PLAY_FLAG | BACK_FLAG | LB_FLAG | RB_FLAG)) { + controller.lastButtonFlags = 0; + exitRequested = YES; + } + // Player 1 is always present for OSC LiSendMultiControllerEvent(_multiController ? controller.playerIndex : 0, (_multiController ? _controllerNumbers : 1) | (_oscEnabled ? 1 : 0), controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY); } [_controllerStreamLock unlock]; + + if (exitRequested) { + // Invoke the delegate callback on the main thread + dispatch_async(dispatch_get_main_queue(), ^{ + [self->_delegate streamExitRequested]; + }); + } } +(BOOL) hasKeyboardOrMouse { @@ -645,7 +660,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; return _controllers.count; } --(id) initWithConfig:(StreamConfiguration*)streamConfig presenceDelegate:(id)delegate +-(id) initWithConfig:(StreamConfiguration*)streamConfig delegate:(id)delegate { self = [super init]; @@ -654,7 +669,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; _controllerNumbers = 0; _multiController = streamConfig.multiController; _swapABXYButtons = streamConfig.swapABXYButtons; - _presenceDelegate = delegate; + _delegate = delegate; _player0osc = [[Controller alloc] init]; _player0osc.playerIndex = 0; @@ -697,7 +712,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self updateAutoOnScreenControlMode]; // Notify the delegate - [self->_presenceDelegate gamepadPresenceChanged]; + [self->_delegate gamepadPresenceChanged]; }]; _controllerDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { Log(LOG_I, @"Controller disconnected!"); @@ -729,7 +744,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self updateAutoOnScreenControlMode]; // Notify the delegate - [self->_presenceDelegate gamepadPresenceChanged]; + [self->_delegate gamepadPresenceChanged]; }]; if (@available(iOS 14.0, tvOS 14.0, *)) { @@ -745,7 +760,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self updateAutoOnScreenControlMode]; // Notify the delegate - [self->_presenceDelegate mousePresenceChanged]; + [self->_delegate mousePresenceChanged]; }]; _mouseDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { Log(LOG_I, @"Mouse disconnected!"); @@ -759,7 +774,7 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [self updateAutoOnScreenControlMode]; // Notify the delegate - [self->_presenceDelegate mousePresenceChanged]; + [self->_delegate mousePresenceChanged]; }]; _keyboardConnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCKeyboardDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { Log(LOG_I, @"Keyboard connected!"); diff --git a/Limelight/ViewControllers/StreamFrameViewController.h b/Limelight/ViewControllers/StreamFrameViewController.h index a8a3806..dc9e5a8 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.h +++ b/Limelight/ViewControllers/StreamFrameViewController.h @@ -15,9 +15,9 @@ #if TARGET_OS_TV @import GameController; -@interface StreamFrameViewController : GCEventViewController +@interface StreamFrameViewController : GCEventViewController #else -@interface StreamFrameViewController : UIViewController +@interface StreamFrameViewController : UIViewController #endif @property (nonatomic) StreamConfiguration* streamConfig; diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index a4bb50e..1a30608 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -104,7 +104,7 @@ [_spinner startAnimating]; _spinner.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2 - _stageLabel.frame.size.height - _spinner.frame.size.height); - _controllerSupport = [[ControllerSupport alloc] initWithConfig:self.streamConfig presenceDelegate:self]; + _controllerSupport = [[ControllerSupport alloc] initWithConfig:self.streamConfig delegate:self]; _inactivityTimer = nil; _streamView = [[StreamView alloc] initWithFrame:self.view.frame]; @@ -615,6 +615,12 @@ #endif } +- (void) streamExitRequested { + Log(LOG_I, @"Gamepad combo requested stream exit"); + + [self returnToMainFrame]; +} + - (void)userInteractionBegan { // Disable hiding home bar when user is interacting. // iOS will force it to be shown anyway, but it will