Rewrote a bunch of controller support. Added auto on-screen controls layouts (GCGamepad not finished). Added LB+Start and RB+Start shortcuts for select and special (same as Android).

This commit is contained in:
Cameron Gutman 2015-01-09 16:13:44 -05:00
parent afb7e930ee
commit cdaf98398c
9 changed files with 426 additions and 151 deletions

View File

@ -8,12 +8,27 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@class OnScreenControls;
@interface ControllerSupport : NSObject @interface ControllerSupport : NSObject
-(id) init; -(id) init;
-(void) initAutoOnScreenControlMode:(OnScreenControls*)osc;
-(void) cleanup; -(void) cleanup;
-(void) updateLeftStick:(short)x y:(short)y;
-(void) updateRightStick:(short)x y:(short)y;
-(void) updateLeftTrigger:(char)left;
-(void) updateRightTrigger:(char)right;
-(void) updateTriggers:(char)left right:(char)right;
-(void) updateButtonFlags:(int)flags;
-(void) setButtonFlag:(int)flags;
-(void) clearButtonFlag:(int)flags;
-(void) updateFinished;
@property (nonatomic, strong) id connectObserver; @property (nonatomic, strong) id connectObserver;
@property (nonatomic, strong) id disconnectObserver; @property (nonatomic, strong) id disconnectObserver;

View File

@ -7,19 +7,166 @@
// //
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "OnScreenControls.h"
#include "Limelight.h" #include "Limelight.h"
@import GameController; @import GameController;
@implementation ControllerSupport @implementation ControllerSupport {
NSLock *_controllerValueLock;
NSLock *_controllerStreamLock;
OnScreenControls *_osc;
int _lastButtonFlags;
char _lastLeftTrigger, _lastRightTrigger;
short _lastLeftStickX, _lastLeftStickY;
short _lastRightStickX, _lastRightStickY;
#define EMULATING_SELECT 0x1
#define EMULATING_SPECIAL 0x2
int _emulatingButtonFlags;
}
// UPDATE_BUTTON(flag, pressed) // UPDATE_BUTTON(flag, pressed)
#define UPDATE_BUTTON(x, y) (buttonFlags = \ #define UPDATE_BUTTON(x, y) (buttonFlags = \
(y) ? (buttonFlags | (x)) : (buttonFlags & ~(x))) (y) ? (buttonFlags | (x)) : (buttonFlags & ~(x)))
static NSLock *controllerStreamLock; -(void) updateLeftStick:(short)x y:(short)y
{
[_controllerValueLock lock];
_lastLeftStickX = x;
_lastLeftStickY = y;
[_controllerValueLock unlock];
}
+(void) registerControllerCallbacks -(void) updateRightStick:(short)x y:(short)y
{
[_controllerValueLock lock];
_lastRightStickX = x;
_lastRightStickY = y;
[_controllerValueLock unlock];
}
-(void) updateLeftTrigger:(char)left
{
[_controllerValueLock lock];
_lastLeftTrigger = left;
[_controllerValueLock unlock];
}
-(void) updateRightTrigger:(char)right
{
[_controllerValueLock lock];
_lastRightTrigger = right;
[_controllerValueLock unlock];
}
-(void) updateTriggers:(char)left right:(char)right
{
[_controllerValueLock lock];
_lastLeftTrigger = left;
_lastRightTrigger = right;
[_controllerValueLock unlock];
}
-(void) handleSpecialCombosReleased:(int)releasedButtons
{
if (releasedButtons & PLAY_FLAG) {
if ((_emulatingButtonFlags & EMULATING_SELECT) &&
(releasedButtons & LB_FLAG)) {
_lastButtonFlags &= ~BACK_FLAG;
_emulatingButtonFlags &= ~EMULATING_SELECT;
}
if ((_emulatingButtonFlags & EMULATING_SPECIAL) &&
(releasedButtons & RB_FLAG)) {
_lastButtonFlags &= ~SPECIAL_FLAG;
_emulatingButtonFlags &= ~EMULATING_SPECIAL;
}
}
}
-(void) handleSpecialCombosPressed
{
// Special button combos for select and special
if (_lastButtonFlags & PLAY_FLAG) {
// If LB and start are down, trigger select
if (_lastButtonFlags & LB_FLAG) {
_lastButtonFlags |= BACK_FLAG;
_lastButtonFlags &= ~(PLAY_FLAG | LB_FLAG);
_emulatingButtonFlags |= EMULATING_SELECT;
}
// If RB and start are down, trigger special
else if (_lastButtonFlags & RB_FLAG) {
_lastButtonFlags |= SPECIAL_FLAG;
_lastButtonFlags &= ~(PLAY_FLAG | RB_FLAG);
_emulatingButtonFlags |= EMULATING_SPECIAL;
}
}
}
-(void) updateButtonFlags:(int)flags
{
[_controllerValueLock lock];
int releasedButtons = (_lastButtonFlags ^ flags) & ~flags;
_lastButtonFlags = flags;
// This must be called before handleSpecialCombosPressed
// because we clear the original button flags there
[self handleSpecialCombosReleased: releasedButtons];
[self handleSpecialCombosPressed];
[_controllerValueLock unlock];
}
-(void) setButtonFlag:(int)flags
{
[_controllerValueLock lock];
_lastButtonFlags |= flags;
[self handleSpecialCombosPressed];
[_controllerValueLock unlock];
}
-(void) clearButtonFlag:(int)flags
{
[_controllerValueLock lock];
_lastButtonFlags &= ~flags;
[self handleSpecialCombosReleased: flags];
[_controllerValueLock unlock];
}
-(void) updateFinished
{
[_controllerStreamLock lock];
[_controllerValueLock lock];
LiSendControllerEvent(_lastButtonFlags, _lastLeftTrigger, _lastRightTrigger, _lastLeftStickX, _lastLeftStickY, _lastRightStickX, _lastRightStickY);
[_controllerValueLock unlock];
[_controllerStreamLock unlock];
}
-(void) unregisterControllerCallbacks
{
for (int i = 0; i < [[GCController controllers] count]; i++) {
GCController *controller = [GCController controllers][i];
if (controller != NULL) {
controller.controllerPausedHandler = NULL;
if (controller.extendedGamepad != NULL) {
controller.extendedGamepad.valueChangedHandler = NULL;
}
else if (controller.gamepad != NULL) {
controller.gamepad.valueChangedHandler = NULL;
}
}
}
}
-(void) registerControllerCallbacks
{ {
for (int i = 0; i < [[GCController controllers] count]; i++) { for (int i = 0; i < [[GCController controllers] count]; i++) {
GCController *controller = [GCController controllers][i]; GCController *controller = [GCController controllers][i];
@ -27,16 +174,14 @@ static NSLock *controllerStreamLock;
if (controller != NULL) { if (controller != NULL) {
NSLog(@"Controller connected!"); NSLog(@"Controller connected!");
controller.controllerPausedHandler = ^(GCController *controller) { controller.controllerPausedHandler = ^(GCController *controller) {
// We call LiSendControllerEvent while holding a lock to prevent [self setButtonFlag:PLAY_FLAG];
// multiple simultaneous calls since this function isn't thread safe. [self updateFinished];
[controllerStreamLock lock];
LiSendControllerEvent(PLAY_FLAG, 0, 0, 0, 0, 0, 0);
// Pause for 100 ms // Pause for 100 ms
usleep(100 * 1000); usleep(100 * 1000);
LiSendControllerEvent(0, 0, 0, 0, 0, 0, 0); [self clearButtonFlag:PLAY_FLAG];
[controllerStreamLock unlock]; [self updateFinished];
}; };
if (controller.extendedGamepad != NULL) { if (controller.extendedGamepad != NULL) {
@ -68,12 +213,11 @@ static NSLock *controllerStreamLock;
leftTrigger = gamepad.leftTrigger.value * 0xFF; leftTrigger = gamepad.leftTrigger.value * 0xFF;
rightTrigger = gamepad.rightTrigger.value * 0xFF; rightTrigger = gamepad.rightTrigger.value * 0xFF;
// We call LiSendControllerEvent while holding a lock to prevent [self updateButtonFlags:buttonFlags];
// multiple simultaneous calls since this function isn't thread safe. [self updateLeftStick:leftStickX y:leftStickY];
[controllerStreamLock lock]; [self updateRightStick:rightStickX y:rightStickY];
LiSendControllerEvent(buttonFlags, leftTrigger, rightTrigger, [self updateTriggers:leftTrigger right:rightTrigger];
leftStickX, leftStickY, rightStickX, rightStickY); [self updateFinished];
[controllerStreamLock unlock];
}; };
} }
else if (controller.gamepad != NULL) { else if (controller.gamepad != NULL) {
@ -93,11 +237,8 @@ static NSLock *controllerStreamLock;
UPDATE_BUTTON(LB_FLAG, gamepad.leftShoulder.pressed); UPDATE_BUTTON(LB_FLAG, gamepad.leftShoulder.pressed);
UPDATE_BUTTON(RB_FLAG, gamepad.rightShoulder.pressed); UPDATE_BUTTON(RB_FLAG, gamepad.rightShoulder.pressed);
// We call LiSendControllerEvent while holding a lock to prevent [self updateButtonFlags:buttonFlags];
// multiple simultaneous calls since this function isn't thread safe. [self updateFinished];
[controllerStreamLock lock];
LiSendControllerEvent(buttonFlags, 0, 0, 0, 0, 0, 0);
[controllerStreamLock unlock];
}; };
} }
} }
@ -105,22 +246,72 @@ static NSLock *controllerStreamLock;
} }
-(void) updateAutoOnScreenControlMode
{
// Auto on-screen control support may not be enabled
if (_osc == NULL) {
return;
}
OnScreenControlsLevel level = OnScreenControlsLevelFull;
// We currently stop after the first controller we find.
// Maybe we'll want to change that logic later.
for (int i = 0; i < [[GCController controllers] count]; i++) {
GCController *controller = [GCController controllers][i];
if (controller != NULL) {
if (controller.extendedGamepad != NULL) {
level = OnScreenControlsLevelAutoGCExtendedGamepad;
break;
}
else if (controller.gamepad != NULL) {
level = OnScreenControlsLevelAutoGCGamepad;
break;
}
}
}
[_osc setLevel:level];
}
-(void) initAutoOnScreenControlMode:(OnScreenControls*)osc
{
_osc = osc;
[self updateAutoOnScreenControlMode];
}
-(id) init -(id) init
{ {
self = [super init]; self = [super init];
if (controllerStreamLock == NULL) { _controllerStreamLock = [[NSLock alloc] init];
controllerStreamLock = [[NSLock alloc] init]; _controllerValueLock = [[NSLock alloc] init];
}
self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[ControllerSupport registerControllerCallbacks]; // Register callbacks on the new controller
[self registerControllerCallbacks];
// Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode];
}]; }];
self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSLog(@"Controller disconnected!"); 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];
// Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode];
}]; }];
[ControllerSupport registerControllerCallbacks]; // Register for controller callbacks on any existing controllers
[self registerControllerCallbacks];
return self; return self;
} }
@ -129,6 +320,8 @@ static NSLock *controllerStreamLock;
{ {
[[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver]; [[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver];
[[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver]; [[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver];
[self unregisterControllerCallbacks];
} }
@end @end

View File

@ -8,15 +8,22 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@class ControllerSupport;
@interface OnScreenControls : NSObject @interface OnScreenControls : NSObject
typedef NS_ENUM(NSInteger, OnScreenControlsLevel) { typedef NS_ENUM(NSInteger, OnScreenControlsLevel) {
OnScreenControlsLevelOff, OnScreenControlsLevelOff,
OnScreenControlsLevelAuto,
OnScreenControlsLevelSimple, OnScreenControlsLevelSimple,
OnScreenControlsLevelFull OnScreenControlsLevelFull,
// Internal levels selected by ControllerSupport
OnScreenControlsLevelAutoGCGamepad,
OnScreenControlsLevelAutoGCExtendedGamepad,
}; };
- (id) initWithView:(UIView*)view; - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport;
- (BOOL) handleTouchDownEvent:(NSSet*)touches; - (BOOL) handleTouchDownEvent:(NSSet*)touches;
- (BOOL) handleTouchUpEvent:(NSSet*)touches; - (BOOL) handleTouchUpEvent:(NSSet*)touches;
- (BOOL) handleTouchMovedEvent:(NSSet*)touches; - (BOOL) handleTouchMovedEvent:(NSSet*)touches;

View File

@ -7,6 +7,7 @@
// //
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "ControllerSupport.h"
#include "Limelight.h" #include "Limelight.h"
#define UPDATE_BUTTON(x, y) (buttonFlags = \ #define UPDATE_BUTTON(x, y) (buttonFlags = \
@ -32,11 +33,6 @@
CALayer* _l1Button; CALayer* _l1Button;
CALayer* _l2Button; CALayer* _l2Button;
short buttonFlags;
short leftStickX, leftStickY;
short rightStickX, rightStickY;
char leftTrigger, rightTrigger;
UITouch* _aTouch; UITouch* _aTouch;
UITouch* _bTouch; UITouch* _bTouch;
UITouch* _xTouch; UITouch* _xTouch;
@ -56,6 +52,8 @@
UIView* _view; UIView* _view;
OnScreenControlsLevel _level; OnScreenControlsLevel _level;
ControllerSupport *_controllerSupport;
} }
static const float BUTTON_SIZE = 50; static const float BUTTON_SIZE = 50;
@ -99,33 +97,10 @@ static float L1_Y;
static float L2_X; static float L2_X;
static float L2_Y; static float L2_Y;
- (id) initWithView:(UIView*)view { - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport {
self = [self init]; self = [self init];
_view = view; _view = view;
_controllerSupport = controllerSupport;
D_PAD_CENTER_X = _view.frame.size.width * .15;
D_PAD_CENTER_Y = _view.frame.size.height * .55;
BUTTON_CENTER_X = _view.frame.size.width * .85;
BUTTON_CENTER_Y = _view.frame.size.height * .55;
LS_CENTER_X = _view.frame.size.width * .35;
LS_CENTER_Y = _view.frame.size.height * .75;
RS_CENTER_X = _view.frame.size.width * .65;
RS_CENTER_Y = _view.frame.size.height * .75;
START_X = _view.frame.size.width * .55;
START_Y = _view.frame.size.height * .1;
SELECT_X = _view.frame.size.width * .45;
SELECT_Y = _view.frame.size.height * .1;
L1_X = _view.frame.size.width * .15;
L1_Y = _view.frame.size.height * .25;
L2_X = _view.frame.size.width * .15;
L2_Y = _view.frame.size.height * .1;
R1_X = _view.frame.size.width * .85;
R1_Y = _view.frame.size.height * .25;
R2_X = _view.frame.size.width * .85;
R2_Y = _view.frame.size.height * .1;
_aButton = [CALayer layer]; _aButton = [CALayer layer];
_bButton = [CALayer layer]; _bButton = [CALayer layer];
@ -163,8 +138,32 @@ static float L2_Y;
[self hideStartSelect]; [self hideStartSelect];
[self hideSticks]; [self hideSticks];
break; break;
case OnScreenControlsLevelAutoGCGamepad:
// GCGamepad is missing triggers, both analog sticks,
// and the select button
[self setupGamepadControls];
[self hideButtons];
[self hideBumpers];
[self drawTriggers];
[self drawStartSelect];
[self drawSticks];
// TODO: Draw L3 and R3 buttons
break;
case OnScreenControlsLevelAutoGCExtendedGamepad:
// GCExtendedGamepad is missing R3, L3, and select
[self setupExtendedGamepadControls];
[self hideButtons];
[self hideBumpers];
[self hideTriggers];
[self drawStartSelect];
[self hideSticks];
// TODO: Draw L3 and R3 buttons
break;
case OnScreenControlsLevelSimple: case OnScreenControlsLevelSimple:
[self setupSimpleControls]; [self setupSimpleControls];
[self drawTriggers]; [self drawTriggers];
[self drawStartSelect]; [self drawStartSelect];
[self hideButtons]; [self hideButtons];
@ -172,25 +171,81 @@ static float L2_Y;
[self hideSticks]; [self hideSticks];
break; break;
case OnScreenControlsLevelFull: case OnScreenControlsLevelFull:
[self setupComplexControls];
[self drawButtons]; [self drawButtons];
[self drawStartSelect]; [self drawStartSelect];
[self drawBumpers]; [self drawBumpers];
[self drawTriggers]; [self drawTriggers];
[self drawSticks]; [self drawSticks];
break; break;
default:
NSLog(@"Unknown on-screen controls level: %d", (int)_level);
break;
} }
} }
// For GCExtendedGamepad controls we move start, select, L3, and R3 to the button
- (void) setupExtendedGamepadControls {
// Start with the default complex layout
[self setupComplexControls];
START_Y = _view.frame.size.height * .9;
SELECT_Y = _view.frame.size.height * .9;
// TODO: Position L3 and R3 at the bottom of the screen
}
// For GCGamepad controls we move triggers, start, and select
// to sit right above the analog sticks
- (void) setupGamepadControls {
// Start with the default complex layout
[self setupComplexControls];
// TODO
}
// For simple controls we move the triggers and buttons to the bottom // For simple controls we move the triggers and buttons to the bottom
- (void) setupSimpleControls { - (void) setupSimpleControls {
// Start with the default complex layout
[self setupComplexControls];
START_Y = _view.frame.size.height * .9; START_Y = _view.frame.size.height * .9;
SELECT_Y = _view.frame.size.height * .9; SELECT_Y = _view.frame.size.height * .9;
L1_Y = _view.frame.size.height * .75; L1_Y = _view.frame.size.height * .75;
L2_Y = _view.frame.size.height * .9; L2_Y = _view.frame.size.height * .9;
R1_Y = _view.frame.size.height * .75; R1_Y = _view.frame.size.height * .75;
R2_Y = _view.frame.size.height * .9; R2_Y = _view.frame.size.height * .9;
} }
- (void) setupComplexControls
{
D_PAD_CENTER_X = _view.frame.size.width * .15;
D_PAD_CENTER_Y = _view.frame.size.height * .55;
BUTTON_CENTER_X = _view.frame.size.width * .85;
BUTTON_CENTER_Y = _view.frame.size.height * .55;
LS_CENTER_X = _view.frame.size.width * .35;
LS_CENTER_Y = _view.frame.size.height * .75;
RS_CENTER_X = _view.frame.size.width * .65;
RS_CENTER_Y = _view.frame.size.height * .75;
START_X = _view.frame.size.width * .55;
START_Y = _view.frame.size.height * .1;
SELECT_X = _view.frame.size.width * .45;
SELECT_Y = _view.frame.size.height * .1;
L1_X = _view.frame.size.width * .15;
L1_Y = _view.frame.size.height * .25;
L2_X = _view.frame.size.width * .15;
L2_Y = _view.frame.size.height * .1;
R1_X = _view.frame.size.width * .85;
R1_Y = _view.frame.size.height * .25;
R2_X = _view.frame.size.width * .85;
R2_Y = _view.frame.size.height * .1;
}
- (void) drawButtons { - (void) drawButtons {
// create A button // create A button
_aButton.contents = (id) [UIImage imageNamed:@"AButton"].CGImage; _aButton.contents = (id) [UIImage imageNamed:@"AButton"].CGImage;
@ -325,7 +380,7 @@ static float L2_Y;
} }
- (BOOL) handleTouchMovedEvent:touches { - (BOOL) handleTouchMovedEvent:touches {
BOOL shouldSendPacket = false; BOOL updated = false;
BOOL buttonTouch = false; BOOL buttonTouch = false;
float rsMaxX = RS_CENTER_X + STICK_OUTER_SIZE / 2; float rsMaxX = RS_CENTER_X + STICK_OUTER_SIZE / 2;
float rsMaxY = RS_CENTER_Y + STICK_OUTER_SIZE / 2; float rsMaxY = RS_CENTER_Y + STICK_OUTER_SIZE / 2;
@ -354,10 +409,9 @@ static float L2_Y;
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
leftStickX = 0x7FFE * xStickVal; [_controllerSupport updateLeftStick:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
leftStickY = 0x7FFE * -yStickVal;
shouldSendPacket = true; updated = true;
} else if (touch == _rsTouch) { } else if (touch == _rsTouch) {
if (xLoc > rsMaxX) xLoc = rsMaxX; if (xLoc > rsMaxX) xLoc = rsMaxX;
if (xLoc < rsMinX) xLoc = rsMinX; if (xLoc < rsMinX) xLoc = rsMinX;
@ -372,10 +426,9 @@ static float L2_Y;
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
rightStickX = 0x7FFE * xStickVal; [_controllerSupport updateRightStick:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
rightStickY = 0x7FFE * -yStickVal;
shouldSendPacket = true; updated = true;
} else if (touch == _aTouch) { } else if (touch == _aTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _bTouch) { } else if (touch == _bTouch) {
@ -406,167 +459,163 @@ static float L2_Y;
buttonTouch = true; buttonTouch = true;
} }
} }
if (shouldSendPacket) { if (updated) {
LiSendControllerEvent(buttonFlags, leftTrigger, rightTrigger, [_controllerSupport updateFinished];
leftStickX, leftStickY, rightStickX, rightStickY);
} }
return shouldSendPacket || buttonTouch; return updated || buttonTouch;
} }
- (BOOL)handleTouchDownEvent:touches { - (BOOL)handleTouchDownEvent:touches {
BOOL shouldSendPacket = false; BOOL updated = false;
BOOL stickTouch = false;
for (UITouch* touch in touches) { for (UITouch* touch in touches) {
CGPoint touchLocation = [touch locationInView:_view]; CGPoint touchLocation = [touch locationInView:_view];
if ([_aButton.presentationLayer hitTest:touchLocation]) { if ([_aButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(A_FLAG, 1); [_controllerSupport setButtonFlag:A_FLAG];
_aTouch = touch; _aTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_bButton.presentationLayer hitTest:touchLocation]) { } else if ([_bButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(B_FLAG, 1); [_controllerSupport setButtonFlag:B_FLAG];
_bTouch = touch; _bTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_xButton.presentationLayer hitTest:touchLocation]) { } else if ([_xButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(X_FLAG, 1); [_controllerSupport setButtonFlag:X_FLAG];
_xTouch = touch; _xTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_yButton.presentationLayer hitTest:touchLocation]) { } else if ([_yButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(Y_FLAG, 1); [_controllerSupport setButtonFlag:Y_FLAG];
_yTouch = touch; _yTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_upButton.presentationLayer hitTest:touchLocation]) { } else if ([_upButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(UP_FLAG, 1); [_controllerSupport setButtonFlag:UP_FLAG];
_upTouch = touch; _upTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_downButton.presentationLayer hitTest:touchLocation]) { } else if ([_downButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(DOWN_FLAG, 1); [_controllerSupport setButtonFlag:DOWN_FLAG];
_downTouch = touch; _downTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) { } else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(LEFT_FLAG, 1); [_controllerSupport setButtonFlag:LEFT_FLAG];
_leftTouch = touch; _leftTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) { } else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(RIGHT_FLAG, 1); [_controllerSupport setButtonFlag:RIGHT_FLAG];
_rightTouch = touch; _rightTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_startButton.presentationLayer hitTest:touchLocation]) { } else if ([_startButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(PLAY_FLAG, 1); [_controllerSupport setButtonFlag:PLAY_FLAG];
_startTouch = touch; _startTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_selectButton.presentationLayer hitTest:touchLocation]) { } else if ([_selectButton.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(BACK_FLAG, 1); [_controllerSupport setButtonFlag:BACK_FLAG];
_selectTouch = touch; _selectTouch = touch;
shouldSendPacket = true; updated = true;
} else if ([_l1Button.presentationLayer hitTest:touchLocation]) { } else if ([_l1Button.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(LB_FLAG, 1); [_controllerSupport setButtonFlag:LB_FLAG];
_l1Touch = touch; _l1Touch = touch;
shouldSendPacket = true; updated = true;
} else if ([_r1Button.presentationLayer hitTest:touchLocation]) { } else if ([_r1Button.presentationLayer hitTest:touchLocation]) {
UPDATE_BUTTON(RB_FLAG, 1); [_controllerSupport setButtonFlag:RB_FLAG];
_r1Touch = touch; _r1Touch = touch;
shouldSendPacket = true; updated = true;
} else if ([_l2Button.presentationLayer hitTest:touchLocation]) { } else if ([_l2Button.presentationLayer hitTest:touchLocation]) {
leftTrigger = 1 * 0xFF; [_controllerSupport updateLeftTrigger:0xFF];
_l2Touch = touch; _l2Touch = touch;
shouldSendPacket = true; updated = true;
} else if ([_r2Button.presentationLayer hitTest:touchLocation]) { } else if ([_r2Button.presentationLayer hitTest:touchLocation]) {
rightTrigger = 1 * 0xFF; [_controllerSupport updateRightTrigger:0xFF];
_r2Touch = touch; _r2Touch = touch;
shouldSendPacket = true; updated = true;
} else if ([_leftStick.presentationLayer hitTest:touchLocation]) { } else if ([_leftStick.presentationLayer hitTest:touchLocation]) {
_lsTouch = touch; _lsTouch = touch;
shouldSendPacket = true; stickTouch = true;
} else if ([_rightStick.presentationLayer hitTest:touchLocation]) { } else if ([_rightStick.presentationLayer hitTest:touchLocation]) {
_rsTouch = touch; _rsTouch = touch;
shouldSendPacket = true; stickTouch = true;
} }
} }
if (shouldSendPacket) { if (updated) {
LiSendControllerEvent(buttonFlags, leftTrigger, rightTrigger, [_controllerSupport updateFinished];
leftStickX, leftStickY, rightStickX, rightStickY);
} }
return shouldSendPacket; return updated || stickTouch;
} }
- (BOOL)handleTouchUpEvent:touches { - (BOOL)handleTouchUpEvent:touches {
BOOL shouldSendPacket = false; BOOL updated = false;
for (UITouch* touch in touches) { for (UITouch* touch in touches) {
if (touch == _aTouch) { if (touch == _aTouch) {
UPDATE_BUTTON(A_FLAG, 0); [_controllerSupport clearButtonFlag:A_FLAG];
_aTouch = nil; _aTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _bTouch) { } else if (touch == _bTouch) {
UPDATE_BUTTON(B_FLAG, 0); [_controllerSupport clearButtonFlag:B_FLAG];
_bTouch = nil; _bTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _xTouch) { } else if (touch == _xTouch) {
UPDATE_BUTTON(X_FLAG, 0); [_controllerSupport clearButtonFlag:X_FLAG];
_xTouch = nil; _xTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _yTouch) { } else if (touch == _yTouch) {
UPDATE_BUTTON(Y_FLAG, 0); [_controllerSupport clearButtonFlag:Y_FLAG];
_yTouch = nil; _yTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _upTouch) { } else if (touch == _upTouch) {
UPDATE_BUTTON(UP_FLAG, 0); [_controllerSupport clearButtonFlag:UP_FLAG];
_upTouch = nil; _upTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _downTouch) { } else if (touch == _downTouch) {
UPDATE_BUTTON(DOWN_FLAG, 0); [_controllerSupport clearButtonFlag:DOWN_FLAG];
_downTouch = nil; _downTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _leftTouch) { } else if (touch == _leftTouch) {
UPDATE_BUTTON(LEFT_FLAG, 0); [_controllerSupport clearButtonFlag:LEFT_FLAG];
_leftTouch = nil; _leftTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _rightTouch) { } else if (touch == _rightTouch) {
UPDATE_BUTTON(RIGHT_FLAG, 0); [_controllerSupport clearButtonFlag:RIGHT_FLAG];
_rightTouch = nil; _rightTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _startTouch) { } else if (touch == _startTouch) {
UPDATE_BUTTON(PLAY_FLAG, 0); [_controllerSupport clearButtonFlag:PLAY_FLAG];
_startTouch = nil; _startTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _selectTouch) { } else if (touch == _selectTouch) {
UPDATE_BUTTON(BACK_FLAG, 0); [_controllerSupport clearButtonFlag:BACK_FLAG];
_selectTouch = nil; _selectTouch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _l1Touch) { } else if (touch == _l1Touch) {
UPDATE_BUTTON(LB_FLAG, 0); [_controllerSupport clearButtonFlag:LB_FLAG];
_l1Touch = nil; _l1Touch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _r1Touch) { } else if (touch == _r1Touch) {
UPDATE_BUTTON(RB_FLAG, 0); [_controllerSupport clearButtonFlag:RB_FLAG];
_r1Touch = nil; _r1Touch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _l2Touch) { } else if (touch == _l2Touch) {
leftTrigger = 0 * 0xFF; [_controllerSupport updateLeftTrigger:0];
_l2Touch = nil; _l2Touch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _r2Touch) { } else if (touch == _r2Touch) {
rightTrigger = 0 * 0xFF; [_controllerSupport updateRightTrigger:0];
_r2Touch = nil; _r2Touch = nil;
shouldSendPacket = true; updated = true;
} else if (touch == _lsTouch) { } 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); _leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
leftStickX = 0 * 0x7FFE; [_controllerSupport updateLeftStick:0 y:0];
leftStickY = 0 * 0x7FFE; updated = true;
shouldSendPacket = true;
_lsTouch = nil; _lsTouch = nil;
} else if (touch == _rsTouch) { } 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); _rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
rightStickX = 0 * 0x7FFE; [_controllerSupport updateRightStick:0 y:0];
rightStickY = 0 * 0x7FFE;
_rsTouch = nil; _rsTouch = nil;
shouldSendPacket = true; updated = true;
} }
} }
if (shouldSendPacket) { if (updated) {
LiSendControllerEvent(buttonFlags, leftTrigger, rightTrigger, [_controllerSupport updateFinished];
leftStickX, leftStickY, rightStickX, rightStickY);
} }
return shouldSendPacket; return updated;
} }
@end @end

View File

@ -7,9 +7,10 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "ControllerSupport.h"
@interface StreamView : UIView @interface StreamView : UIView
- (void) setupOnScreenControls; - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport;
@end @end

View File

@ -10,6 +10,7 @@
#include <Limelight.h> #include <Limelight.h>
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "DataManager.h" #import "DataManager.h"
#import "ControllerSupport.h"
@implementation StreamView { @implementation StreamView {
CGPoint touchLocation; CGPoint touchLocation;
@ -17,14 +18,21 @@
OnScreenControls* onScreenControls; OnScreenControls* onScreenControls;
} }
- (void) setupOnScreenControls { - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport {
onScreenControls = [[OnScreenControls alloc] initWithView:self]; onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport];
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue]; OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue];
NSLog(@"Setting on-screen controls level: %d", (int)level);
if (level == OnScreenControlsLevelAuto) {
[controllerSupport initAutoOnScreenControlMode:onScreenControls];
}
else {
NSLog(@"Setting manual on-screen controls level: %d", (int)level);
[onScreenControls setLevel:level]; [onScreenControls setLevel:level];
} }
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Touch down"); NSLog(@"Touch down");
if (![onScreenControls handleTouchDownEvent:touches]) { if (![onScreenControls handleTouchDownEvent:touches]) {

View File

@ -64,7 +64,7 @@
[self.stageLabel setText:@"Waiting for first frame..."]; [self.stageLabel setText:@"Waiting for first frame..."];
[self.stageLabel sizeToFit]; [self.stageLabel sizeToFit];
}); });
[(StreamView*)self.view setupOnScreenControls]; [(StreamView*)self.view setupOnScreenControls: _controllerSupport];
} }
- (void)connectionTerminated:(long)errorCode { - (void)connectionTerminated:(long)errorCode {

View File

@ -126,11 +126,12 @@
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="2" id="qSU-wh-tqA"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="qSU-wh-tqA">
<rect key="frame" x="16" y="265" width="209" height="29"/> <rect key="frame" x="16" y="265" width="209" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments> <segments>
<segment title="Off"/> <segment title="Off"/>
<segment title="Auto"/>
<segment title="Simple"/> <segment title="Simple"/>
<segment title="Full"/> <segment title="Full"/>
</segments> </segments>

View File

@ -146,11 +146,12 @@
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="2" id="WGf-9d-eAm"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="WGf-9d-eAm">
<rect key="frame" x="16" y="246" width="200" height="29"/> <rect key="frame" x="16" y="246" width="200" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments> <segments>
<segment title="Off"/> <segment title="Off"/>
<segment title="Auto"/>
<segment title="Simple"/> <segment title="Simple"/>
<segment title="Full"/> <segment title="Full"/>
</segments> </segments>