dual sense adaptive trigger implementation working with Sunshine-Foundation
This commit is contained in:
@@ -52,6 +52,9 @@
|
||||
-(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) setControllerLed:(uint16_t)controllerNumber r:(uint8_t)r g:(uint8_t)g b:(uint8_t)b;
|
||||
-(void) setAdaptiveTriggers:(uint16_t)controllerNumber eventFlags:(uint8_t)eventFlags
|
||||
typeLeft:(uint8_t)typeLeft typeRight:(uint8_t)typeRight
|
||||
left:(const uint8_t*)left right:(const uint8_t*)right;
|
||||
-(void) updateTimerStateForOsc;
|
||||
|
||||
-(uint16_t) getActiveGamepadMask;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#import "DataManager.h"
|
||||
#include "Limelight.h"
|
||||
#include <stdio.h>
|
||||
|
||||
@import GameController;
|
||||
#if !TARGET_OS_TV
|
||||
@@ -26,6 +27,61 @@
|
||||
static const double MOUSE_SPEED_DIVISOR = 1.25;
|
||||
static __weak ControllerSupport *VLSharedControllerSupport = nil;
|
||||
|
||||
typedef struct _VL_ADAPTIVE_TRIGGER_EFFECT {
|
||||
uint8_t type;
|
||||
float parameter0;
|
||||
float parameter1;
|
||||
float parameter2;
|
||||
} VL_ADAPTIVE_TRIGGER_EFFECT;
|
||||
|
||||
static VL_ADAPTIVE_TRIGGER_EFFECT DecodeAdaptiveTriggerEffect(uint8_t type, const uint8_t* payload)
|
||||
{
|
||||
const float byteScale = 1.0f / 255.0f;
|
||||
VL_ADAPTIVE_TRIGGER_EFFECT effect = {
|
||||
.type = type,
|
||||
.parameter0 = payload[0] * byteScale,
|
||||
.parameter1 = payload[1] * byteScale,
|
||||
.parameter2 = payload[2] * byteScale,
|
||||
};
|
||||
return effect;
|
||||
}
|
||||
|
||||
static void ApplyAdaptiveTriggerEffect(GCDualSenseAdaptiveTrigger* trigger,
|
||||
VL_ADAPTIVE_TRIGGER_EFFECT effect)
|
||||
API_AVAILABLE(ios(14.5), tvos(14.5));
|
||||
|
||||
static void ApplyAdaptiveTriggerEffect(GCDualSenseAdaptiveTrigger* trigger,
|
||||
VL_ADAPTIVE_TRIGGER_EFFECT effect)
|
||||
{
|
||||
switch (effect.type) {
|
||||
case 0x00:
|
||||
[trigger setModeOff];
|
||||
break;
|
||||
case 0x01:
|
||||
[trigger setModeFeedbackWithStartPosition:effect.parameter0
|
||||
resistiveStrength:effect.parameter1];
|
||||
break;
|
||||
case 0x02:
|
||||
if (effect.parameter1 > effect.parameter0) {
|
||||
[trigger setModeWeaponWithStartPosition:effect.parameter0
|
||||
endPosition:effect.parameter1
|
||||
resistiveStrength:effect.parameter2];
|
||||
}
|
||||
else {
|
||||
// Log(LOG_W, @"Ignoring invalid adaptive weapon effect: start=%.3f end=%.3f", effect.parameter0, effect.parameter1);
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
[trigger setModeVibrationWithStartPosition:effect.parameter0
|
||||
amplitude:effect.parameter1
|
||||
frequency:effect.parameter2];
|
||||
break;
|
||||
default:
|
||||
// Log(LOG_W, @"Ignoring unsupported adaptive trigger effect type: 0x%02X", effect.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@interface ControllerSupport()
|
||||
|
||||
@property (assign,nonatomic) bool shallDisableGyroHotSwitch;
|
||||
@@ -455,6 +511,55 @@ static __weak ControllerSupport *VLSharedControllerSupport = nil;
|
||||
}
|
||||
}
|
||||
|
||||
-(void) setAdaptiveTriggers:(uint16_t)controllerNumber eventFlags:(uint8_t)eventFlags
|
||||
typeLeft:(uint8_t)typeLeft typeRight:(uint8_t)typeRight
|
||||
left:(const uint8_t*)left right:(const uint8_t*)right {
|
||||
char leftPayload[DS_EFFECT_PAYLOAD_SIZE * 3] = {0};
|
||||
char rightPayload[DS_EFFECT_PAYLOAD_SIZE * 3] = {0};
|
||||
|
||||
for (int i = 0; i < DS_EFFECT_PAYLOAD_SIZE; i++) {
|
||||
snprintf(leftPayload + (i * 3), sizeof(leftPayload) - (i * 3),
|
||||
i == DS_EFFECT_PAYLOAD_SIZE - 1 ? "%02X" : "%02X ", left[i]);
|
||||
snprintf(rightPayload + (i * 3), sizeof(rightPayload) - (i * 3),
|
||||
i == DS_EFFECT_PAYLOAD_SIZE - 1 ? "%02X" : "%02X ", right[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
Log(LOG_I, @"Adaptive trigger: controller=%u flags=0x%02X "
|
||||
"leftType=0x%02X left=[%s] rightType=0x%02X right=[%s]",
|
||||
controllerNumber, eventFlags,
|
||||
typeLeft, leftPayload, typeRight, rightPayload);
|
||||
*/
|
||||
|
||||
VL_ADAPTIVE_TRIGGER_EFFECT leftEffect = DecodeAdaptiveTriggerEffect(typeLeft, left);
|
||||
VL_ADAPTIVE_TRIGGER_EFFECT rightEffect = DecodeAdaptiveTriggerEffect(typeRight, right);
|
||||
bool applyLeft = (eventFlags & DS_EFFECT_LEFT_TRIGGER) != 0;
|
||||
bool applyRight = (eventFlags & DS_EFFECT_RIGHT_TRIGGER) != 0;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (@available(iOS 14.5, tvOS 14.5, *)) {
|
||||
VoidController* controller = [self->_voidControllers objectForKey:@(controllerNumber)];
|
||||
if (controller == nil) {
|
||||
Log(LOG_W, @"Ignoring adaptive trigger effect for missing gamepad %u", controllerNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
if (![controller.gamepad.extendedGamepad isKindOfClass:[GCDualSenseGamepad class]]) {
|
||||
Log(LOG_W, @"Ignoring adaptive trigger effect for non-DualSense gamepad %u", controllerNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
GCDualSenseGamepad* dualSense = (GCDualSenseGamepad*)controller.gamepad.extendedGamepad;
|
||||
if (applyLeft) {
|
||||
ApplyAdaptiveTriggerEffect(dualSense.leftTrigger, leftEffect);
|
||||
}
|
||||
if (applyRight) {
|
||||
ApplyAdaptiveTriggerEffect(dualSense.rightTrigger, rightEffect);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
-(void) updateLeftStick:(VoidController*)controller x:(short)x y:(short)y
|
||||
{
|
||||
@synchronized(controller) {
|
||||
@@ -691,6 +796,14 @@ static __weak ControllerSupport *VLSharedControllerSupport = nil;
|
||||
|
||||
-(void) cleanupControllerHaptics:(VoidController*) controller
|
||||
{
|
||||
if (@available(iOS 14.5, tvOS 14.5, *)) {
|
||||
if ([controller.gamepad.extendedGamepad isKindOfClass:[GCDualSenseGamepad class]]) {
|
||||
GCDualSenseGamepad* dualSense = (GCDualSenseGamepad*)controller.gamepad.extendedGamepad;
|
||||
[dualSense.leftTrigger setModeOff];
|
||||
[dualSense.rightTrigger setModeOff];
|
||||
}
|
||||
}
|
||||
|
||||
[controller.lowFreqMotor cleanup];
|
||||
[controller.highFreqMotor cleanup];
|
||||
[controller.leftTriggerMotor cleanup];
|
||||
@@ -854,7 +967,6 @@ static __weak ControllerSupport *VLSharedControllerSupport = nil;
|
||||
capabilities |= LI_CCAP_TOUCHPAD;
|
||||
}
|
||||
|
||||
|
||||
// LI_CTYPE_UNKNOWN for option "Both"
|
||||
if(voidController.playerIndex == 0){
|
||||
type = _streamConfig.emulatedControllerType == LI_CTYPE_UNKNOWN ? LI_CTYPE_PS : _streamConfig.emulatedControllerType;
|
||||
@@ -878,9 +990,7 @@ static __weak ControllerSupport *VLSharedControllerSupport = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Detect supported haptics localities
|
||||
if (controller.haptics) {
|
||||
if ([controller.haptics.supportedLocalities containsObject:GCHapticsLocalityHandles]) {
|
||||
|
||||
@@ -576,6 +576,18 @@ void ClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t
|
||||
[_callbacks setControllerLed:controllerNumber r:r g:g b:b];
|
||||
}
|
||||
|
||||
void ClSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlags,
|
||||
uint8_t typeLeft, uint8_t typeRight,
|
||||
uint8_t* left, uint8_t* right)
|
||||
{
|
||||
[_callbacks setAdaptiveTriggers:controllerNumber
|
||||
eventFlags:eventFlags
|
||||
typeLeft:typeLeft
|
||||
typeRight:typeRight
|
||||
left:left
|
||||
right:right];
|
||||
}
|
||||
|
||||
-(void) terminate
|
||||
{
|
||||
// Interrupt any action blocking LiStartConnection(). This is
|
||||
@@ -737,6 +749,7 @@ void ClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t
|
||||
_clCallbacks.rumbleTriggers = ClRumbleTriggers;
|
||||
_clCallbacks.setMotionEventState = ClSetMotionEventState;
|
||||
_clCallbacks.setControllerLED = ClSetControllerLED;
|
||||
_clCallbacks.setAdaptiveTriggers = ClSetAdaptiveTriggers;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleAudioSessionInterruption:)
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
- (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) setControllerLed:(uint16_t)controllerNumber r:(uint8_t)r g:(uint8_t)g b:(uint8_t)b;
|
||||
- (void) setAdaptiveTriggers:(uint16_t)controllerNumber eventFlags:(uint8_t)eventFlags
|
||||
typeLeft:(uint8_t)typeLeft typeRight:(uint8_t)typeRight
|
||||
left:(const uint8_t*)left right:(const uint8_t*)right;
|
||||
- (void) videoContentShown;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
//
|
||||
// FrameQueue.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Andy Grundman.
|
||||
// Ported to VoidLink by Acaki.
|
||||
// Copyright (c) 2025 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2026/8/12.
|
||||
// Copyright © 2026 True砖家 on Bilibili. All rights reserved.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <VideoToolbox/VideoToolbox.h>
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
//
|
||||
// FrameQueue.m
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Andy Grundman.
|
||||
// Ported to VoidLink by Acaki.
|
||||
// Copyright (c) 2025 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2026/8/6.
|
||||
// Copyright © 2026 True砖家 on Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@import AVFoundation;
|
||||
@import VideoToolbox;
|
||||
|
||||
|
||||
@@ -1946,6 +1946,17 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
[_controllerSupport setControllerLed:controllerNumber r:r g:g b:b];
|
||||
}
|
||||
|
||||
- (void) setAdaptiveTriggers:(uint16_t)controllerNumber eventFlags:(uint8_t)eventFlags
|
||||
typeLeft:(uint8_t)typeLeft typeRight:(uint8_t)typeRight
|
||||
left:(const uint8_t*)left right:(const uint8_t*)right {
|
||||
[_controllerSupport setAdaptiveTriggers:controllerNumber
|
||||
eventFlags:eventFlags
|
||||
typeLeft:typeLeft
|
||||
typeRight:typeRight
|
||||
left:left
|
||||
right:right];
|
||||
}
|
||||
|
||||
- (void)connectionStatusUpdate:(int)status {
|
||||
Log(LOG_W, @"Connection status update: %d", status);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user