feat: implements button visual feedback switch for legacy osc

This commit is contained in:
TrueZhuanjia committed 2025-09-13 17:33:40 +08:00
1 parent 92f1fbf33b
commit 6c72f0331b
4 files changed
+51 -51

No files matched your search

+48 -50
View File
@@ -73,6 +73,7 @@ static NSSet *validPositionButtonNames;
VoidController *_controller; VoidController *_controller;
NSMutableArray* _deadTouches; NSMutableArray* _deadTouches;
BOOL _swapABXY; BOOL _swapABXY;
BOOL _visualFeedbackEnabled;
BOOL _largerStickLR1; BOOL _largerStickLR1;
CGFloat _oscTapExlusionAreaSizeFactor; CGFloat _oscTapExlusionAreaSizeFactor;
OSCProfilesManager *profilesManager; OSCProfilesManager *profilesManager;
@@ -219,6 +220,7 @@ static float L3_Y;
_deadTouches = [[NSMutableArray alloc] init]; _deadTouches = [[NSMutableArray alloc] init];
if (streamConfig) { if (streamConfig) {
_swapABXY = streamConfig.swapABXYButtons; _swapABXY = streamConfig.swapABXYButtons;
_visualFeedbackEnabled = streamConfig.buttonVisualFeedback;
} }
_originalControllerLayerOpacityDict = [[NSMutableDictionary alloc] init]; _originalControllerLayerOpacityDict = [[NSMutableDictionary alloc] init];
@@ -1103,7 +1105,7 @@ static float L3_Y;
// Allow the user to slide their finger to another d-pad button // Allow the user to slide their finger to another d-pad button
if ([_upButton.presentationLayer hitTest:touchLocation]) { if ([_upButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG]; [_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
[self oscButtonTouchDownFeedback:_upButton]; [self handleButtonFeedback:_upButton];
updated = true; updated = true;
} else { } else {
_upButton.opacity = [_originalControllerLayerOpacityDict[_upButton.name] floatValue]; _upButton.opacity = [_originalControllerLayerOpacityDict[_upButton.name] floatValue];
@@ -1112,7 +1114,7 @@ static float L3_Y;
if ([_downButton.presentationLayer hitTest:touchLocation]) { if ([_downButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG]; [_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
[self oscButtonTouchDownFeedback:_downButton]; [self handleButtonFeedback:_downButton];
updated = true; updated = true;
} else { } else {
_downButton.opacity = [_originalControllerLayerOpacityDict[_downButton.name] floatValue]; _downButton.opacity = [_originalControllerLayerOpacityDict[_downButton.name] floatValue];
@@ -1121,7 +1123,7 @@ static float L3_Y;
if ([_leftButton.presentationLayer hitTest:touchLocation]) { if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
[self oscButtonTouchDownFeedback:_leftButton]; [self handleButtonFeedback:_leftButton];
updated = true; updated = true;
} else { } else {
_leftButton.opacity = [_originalControllerLayerOpacityDict[_leftButton.name] floatValue]; _leftButton.opacity = [_originalControllerLayerOpacityDict[_leftButton.name] floatValue];
@@ -1130,7 +1132,7 @@ static float L3_Y;
if ([_rightButton.presentationLayer hitTest:touchLocation]) { if ([_rightButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
[self oscButtonTouchDownFeedback:_rightButton]; [self handleButtonFeedback:_rightButton];
updated = true; updated = true;
} else { } else {
_rightButton.opacity = [_originalControllerLayerOpacityDict[_rightButton.name] floatValue]; _rightButton.opacity = [_originalControllerLayerOpacityDict[_rightButton.name] floatValue];
@@ -1177,35 +1179,35 @@ static float L3_Y;
} }
- (void)oscButtonTouchDownFeedback:(CALayer* )button{ - (void)handleButtonFeedback:(CALayer* )button{
[CATransaction begin]; if(_visualFeedbackEnabled){
[CATransaction setDisableActions:YES]; [CATransaction begin];
[CATransaction setDisableActions:YES];
/* button.opacity = 0.9; // set a high opacity to ensure visibility of visual effect
if(![[_originalControllerLayerOpacityDict allKeys] containsObject:button.name]){ button.borderColor = [UIColor clearColor].CGColor; // Color of the outline
[_originalControllerLayerOpacityDict setObject:@(button.opacity) forKey:button.name]; button.borderWidth = 20; // Width of the outline
button.cornerRadius = button.bounds.size.width/2;
// 使用 shadowPath 定义阴影形状和扩展范围
CGFloat spread = 15; // 扩散的大小
if([button.name isEqualToString:@"leftStick"] || [button.name isEqualToString:@"rightStick"]) spread = 12;
CGRect largerRect = CGRectInset(button.bounds, -spread, -spread);
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:largerRect cornerRadius:button.cornerRadius];
button.shadowPath = shadowPath.CGPath;
//button.shadowColor = [[UIColor colorWithRed:0/255.0 green:110/255.0 blue:255/255.0 alpha:1.0] colorWithAlphaComponent:0.7].CGColor;
button.shadowColor = [[UIColor colorWithRed:0.5 green:0.5 blue:1.0 alpha:1] colorWithAlphaComponent:1].CGColor;
//button.shadowColor = [UIColor colorWithRed:0/255.0 green:51/255.0 blue:102/255.0 alpha:0.6].CGColor;
button.shadowOffset = CGSizeZero;
button.shadowOpacity = 1.0;
button.shadowRadius = 0.0; // Adjust the radius to simulate border thickness
[CATransaction commit];
} }
*/ [self oscButtonHapticFeedback:button];
}
button.opacity = 0.9; // set a high opacity to ensure visibility of visual effect
button.borderColor = [UIColor clearColor].CGColor; // Color of the outline
button.borderWidth = 20; // Width of the outline
button.cornerRadius = button.bounds.size.width/2;
// 使用 shadowPath 定义阴影形状和扩展范围
CGFloat spread = 15; // 扩散的大小
if([button.name isEqualToString:@"leftStick"] || [button.name isEqualToString:@"rightStick"]) spread = 12;
CGRect largerRect = CGRectInset(button.bounds, -spread, -spread);
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:largerRect cornerRadius:button.cornerRadius];
button.shadowPath = shadowPath.CGPath;
//button.shadowColor = [[UIColor colorWithRed:0/255.0 green:110/255.0 blue:255/255.0 alpha:1.0] colorWithAlphaComponent:0.7].CGColor;
button.shadowColor = [[UIColor colorWithRed:0.5 green:0.5 blue:1.0 alpha:1] colorWithAlphaComponent:1].CGColor;
//button.shadowColor = [UIColor colorWithRed:0/255.0 green:51/255.0 blue:102/255.0 alpha:0.6].CGColor;
button.shadowOffset = CGSizeZero;
button.shadowOpacity = 1.0;
button.shadowRadius = 0.0; // Adjust the radius to simulate border thickness
- (void)oscButtonHapticFeedback:(CALayer* )button{
NSNumber *style = [OnScreenControls.layerVibrationStyleDic objectForKey:button.name]; NSNumber *style = [OnScreenControls.layerVibrationStyleDic objectForKey:button.name];
uint8_t vibrationStyle = [style unsignedCharValue]; uint8_t vibrationStyle = [style unsignedCharValue];
@@ -1223,12 +1225,8 @@ static float L3_Y;
[vibrationGenerator impactOccurred]; [vibrationGenerator impactOccurred];
NSLog(@"vibration instance: %@",vibrationGenerator); NSLog(@"vibration instance: %@",vibrationGenerator);
} }
[CATransaction commit];
} }
// osc Button capturing here // osc Button capturing here
- (BOOL)handleTouchDownEvent:touches { - (BOOL)handleTouchDownEvent:touches {
BOOL updated = false; BOOL updated = false;
@@ -1242,28 +1240,28 @@ static float L3_Y;
if ([_aButton.presentationLayer hitTest:touchLocation]) { if ([_aButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:A_FLAG]; [_controllerSupport setButtonFlag:_controller flags:A_FLAG];
_aTouch = touch; _aTouch = touch;
[self oscButtonTouchDownFeedback:_aButton]; [self handleButtonFeedback:_aButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC A"); // NSLog(@"Captured OSC A");
} else if ([_bButton.presentationLayer hitTest:touchLocation]) { } else if ([_bButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:B_FLAG]; [_controllerSupport setButtonFlag:_controller flags:B_FLAG];
_bTouch = touch; _bTouch = touch;
[self oscButtonTouchDownFeedback:_bButton]; [self handleButtonFeedback:_bButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC B"); // NSLog(@"Captured OSC B");
} else if ([_xButton.presentationLayer hitTest:touchLocation]) { } else if ([_xButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:X_FLAG]; [_controllerSupport setButtonFlag:_controller flags:X_FLAG];
_xTouch = touch; _xTouch = touch;
[self oscButtonTouchDownFeedback:_xButton]; [self handleButtonFeedback:_xButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC X"); // NSLog(@"Captured OSC X");
} else if ([_yButton.presentationLayer hitTest:touchLocation]) { } else if ([_yButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:Y_FLAG]; [_controllerSupport setButtonFlag:_controller flags:Y_FLAG];
_yTouch = touch; _yTouch = touch;
[self oscButtonTouchDownFeedback:_yButton]; [self handleButtonFeedback:_yButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC Y"); // NSLog(@"Captured OSC Y");
@@ -1271,7 +1269,7 @@ static float L3_Y;
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG]; [_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
_dpadTouch = touch; _dpadTouch = touch;
_upTouch = touch; _upTouch = touch;
[self oscButtonTouchDownFeedback:_upButton]; [self handleButtonFeedback:_upButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC UP"); // NSLog(@"Captured OSC UP");
@@ -1279,14 +1277,14 @@ static float L3_Y;
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG]; [_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
_dpadTouch = touch; _dpadTouch = touch;
_downTouch = touch; _downTouch = touch;
[self oscButtonTouchDownFeedback:_downButton]; [self handleButtonFeedback:_downButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) { } else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
_dpadTouch = touch; _dpadTouch = touch;
_leftTouch = touch; _leftTouch = touch;
[self oscButtonTouchDownFeedback:_leftButton]; [self handleButtonFeedback:_leftButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC LEFT"); // NSLog(@"Captured OSC LEFT");
@@ -1294,49 +1292,49 @@ static float L3_Y;
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
_dpadTouch = touch; _dpadTouch = touch;
_rightTouch = touch; _rightTouch = touch;
[self oscButtonTouchDownFeedback:_rightButton]; [self handleButtonFeedback:_rightButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC RIGHT"); // NSLog(@"Captured OSC RIGHT");
} else if ([_startButton.presentationLayer hitTest:touchLocation]) { } else if ([_startButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG]; [_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
_startTouch = touch; _startTouch = touch;
[self oscButtonTouchDownFeedback:_startButton]; [self handleButtonFeedback:_startButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC PLAY"); // NSLog(@"Captured OSC PLAY");
} else if ([_selectButton.presentationLayer hitTest:touchLocation]) { } else if ([_selectButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:BACK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:BACK_FLAG];
_selectTouch = touch; _selectTouch = touch;
[self oscButtonTouchDownFeedback:_selectButton]; [self handleButtonFeedback:_selectButton];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC BACK"); // NSLog(@"Captured OSC BACK");
} else if ([_l1Button.presentationLayer hitTest:touchLocation]) { } else if ([_l1Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LB_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LB_FLAG];
_l1Touch = touch; _l1Touch = touch;
[self oscButtonTouchDownFeedback:_l1Button]; [self handleButtonFeedback:_l1Button];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC LB"); // NSLog(@"Captured OSC LB");
} else if ([_r1Button.presentationLayer hitTest:touchLocation]) { } else if ([_r1Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:RB_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RB_FLAG];
_r1Touch = touch; _r1Touch = touch;
[self oscButtonTouchDownFeedback:_r1Button]; [self handleButtonFeedback:_r1Button];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC RB"); // NSLog(@"Captured OSC RB");
} else if ([_l2Button.presentationLayer hitTest:touchLocation]) { } else if ([_l2Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport updateLeftTrigger:_controller left:0xFF]; [_controllerSupport updateLeftTrigger:_controller left:0xFF];
_l2Touch = touch; _l2Touch = touch;
[self oscButtonTouchDownFeedback:_l2Button]; [self handleButtonFeedback:_l2Button];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC LeftTrigger"); // NSLog(@"Captured OSC LeftTrigger");
} else if ([_r2Button.presentationLayer hitTest:touchLocation]) { } else if ([_r2Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport updateRightTrigger:_controller right:0xFF]; [_controllerSupport updateRightTrigger:_controller right:0xFF];
_r2Touch = touch; _r2Touch = touch;
[self oscButtonTouchDownFeedback:_r2Button]; [self handleButtonFeedback:_r2Button];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC RightTrigger"); // NSLog(@"Captured OSC RightTrigger");
@@ -1376,7 +1374,7 @@ static float L3_Y;
double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0; double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0;
if (l3TouchTime < STICK_CLICK_RATE) { if (l3TouchTime < STICK_CLICK_RATE) {
[_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG];
[self oscButtonTouchDownFeedback:_leftStick]; [self handleButtonFeedback:_leftStick];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC LS_CLK3"); // NSLog(@"Captured OSC LS_CLK3");
@@ -1394,7 +1392,7 @@ static float L3_Y;
double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0; double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0;
if (r3TouchTime < STICK_CLICK_RATE) { if (r3TouchTime < STICK_CLICK_RATE) {
[_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG];
[self oscButtonTouchDownFeedback:_rightStick]; [self handleButtonFeedback:_rightStick];
updated = true; updated = true;
touchEventCapturedByOsc = true; touchEventCapturedByOsc = true;
// NSLog(@"Captured OSC LS_CLK4"); // NSLog(@"Captured OSC LS_CLK4");
+1
View File
@@ -33,6 +33,7 @@
@property BOOL playAudioOnPC; @property BOOL playAudioOnPC;
@property BOOL redirectMic; @property BOOL redirectMic;
@property BOOL swapABXYButtons; @property BOOL swapABXYButtons;
@property BOOL buttonVisualFeedback;
@property BOOL asyncNativeTouchPriority; @property BOOL asyncNativeTouchPriority;
@property int gyroMode; @property int gyroMode;
@property int emulatedControllerType; @property int emulatedControllerType;
+1 -1
View File
@@ -9,5 +9,5 @@
#import "StreamConfiguration.h" #import "StreamConfiguration.h"
@implementation StreamConfiguration @implementation StreamConfiguration
@synthesize host, httpsPort, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, appName, optimizeGameSettings, playAudioOnPC, swapABXYButtons, gyroMode, emulatedControllerType, audioConfiguration, supportedVideoFormats, multiController, serverCert, rtspSessionUrl, serverCodecModeSupport, enableYUV444, enablePIP; @synthesize host, httpsPort, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, appName, optimizeGameSettings, playAudioOnPC, swapABXYButtons, buttonVisualFeedback, gyroMode, emulatedControllerType, audioConfiguration, supportedVideoFormats, multiController, serverCert, rtspSessionUrl, serverCodecModeSupport, enableYUV444, enablePIP;
@end @end
@@ -822,6 +822,7 @@ static NSMutableSet* hostList;
_streamConfig.playAudioOnPC = streamSettings.playAudioOnPC; _streamConfig.playAudioOnPC = streamSettings.playAudioOnPC;
_streamConfig.redirectMic = streamSettings.redirectMic; _streamConfig.redirectMic = streamSettings.redirectMic;
_streamConfig.swapABXYButtons = streamSettings.swapABXYButtons; _streamConfig.swapABXYButtons = streamSettings.swapABXYButtons;
_streamConfig.buttonVisualFeedback = streamSettings.buttonVisualFeedback;
_streamConfig.asyncNativeTouchPriority = streamSettings.asyncNativeTouchPriority; // new streamConfig segment _streamConfig.asyncNativeTouchPriority = streamSettings.asyncNativeTouchPriority; // new streamConfig segment
_streamConfig.gyroMode = [streamSettings.gyroMode intValue]; _streamConfig.gyroMode = [streamSettings.gyroMode intValue];
_streamConfig.emulatedControllerType = streamSettings.emulatedControllerType.intValue; _streamConfig.emulatedControllerType = streamSettings.emulatedControllerType.intValue;