diff --git a/Limelight/Input/Controller.h b/Limelight/Input/Controller.h index 833284b..e3b356f 100644 --- a/Limelight/Input/Controller.h +++ b/Limelight/Input/Controller.h @@ -27,5 +27,7 @@ @property (nonatomic) HapticContext* _Nullable lowFreqMotor; @property (nonatomic) HapticContext* _Nullable highFreqMotor; +@property (nonatomic) HapticContext* _Nullable leftTriggerMotor; +@property (nonatomic) HapticContext* _Nullable rightTriggerMotor; @end diff --git a/Limelight/Input/ControllerSupport.h b/Limelight/Input/ControllerSupport.h index 19056c1..f839bb7 100644 --- a/Limelight/Input/ControllerSupport.h +++ b/Limelight/Input/ControllerSupport.h @@ -41,6 +41,8 @@ -(void) updateFinished:(Controller*)controller; -(void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor; +-(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger; +-(void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz; +(int) getConnectedGamepadMask:(StreamConfiguration*)streamConfig; diff --git a/Limelight/Input/ControllerSupport.m b/Limelight/Input/ControllerSupport.m index 0d22b2f..87a38e4 100644 --- a/Limelight/Input/ControllerSupport.m +++ b/Limelight/Input/ControllerSupport.m @@ -71,6 +71,27 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; [controller.highFreqMotor setMotorAmplitude:highFreqMotor]; } +-(void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger +{ + Controller* controller = [_controllers objectForKey:[NSNumber numberWithInteger:controllerNumber]]; + if (controller == nil && controllerNumber == 0 && _oscEnabled) { + // No physical controller, but we have on-screen controls + controller = _player0osc; + } + if (controller == nil) { + // No connected controller for this player + return; + } + + [controller.leftTriggerMotor setMotorAmplitude:leftTrigger]; + [controller.rightTriggerMotor setMotorAmplitude:rightTrigger]; +} + +- (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz +{ + +} + -(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y { @synchronized(controller) { @@ -261,12 +282,17 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; { controller.lowFreqMotor = [HapticContext createContextForLowFreqMotor:controller.gamepad]; controller.highFreqMotor = [HapticContext createContextForHighFreqMotor:controller.gamepad]; + controller.leftTriggerMotor = [HapticContext createContextForLeftTrigger:controller.gamepad]; + controller.rightTriggerMotor = [HapticContext createContextForRightTrigger:controller.gamepad]; } -(void) cleanupControllerHaptics:(Controller*) controller { [controller.lowFreqMotor cleanup]; [controller.highFreqMotor cleanup]; + [controller.leftTriggerMotor cleanup]; + [controller.rightTriggerMotor cleanup]; +} } -(void) registerControllerCallbacks:(GCController*) controller diff --git a/Limelight/Input/HapticContext.h b/Limelight/Input/HapticContext.h index 69f9d5c..b8f2b61 100644 --- a/Limelight/Input/HapticContext.h +++ b/Limelight/Input/HapticContext.h @@ -16,5 +16,7 @@ +(HapticContext*) createContextForHighFreqMotor:(GCController*)gamepad; +(HapticContext*) createContextForLowFreqMotor:(GCController*)gamepad; ++(HapticContext*) createContextForLeftTrigger:(GCController*)gamepad; ++(HapticContext*) createContextForRightTrigger:(GCController*)gamepad; @end diff --git a/Limelight/Input/HapticContext.m b/Limelight/Input/HapticContext.m index dde1010..b61124c 100644 --- a/Limelight/Input/HapticContext.m +++ b/Limelight/Input/HapticContext.m @@ -89,6 +89,11 @@ return nil; } + if (![[gamepad.haptics supportedLocalities] containsObject:locality]) { + Log(LOG_W, @"Controller %d does not support haptic locality: %@", gamepad.playerIndex, locality); + return nil; + } + _playerIndex = gamepad.playerIndex; _hapticEngine = [gamepad.haptics createEngineWithLocality:locality]; @@ -144,4 +149,22 @@ } } ++(HapticContext*) createContextForLeftTrigger:(GCController*)gamepad { + if (@available(iOS 14.0, tvOS 14.0, *)) { + return [[HapticContext alloc] initWithGamepad:gamepad locality:GCHapticsLocalityLeftTrigger]; + } + else { + return nil; + } +} + ++(HapticContext*) createContextForRightTrigger:(GCController*)gamepad { + if (@available(iOS 14.0, tvOS 14.0, *)) { + return [[HapticContext alloc] initWithGamepad:gamepad locality:GCHapticsLocalityRightTrigger]; + } + else { + return nil; + } +} + @end diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index a53f30f..af28628 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -313,6 +313,16 @@ void ClSetHdrMode(bool enabled) [_callbacks setHdrMode:enabled]; } +void ClRumbleTriggers(uint16_t controllerNumber, uint16_t leftTriggerMotor, uint16_t rightTriggerMotor) +{ + [_callbacks rumbleTriggers:controllerNumber leftTrigger:leftTriggerMotor rightTrigger:rightTriggerMotor]; +} + +void ClSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) +{ + [_callbacks setMotionEventState:controllerNumber motionType:motionType reportRateHz:reportRateHz]; +} + -(void) terminate { // Interrupt any action blocking LiStartConnection(). This is @@ -455,6 +465,8 @@ void ClSetHdrMode(bool enabled) _clCallbacks.rumble = ClRumble; _clCallbacks.connectionStatusUpdate = ClConnectionStatusUpdate; _clCallbacks.setHdrMode = ClSetHdrMode; + _clCallbacks.rumbleTriggers = ClRumbleTriggers; + _clCallbacks.setMotionEventState = ClSetMotionEventState; return self; } diff --git a/Limelight/Stream/ConnectionCallbacks.h b/Limelight/Stream/ConnectionCallbacks.h index 3da578b..c67cd1e 100644 --- a/Limelight/Stream/ConnectionCallbacks.h +++ b/Limelight/Stream/ConnectionCallbacks.h @@ -17,6 +17,8 @@ - (void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor; - (void) connectionStatusUpdate:(int)status; - (void) setHdrMode:(bool)enabled; +- (void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger; +- (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz; - (void) videoContentShown; @end diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index 1a30608..67db79d 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -526,6 +526,18 @@ [_controllerSupport rumble:controllerNumber lowFreqMotor:lowFreqMotor highFreqMotor:highFreqMotor]; } +- (void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger { + Log(LOG_I, @"Trigger rumble on gamepad %d: %04x %04x", controllerNumber, leftTrigger, rightTrigger); + + [_controllerSupport rumbleTriggers:controllerNumber leftTrigger:leftTrigger rightTrigger:rightTrigger]; +} + +- (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz { + Log(LOG_I, @"Set motion state on gamepad %d: %02x %u Hz", controllerNumber, motionType, reportRateHz); + + [_controllerSupport setMotionEventState:controllerNumber motionType:motionType reportRateHz:reportRateHz]; +} + - (void)connectionStatusUpdate:(int)status { Log(LOG_W, @"Connection status update: %d", status); diff --git a/moonlight-common/moonlight-common-c b/moonlight-common/moonlight-common-c index b77072d..c5dc45e 160000 --- a/moonlight-common/moonlight-common-c +++ b/moonlight-common/moonlight-common-c @@ -1 +1 @@ -Subproject commit b77072d39984019b4234d9f2adc3b673b6d57812 +Subproject commit c5dc45e1443363d95b9708de26e86ed57b6946e6