From 93119f25a680cba54f1ec327a2981510f917dbd7 Mon Sep 17 00:00:00 2001 From: Diego Waxemberg Date: Mon, 2 Feb 2015 02:42:38 -0500 Subject: [PATCH] added support for multiple controllers --- Limelight.xcodeproj/project.pbxproj | 6 + Limelight/Input/Controller.h | 22 ++ Limelight/Input/Controller.m | 15 ++ Limelight/Input/ControllerSupport.h | 19 +- Limelight/Input/ControllerSupport.m | 247 ++++++++++-------- Limelight/Input/OnScreenControls.m | 90 ++++--- .../StreamFrameViewController.m | 1 + limelight-common-c | 2 +- 8 files changed, 237 insertions(+), 165 deletions(-) create mode 100644 Limelight/Input/Controller.h create mode 100644 Limelight/Input/Controller.m diff --git a/Limelight.xcodeproj/project.pbxproj b/Limelight.xcodeproj/project.pbxproj index e215a71..1bb0904 100644 --- a/Limelight.xcodeproj/project.pbxproj +++ b/Limelight.xcodeproj/project.pbxproj @@ -64,6 +64,7 @@ FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; }; FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; }; FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; }; + FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD421A7F0C6900872C98 /* Controller.m */; }; FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; }; FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; }; FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; }; @@ -265,6 +266,8 @@ FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = ""; }; FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = ""; }; FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = ""; }; + FB9AFD411A7F0C6900872C98 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = ""; }; + FB9AFD421A7F0C6900872C98 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = ""; }; FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = ""; }; FBD3494219FC9C04002D2A60 /* AppAssetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetManager.m; sourceTree = ""; }; FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; @@ -460,6 +463,8 @@ children = ( FB89460A19F646E200339C8A /* ControllerSupport.h */, FB89460B19F646E200339C8A /* ControllerSupport.m */, + FB9AFD411A7F0C6900872C98 /* Controller.h */, + FB9AFD421A7F0C6900872C98 /* Controller.m */, FB89460C19F646E200339C8A /* StreamView.h */, FB89460D19F646E200339C8A /* StreamView.m */, FB4678EB1A50C40900377732 /* OnScreenControls.h */, @@ -894,6 +899,7 @@ FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */, FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */, FB290D0019B2C406004C83CF /* main.m in Sources */, + FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */, FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */, FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, diff --git a/Limelight/Input/Controller.h b/Limelight/Input/Controller.h new file mode 100644 index 0000000..cc3289b --- /dev/null +++ b/Limelight/Input/Controller.h @@ -0,0 +1,22 @@ +// +// Controller.h +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import + +@interface Controller : NSObject + +@property (nonatomic) int playerIndex; +@property (nonatomic) int lastButtonFlags; +@property (nonatomic) char lastLeftTrigger; +@property (nonatomic) char lastRightTrigger; +@property (nonatomic) short lastLeftStickX; +@property (nonatomic) short lastLeftStickY; +@property (nonatomic) short lastRightStickX; +@property (nonatomic) short lastRightStickY; + +@end diff --git a/Limelight/Input/Controller.m b/Limelight/Input/Controller.m new file mode 100644 index 0000000..e261a50 --- /dev/null +++ b/Limelight/Input/Controller.m @@ -0,0 +1,15 @@ +// +// Controller.m +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "Controller.h" + +@implementation Controller +@synthesize playerIndex; +@synthesize lastButtonFlags, lastLeftTrigger, lastRightTrigger; +@synthesize lastLeftStickX, lastLeftStickY, lastRightStickX, lastRightStickY; +@end diff --git a/Limelight/Input/ControllerSupport.h b/Limelight/Input/ControllerSupport.h index cf7b38c..ad82d87 100644 --- a/Limelight/Input/ControllerSupport.h +++ b/Limelight/Input/ControllerSupport.h @@ -7,6 +7,7 @@ // #import +#import "Controller.h" @class OnScreenControls; @@ -16,18 +17,18 @@ -(void) initAutoOnScreenControlMode:(OnScreenControls*)osc; -(void) cleanup; --(void) updateLeftStick:(short)x y:(short)y; --(void) updateRightStick:(short)x y:(short)y; +-(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y; +-(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y; --(void) updateLeftTrigger:(char)left; --(void) updateRightTrigger:(char)right; --(void) updateTriggers:(char)left right:(char)right; +-(void) updateLeftTrigger:(Controller*)controller left:(char)left; +-(void) updateRightTrigger:(Controller*)controller right:(char)right; +-(void) updateTriggers:(Controller*)controller left:(char)left right:(char)right; --(void) updateButtonFlags:(int)flags; --(void) setButtonFlag:(int)flags; --(void) clearButtonFlag:(int)flags; +-(void) updateButtonFlags:(Controller*)controller flags:(int)flags; +-(void) setButtonFlag:(Controller*)controller flags:(int)flags; +-(void) clearButtonFlag:(Controller*)controller flags:(int)flags; --(void) updateFinished; +-(void) updateFinished:(Controller*)controller; @property (nonatomic, strong) id connectObserver; @property (nonatomic, strong) id disconnectObserver; diff --git a/Limelight/Input/ControllerSupport.m b/Limelight/Input/ControllerSupport.m index 64d2688..1440c86 100644 --- a/Limelight/Input/ControllerSupport.m +++ b/Limelight/Input/ControllerSupport.m @@ -8,20 +8,18 @@ #import "ControllerSupport.h" #import "OnScreenControls.h" +#import "Controller.h" #include "Limelight.h" @import GameController; @implementation ControllerSupport { - NSLock *_controllerValueLock; NSLock *_controllerStreamLock; + NSMutableDictionary *_controllers; OnScreenControls *_osc; - int _lastButtonFlags; - char _lastLeftTrigger, _lastRightTrigger; - short _lastLeftStickX, _lastLeftStickY; - short _lastRightStickX, _lastRightStickY; + char _controllerNumbers; #define EMULATING_SELECT 0x1 #define EMULATING_SPECIAL 0x2 @@ -29,122 +27,121 @@ } // UPDATE_BUTTON_FLAG(flag, pressed) -#define UPDATE_BUTTON_FLAG(x, y) \ - ((y) ? [self setButtonFlag:x] : [self clearButtonFlag:x]) +#define UPDATE_BUTTON_FLAG(controller, x, y) \ +((y) ? [self setButtonFlag:controller flags:x] : [self clearButtonFlag:controller flags:x]) --(void) updateLeftStick:(short)x y:(short)y +-(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y { - [_controllerValueLock lock]; - _lastLeftStickX = x; - _lastLeftStickY = y; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastLeftStickX = x; + controller.lastLeftStickY = y; + } } --(void) updateRightStick:(short)x y:(short)y +-(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y { - [_controllerValueLock lock]; - _lastRightStickX = x; - _lastRightStickY = y; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastRightStickX = x; + controller.lastRightStickY = y; + } } --(void) updateLeftTrigger:(char)left +-(void) updateLeftTrigger:(Controller*)controller left:(char)left { - [_controllerValueLock lock]; - _lastLeftTrigger = left; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastLeftTrigger = left; + } } --(void) updateRightTrigger:(char)right +-(void) updateRightTrigger:(Controller*)controller right:(char)right { - [_controllerValueLock lock]; - _lastRightTrigger = right; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastRightTrigger = right; + } } --(void) updateTriggers:(char)left right:(char)right +-(void) updateTriggers:(Controller*) controller left:(char)left right:(char)right { - [_controllerValueLock lock]; - _lastLeftTrigger = left; - _lastRightTrigger = right; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastLeftTrigger = left; + controller.lastRightTrigger = right; + } } --(void) handleSpecialCombosReleased:(int)releasedButtons +-(void) handleSpecialCombosReleased:(Controller*)controller releasedButtons:(int)releasedButtons { if ((_emulatingButtonFlags & EMULATING_SELECT) && ((releasedButtons & LB_FLAG) || (releasedButtons & PLAY_FLAG))) { - _lastButtonFlags &= ~BACK_FLAG; + controller.lastButtonFlags &= ~BACK_FLAG; _emulatingButtonFlags &= ~EMULATING_SELECT; } if ((_emulatingButtonFlags & EMULATING_SPECIAL) && ((releasedButtons & RB_FLAG) || (releasedButtons & PLAY_FLAG) || (releasedButtons & BACK_FLAG))) { - _lastButtonFlags &= ~SPECIAL_FLAG; - _emulatingButtonFlags &= ~EMULATING_SPECIAL; - } + controller.lastButtonFlags &= ~SPECIAL_FLAG; + _emulatingButtonFlags &= ~EMULATING_SPECIAL; + } } --(void) handleSpecialCombosPressed:(int)pressedButtons +-(void) handleSpecialCombosPressed:(Controller*)controller pressedButtons:(int)pressedButtons { // Special button combos for select and special - if (_lastButtonFlags & PLAY_FLAG) { + if (controller.lastButtonFlags & PLAY_FLAG) { // If LB and start are down, trigger select - if (_lastButtonFlags & LB_FLAG) { - _lastButtonFlags |= BACK_FLAG; - _lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | LB_FLAG)); + if (controller.lastButtonFlags & LB_FLAG) { + controller.lastButtonFlags |= BACK_FLAG; + controller.lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | LB_FLAG)); _emulatingButtonFlags |= EMULATING_SELECT; } // If (RB or select) and start are down, trigger special - else if ((_lastButtonFlags & RB_FLAG) || (_lastButtonFlags & BACK_FLAG)) { - _lastButtonFlags |= SPECIAL_FLAG; - _lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | RB_FLAG | BACK_FLAG)); + else if ((controller.lastButtonFlags & RB_FLAG) || (controller.lastButtonFlags & BACK_FLAG)) { + controller.lastButtonFlags |= SPECIAL_FLAG; + controller.lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | RB_FLAG | BACK_FLAG)); _emulatingButtonFlags |= EMULATING_SPECIAL; } } + } --(void) updateButtonFlags:(int)flags +-(void) updateButtonFlags:(Controller*)controller flags:(int)flags { - [_controllerValueLock lock]; - int releasedButtons = (_lastButtonFlags ^ flags) & ~flags; - int pressedButtons = (_lastButtonFlags ^ flags) & flags; - - _lastButtonFlags = flags; - - // This must be called before handleSpecialCombosPressed - // because we clear the original button flags there - [self handleSpecialCombosReleased: releasedButtons]; - - [self handleSpecialCombosPressed: pressedButtons]; - - [_controllerValueLock unlock]; + @synchronized(controller) { + int releasedButtons = (controller.lastButtonFlags ^ flags) & ~flags; + int pressedButtons = (controller.lastButtonFlags ^ flags) & flags; + + controller.lastButtonFlags = flags; + + // This must be called before handleSpecialCombosPressed + // because we clear the original button flags there + [self handleSpecialCombosReleased:controller releasedButtons:releasedButtons]; + + [self handleSpecialCombosPressed:controller pressedButtons:pressedButtons]; + + } } --(void) setButtonFlag:(int)flags +-(void) setButtonFlag:(Controller*)controller flags:(int)flags { - [_controllerValueLock lock]; - _lastButtonFlags |= flags; - [self handleSpecialCombosPressed: flags]; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastButtonFlags |= flags; + [self handleSpecialCombosPressed:controller pressedButtons:flags]; + } } --(void) clearButtonFlag:(int)flags +-(void) clearButtonFlag:(Controller*)controller flags:(int)flags { - [_controllerValueLock lock]; - _lastButtonFlags &= ~flags; - [self handleSpecialCombosReleased: flags]; - [_controllerValueLock unlock]; + @synchronized(controller) { + controller.lastButtonFlags &= ~flags; + [self handleSpecialCombosReleased:controller releasedButtons:flags]; + } } --(void) updateFinished +-(void) updateFinished:(Controller*)controller { [_controllerStreamLock lock]; - [_controllerValueLock lock]; - - LiSendControllerEvent(_lastButtonFlags, _lastLeftTrigger, _lastRightTrigger, _lastLeftStickX, _lastLeftStickY, _lastRightStickX, _lastRightStickY); - - [_controllerValueLock unlock]; + @synchronized(controller) { + LiSendControllerEvent(controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY); + } [_controllerStreamLock unlock]; } @@ -164,6 +161,7 @@ } } } + [_controllers removeAllObjects]; } -(void) registerControllerCallbacks @@ -172,36 +170,37 @@ GCController *controller = [GCController controllers][i]; if (controller != NULL) { - NSLog(@"Controller connected!"); controller.controllerPausedHandler = ^(GCController *controller) { - [self setButtonFlag:PLAY_FLAG]; - [self updateFinished]; + Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; + [self setButtonFlag:limeController flags:PLAY_FLAG]; + [self updateFinished:limeController]; // Pause for 100 ms usleep(100 * 1000); - [self clearButtonFlag:PLAY_FLAG]; - [self updateFinished]; + [self clearButtonFlag:limeController flags:PLAY_FLAG]; + [self updateFinished:limeController]; }; if (controller.extendedGamepad != NULL) { controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) { + Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]]; short leftStickX, leftStickY; short rightStickX, rightStickY; char leftTrigger, rightTrigger; - UPDATE_BUTTON_FLAG(A_FLAG, gamepad.buttonA.pressed); - UPDATE_BUTTON_FLAG(B_FLAG, gamepad.buttonB.pressed); - UPDATE_BUTTON_FLAG(X_FLAG, gamepad.buttonX.pressed); - UPDATE_BUTTON_FLAG(Y_FLAG, gamepad.buttonY.pressed); + UPDATE_BUTTON_FLAG(limeController, A_FLAG, gamepad.buttonA.pressed); + UPDATE_BUTTON_FLAG(limeController, B_FLAG, gamepad.buttonB.pressed); + UPDATE_BUTTON_FLAG(limeController, X_FLAG, gamepad.buttonX.pressed); + UPDATE_BUTTON_FLAG(limeController, Y_FLAG, gamepad.buttonY.pressed); - UPDATE_BUTTON_FLAG(UP_FLAG, gamepad.dpad.up.pressed); - UPDATE_BUTTON_FLAG(DOWN_FLAG, gamepad.dpad.down.pressed); - UPDATE_BUTTON_FLAG(LEFT_FLAG, gamepad.dpad.left.pressed); - UPDATE_BUTTON_FLAG(RIGHT_FLAG, gamepad.dpad.right.pressed); + UPDATE_BUTTON_FLAG(limeController, UP_FLAG, gamepad.dpad.up.pressed); + UPDATE_BUTTON_FLAG(limeController, DOWN_FLAG, gamepad.dpad.down.pressed); + UPDATE_BUTTON_FLAG(limeController, LEFT_FLAG, gamepad.dpad.left.pressed); + UPDATE_BUTTON_FLAG(limeController, RIGHT_FLAG, gamepad.dpad.right.pressed); - UPDATE_BUTTON_FLAG(LB_FLAG, gamepad.leftShoulder.pressed); - UPDATE_BUTTON_FLAG(RB_FLAG, gamepad.rightShoulder.pressed); + UPDATE_BUTTON_FLAG(limeController, LB_FLAG, gamepad.leftShoulder.pressed); + UPDATE_BUTTON_FLAG(limeController, RB_FLAG, gamepad.rightShoulder.pressed); leftStickX = gamepad.leftThumbstick.xAxis.value * 0x7FFE; leftStickY = gamepad.leftThumbstick.yAxis.value * 0x7FFE; @@ -212,34 +211,34 @@ leftTrigger = gamepad.leftTrigger.value * 0xFF; rightTrigger = gamepad.rightTrigger.value * 0xFF; - [self updateLeftStick:leftStickX y:leftStickY]; - [self updateRightStick:rightStickX y:rightStickY]; - [self updateTriggers:leftTrigger right:rightTrigger]; - [self updateFinished]; + [self updateLeftStick:limeController x:leftStickX y:leftStickY]; + [self updateRightStick:limeController x:rightStickX y:rightStickY]; + [self updateTriggers:limeController left:leftTrigger right:rightTrigger]; + [self updateFinished:limeController]; }; } else if (controller.gamepad != NULL) { controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, GCControllerElement *element) { + Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]]; + UPDATE_BUTTON_FLAG(limeController, A_FLAG, gamepad.buttonA.pressed); + UPDATE_BUTTON_FLAG(limeController, B_FLAG, gamepad.buttonB.pressed); + UPDATE_BUTTON_FLAG(limeController, X_FLAG, gamepad.buttonX.pressed); + UPDATE_BUTTON_FLAG(limeController, Y_FLAG, gamepad.buttonY.pressed); - UPDATE_BUTTON_FLAG(A_FLAG, gamepad.buttonA.pressed); - UPDATE_BUTTON_FLAG(B_FLAG, gamepad.buttonB.pressed); - UPDATE_BUTTON_FLAG(X_FLAG, gamepad.buttonX.pressed); - UPDATE_BUTTON_FLAG(Y_FLAG, gamepad.buttonY.pressed); + UPDATE_BUTTON_FLAG(limeController, UP_FLAG, gamepad.dpad.up.pressed); + UPDATE_BUTTON_FLAG(limeController, DOWN_FLAG, gamepad.dpad.down.pressed); + UPDATE_BUTTON_FLAG(limeController, LEFT_FLAG, gamepad.dpad.left.pressed); + UPDATE_BUTTON_FLAG(limeController, RIGHT_FLAG, gamepad.dpad.right.pressed); - UPDATE_BUTTON_FLAG(UP_FLAG, gamepad.dpad.up.pressed); - UPDATE_BUTTON_FLAG(DOWN_FLAG, gamepad.dpad.down.pressed); - UPDATE_BUTTON_FLAG(LEFT_FLAG, gamepad.dpad.left.pressed); - UPDATE_BUTTON_FLAG(RIGHT_FLAG, gamepad.dpad.right.pressed); + UPDATE_BUTTON_FLAG(limeController, LB_FLAG, gamepad.leftShoulder.pressed); + UPDATE_BUTTON_FLAG(limeController, RB_FLAG, gamepad.rightShoulder.pressed); - UPDATE_BUTTON_FLAG(LB_FLAG, gamepad.leftShoulder.pressed); - UPDATE_BUTTON_FLAG(RB_FLAG, gamepad.rightShoulder.pressed); - - [self updateFinished]; + [self updateFinished:limeController]; }; } } } - + } -(void) updateAutoOnScreenControlMode @@ -278,14 +277,40 @@ [self updateAutoOnScreenControlMode]; } +-(void) assignController:(GCController*)controller { + for (int i = 0; i < 4; i++) { + if (!(_controllerNumbers & (1 << i))) { + _controllerNumbers |= (1 << i); + Controller* limeController = [[Controller alloc] init]; + controller.playerIndex = i; + limeController.playerIndex = i; + [_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]]; + + NSLog(@"Assigning controller index: %d", i); + break; + } + } +} + -(id) init { self = [super init]; _controllerStreamLock = [[NSLock alloc] init]; - _controllerValueLock = [[NSLock alloc] init]; + _controllers = [[NSMutableDictionary alloc] init]; + _controllerNumbers = 0; + + NSLog(@"Number of controllers connected: %ld", [[GCController controllers] count]); + for (GCController* controller in [GCController controllers]) { + [self assignController:controller]; + } self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Controller connected!"); + + GCController* controller = (GCController*) note.object; + [self assignController:controller]; + // Register callbacks on the new controller [self registerControllerCallbacks]; @@ -295,12 +320,10 @@ self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { NSLog(@"Controller disconnected!"); - // Reset all controller state to be safe - [self updateButtonFlags:0]; - [self updateLeftStick:0 y:0]; - [self updateRightStick:0 y:0]; - [self updateTriggers:0 right:0]; - [self updateFinished]; + GCController* controller = note.object; + [_controllers removeObjectForKey:[NSNumber numberWithInteger:controller.playerIndex]]; + _controllerNumbers &= ~(1 << controller.playerIndex); + NSLog(@"Unassigning controller index: %ld", (long)controller.playerIndex); // Re-evaluate the on-screen control mode [self updateAutoOnScreenControlMode]; diff --git a/Limelight/Input/OnScreenControls.m b/Limelight/Input/OnScreenControls.m index 01225d4..67fccc3 100644 --- a/Limelight/Input/OnScreenControls.m +++ b/Limelight/Input/OnScreenControls.m @@ -8,6 +8,7 @@ #import "OnScreenControls.h" #import "ControllerSupport.h" +#import "Controller.h" #include "Limelight.h" #define UPDATE_BUTTON(x, y) (buttonFlags = \ @@ -64,6 +65,7 @@ OnScreenControlsLevel _level; ControllerSupport *_controllerSupport; + Controller *_controller; } static const float BUTTON_SIZE = 50; @@ -117,6 +119,8 @@ static float L3_Y; self = [self init]; _view = view; _controllerSupport = controllerSupport; + _controller = [[Controller alloc] init]; + _controller.playerIndex = 0; _aButton = [CALayer layer]; _bButton = [CALayer layer]; @@ -449,7 +453,7 @@ static float L3_Y; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; - [_controllerSupport updateLeftStick:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; + [_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; updated = true; } else if (touch == _rsTouch) { @@ -466,7 +470,7 @@ static float L3_Y; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; - [_controllerSupport updateRightStick:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; + [_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; updated = true; } else if (touch == _aTouch) { @@ -504,7 +508,7 @@ static float L3_Y; } } if (updated) { - [_controllerSupport updateFinished]; + [_controllerSupport updateFinished:_controller]; } return updated || buttonTouch; } @@ -516,67 +520,67 @@ static float L3_Y; CGPoint touchLocation = [touch locationInView:_view]; if ([_aButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:A_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:A_FLAG]; _aTouch = touch; updated = true; } else if ([_bButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:B_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:B_FLAG]; _bTouch = touch; updated = true; } else if ([_xButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:X_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:X_FLAG]; _xTouch = touch; updated = true; } else if ([_yButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:Y_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:Y_FLAG]; _yTouch = touch; updated = true; } else if ([_upButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:UP_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:UP_FLAG]; _upTouch = touch; updated = true; } else if ([_downButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:DOWN_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG]; _downTouch = touch; updated = true; } else if ([_leftButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:LEFT_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG]; _leftTouch = touch; updated = true; } else if ([_rightButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:RIGHT_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG]; _rightTouch = touch; updated = true; } else if ([_startButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:PLAY_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG]; _startTouch = touch; updated = true; } else if ([_selectButton.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:BACK_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:BACK_FLAG]; _selectTouch = touch; updated = true; } else if ([_l1Button.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:LB_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:LB_FLAG]; _l1Touch = touch; updated = true; } else if ([_r1Button.presentationLayer hitTest:touchLocation]) { - [_controllerSupport setButtonFlag:RB_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:RB_FLAG]; _r1Touch = touch; updated = true; } else if ([_l2Button.presentationLayer hitTest:touchLocation]) { - [_controllerSupport updateLeftTrigger:0xFF]; + [_controllerSupport updateLeftTrigger:_controller left:0xFF]; _l2Touch = touch; updated = true; } else if ([_r2Button.presentationLayer hitTest:touchLocation]) { - [_controllerSupport updateRightTrigger:0xFF]; + [_controllerSupport updateRightTrigger:_controller right:0xFF]; _r2Touch = touch; updated = true; } else if ([_l3Button.presentationLayer hitTest:touchLocation]) { if (l3Set) { - [_controllerSupport clearButtonFlag:LS_CLK_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG]; _l3Button.borderWidth = 0.0f; } else { - [_controllerSupport setButtonFlag:LS_CLK_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG]; _l3Button.borderWidth = 2.0f; } l3Set = !l3Set; @@ -584,10 +588,10 @@ static float L3_Y; updated = true; } else if ([_r3Button.presentationLayer hitTest:touchLocation]) { if (r3Set) { - [_controllerSupport clearButtonFlag:RS_CLK_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG]; _r3Button.borderWidth = 0.0f; } else { - [_controllerSupport setButtonFlag:RS_CLK_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG]; _r3Button.borderWidth = 2.0f; } r3Set = !r3Set; @@ -599,7 +603,7 @@ static float L3_Y; // Use (-) modifier to conversion since receiver is earlier than now double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0; if (l3TouchTime < STICK_CLICK_RATE) { - [_controllerSupport setButtonFlag:LS_CLK_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG]; updated = true; } } @@ -611,7 +615,7 @@ static float L3_Y; // Use (-) modifier to conversion since receiver is earlier than now double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0; if (r3TouchTime < STICK_CLICK_RATE) { - [_controllerSupport setButtonFlag:RS_CLK_FLAG]; + [_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG]; updated = true; } } @@ -620,7 +624,7 @@ static float L3_Y; } } if (updated) { - [_controllerSupport updateFinished]; + [_controllerSupport updateFinished:_controller]; } return updated || stickTouch; } @@ -630,72 +634,72 @@ static float L3_Y; BOOL touched = false; for (UITouch* touch in touches) { if (touch == _aTouch) { - [_controllerSupport clearButtonFlag:A_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:A_FLAG]; _aTouch = nil; updated = true; } else if (touch == _bTouch) { - [_controllerSupport clearButtonFlag:B_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:B_FLAG]; _bTouch = nil; updated = true; } else if (touch == _xTouch) { - [_controllerSupport clearButtonFlag:X_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:X_FLAG]; _xTouch = nil; updated = true; } else if (touch == _yTouch) { - [_controllerSupport clearButtonFlag:Y_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:Y_FLAG]; _yTouch = nil; updated = true; } else if (touch == _upTouch) { - [_controllerSupport clearButtonFlag:UP_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:UP_FLAG]; _upTouch = nil; updated = true; } else if (touch == _downTouch) { - [_controllerSupport clearButtonFlag:DOWN_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG]; _downTouch = nil; updated = true; } else if (touch == _leftTouch) { - [_controllerSupport clearButtonFlag:LEFT_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG]; _leftTouch = nil; updated = true; } else if (touch == _rightTouch) { - [_controllerSupport clearButtonFlag:RIGHT_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG]; _rightTouch = nil; updated = true; } else if (touch == _startTouch) { - [_controllerSupport clearButtonFlag:PLAY_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG]; _startTouch = nil; updated = true; } else if (touch == _selectTouch) { - [_controllerSupport clearButtonFlag:BACK_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:BACK_FLAG]; _selectTouch = nil; updated = true; } else if (touch == _l1Touch) { - [_controllerSupport clearButtonFlag:LB_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:LB_FLAG]; _l1Touch = nil; updated = true; } else if (touch == _r1Touch) { - [_controllerSupport clearButtonFlag:RB_FLAG]; + [_controllerSupport clearButtonFlag:_controller flags:RB_FLAG]; _r1Touch = nil; updated = true; } else if (touch == _l2Touch) { - [_controllerSupport updateLeftTrigger:0]; + [_controllerSupport updateLeftTrigger:_controller left:0]; _l2Touch = nil; updated = true; } else if (touch == _r2Touch) { - [_controllerSupport updateRightTrigger:0]; + [_controllerSupport updateRightTrigger:_controller right:0]; _r2Touch = nil; updated = true; } else if (touch == _lsTouch) { _leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); - [_controllerSupport updateLeftStick:0 y:0]; - [_controllerSupport clearButtonFlag:LS_CLK_FLAG]; + [_controllerSupport updateLeftStick:_controller x:0 y:0]; + [_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG]; l3TouchStart = [NSDate date]; _lsTouch = nil; updated = true; } else if (touch == _rsTouch) { _rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); - [_controllerSupport updateRightStick:0 y:0]; - [_controllerSupport clearButtonFlag:RS_CLK_FLAG]; + [_controllerSupport updateRightStick:_controller x:0 y:0]; + [_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG]; r3TouchStart = [NSDate date]; _rsTouch = nil; updated = true; @@ -710,7 +714,7 @@ static float L3_Y; } } if (updated) { - [_controllerSupport updateFinished]; + [_controllerSupport updateFinished:_controller]; } return updated || touched; } diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index fbbfcf6..84de186 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -49,6 +49,7 @@ } - (void) returnToMainFrame { + [_controllerSupport cleanup]; [self.navigationController popToRootViewControllerAnimated:YES]; } diff --git a/limelight-common-c b/limelight-common-c index 0fa1a02..975be33 160000 --- a/limelight-common-c +++ b/limelight-common-c @@ -1 +1 @@ -Subproject commit 0fa1a02e0a7ac560eff6411b238394459549fd6c +Subproject commit 975be33ff83321265d7e4f5d9f6c44ed49b26cf6