minor fixes for controller navigation

This commit is contained in:
True Zhuanjia
2026-08-02 17:54:28 +08:00
parent a01af9ee21
commit 54ac7f6522
8 changed files with 59 additions and 92 deletions
+31 -80
View File
@@ -33,13 +33,6 @@ private let settingsExcludedControllerNavigationSectionIdentifiers: Set<String>
"SettingsSectionPencil"
]
@available(iOS 13.0, *)
private final class ControllerMouseDisplayLinkTarget: NSObject {
@objc func displayLinkDidFire() {
ControllerNavigator.controllerMouseDisplayLinkDidFire()
}
}
@available(iOS 13.0, *)
private final class ControllerMouseCurvePreviewView: UIView {
var expo: CGFloat = 1.0 {
@@ -256,8 +249,7 @@ final class ControllerNavigator: NSObject {
@objc static var customPositionForStreamingRadialMenuButton: ControllerElementPosition = .left
@objc static var streamingRadialMenuDelay: TimeInterval = 0
private static let controllerMouseDisplayLinkTarget = ControllerMouseDisplayLinkTarget()
private static var controllerMouseDisplayLink: CADisplayLink?
private static var controllerMouseTimer: SafeTimer?
@objc static var controllerMouseStick: ControllerElement = .rightStick
@objc static var controllerMouseLeftButton: ControllerElement = .dpadRight
@objc static var controllerMouseRightButton: ControllerElement = .dpadDown
@@ -386,7 +378,7 @@ final class ControllerNavigator: NSObject {
@objc static func startControllerMouse() {
controllerMouseInputX = 0
controllerMouseInputY = 0
startControllerMouseDisplayLink(frameRate: controllerMouseFrameRate)
startControllerMouseTimer(frameRate: controllerMouseFrameRate)
ControllerUtil.stopListeningPrimaryController()
listenToControllerMouse()
DispatchQueue.main.async {
@@ -410,87 +402,46 @@ final class ControllerNavigator: NSObject {
)
}
/*
@objc static func stopControllerMouse() {
controllerMouseEnabledFlag = false
stopControllerMouseDisplayLink()
}
@objc static func setControllerMouseEnabled(_ enabled: Bool) {
controllerMouseEnabledFlag = mapControllerToMouse && enabled
if !controllerMouseEnabledFlag {
}
}
@objc static func isControllerMouseEnabled() -> Bool {
return controllerMouseEnabledFlag
}
*/
fileprivate static func controllerMouseDisplayLinkDidFire() {
guard radialMenuState == .mouseModeEnabled,
let displayLink = controllerMouseDisplayLink else {
private static func startControllerMouseTimer(frameRate: Int) {
guard radialMenuState == .mouseModeEnabled else {
return
}
// print("controllerMouseDisplayLinkDidFire \(CACurrentMediaTime())")
let delay = 0.5 / Double(max(displayLink.preferredFramesPerSecond, 1))
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + delay) {
guard radialMenuState == .mouseModeEnabled else { return }
let moveVector = PublicUtils.controllerMouseMoveVector(
stickX: controllerMouseInputX,
stickY: controllerMouseInputY,
velocity: controllerMouseVelocity,
expo: controllerMouseExpo
)
if moveVector.dx != 0 || moveVector.dy != 0 {
controllerMouseTimer = SafeTimer(interval: 1/TimeInterval(frameRate)) {
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.002) {
guard radialMenuState == .mouseModeEnabled else { return }
let moveVector = PublicUtils.controllerMouseMoveVector(
stickX: controllerMouseInputX,
stickY: controllerMouseInputY,
velocity: controllerMouseVelocity,
expo: controllerMouseExpo
)
LiSendMouseMoveEvent(clampedInt16(moveVector.dx), clampedInt16(moveVector.dy))
}
let scrollVector = PublicUtils.controllerMouseScrollVector(
stickX: controllerMouseWheelInputX,
stickY: controllerMouseWheelInputY,
multiplier: 15
)
if abs(scrollVector.dy) > abs(scrollVector.dx) {
LiSendHighResScrollEvent(clampedInt16(scrollVector.dy))
}
else {
LiSendHighResHScrollEvent(clampedInt16(scrollVector.dx))
let scrollVector = PublicUtils.controllerMouseScrollVector(
stickX: controllerMouseWheelInputX,
stickY: controllerMouseWheelInputY,
multiplier: 15
)
if abs(scrollVector.dy) > abs(scrollVector.dx) {
LiSendHighResScrollEvent(clampedInt16(scrollVector.dy))
}
else {
LiSendHighResHScrollEvent(clampedInt16(scrollVector.dx))
}
}
}
controllerMouseTimer?.restart()
}
private static func startControllerMouseDisplayLink(frameRate: Int) {
stopControllerMouseDisplayLink()
let displayLink = CADisplayLink(
target: controllerMouseDisplayLinkTarget,
selector: #selector(ControllerMouseDisplayLinkTarget.displayLinkDidFire)
)
if #available(iOS 15.0, tvOS 15.0, *) {
displayLink.preferredFrameRateRange = CAFrameRateRange(
minimum: Float(frameRate),
maximum: Float(frameRate),
preferred: Float(frameRate)
)
} else {
displayLink.preferredFramesPerSecond = frameRate
}
displayLink.add(to: .main, forMode: .common)
controllerMouseDisplayLink = displayLink
}
private static func stopControllerMouseDisplayLink() {
private static func stopControllerMouseTimer() {
controllerMouseInputX = 0
controllerMouseInputY = 0
controllerMouseDisplayLink?.invalidate()
controllerMouseDisplayLink = nil
controllerMouseTimer?.clean()
}
private static func swappedFaceButtonIfNeeded(_ button: ControllerElement, swapABXY: Bool) -> ControllerElement {
guard swapABXY else { return button }
switch button {
@@ -602,7 +553,7 @@ final class ControllerNavigator: NSObject {
updateRadialMenu()
}
else {
stopControllerMouseDisplayLink()
stopControllerMouseTimer()
radialMenuState = .main
updateRadialMenu()
}
@@ -737,7 +688,7 @@ final class ControllerNavigator: NSObject {
private static var radialMenuButtonPressed: Bool = false
private static var radialMenuDelayTimer: SafeTimer?
private static var radialMenuState: RadialMenuState = .main
private static func listenToRadialMenuButton() {
@objc static func listenToRadialMenuButton() {
guard enabled else {return}
guard let mainFrameVC = radialMenuDelegate as? MainFrameViewController else {return}
radialMenuState = .main
+2 -1
View File
@@ -1211,7 +1211,8 @@ double rc_expo(double x, double expo) {
if(![StreamFrameViewController sharedInstance]) return;
MainFrameViewController* mainFrameVC =(MainFrameViewController* )ControllerUtil.delegate;
if(mainFrameVC.settingsExpandedInStreamView) return;
[ControllerUtil stopListeningPrimaryControllerWithStopListenToRadialMenuButton:false];
[ControllerUtil stopListeningPrimaryControllerWithStopListenToRadialMenuButton:true];
if (@available(iOS 13.0, *)) [ControllerNavigator listenToRadialMenuButton];
[self listenToGCController: ControllerUtil.primaryGCController];
if (@available(iOS 13.0, *)){
NSLog(@"ControllerUtil setUINavigationDelegate %f",CACurrentMediaTime());
@@ -40,9 +40,9 @@
<attribute name="controllerGyroBiasX" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerGyroBiasY" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerGyroBiasZ" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMouseExpo" optional="YES" attributeType="Float" defaultValueString="1.6" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMouseExpo" optional="YES" attributeType="Float" defaultValueString="1.8" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMouseLeftButton" attributeType="Integer 32" defaultValueString="8" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMousePointerVelocity" optional="YES" attributeType="Float" defaultValueString="12" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMousePointerVelocity" optional="YES" attributeType="Float" defaultValueString="15" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMouseRightButton" attributeType="Integer 32" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
<attribute name="controllerMouseStick" attributeType="Integer 32" defaultValueString="8388640" usesScalarValueType="NO" syncable="YES"/>
<attribute name="ctrlDownForPinch" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES" syncable="YES"/>
+1 -1
View File
@@ -109,7 +109,7 @@ import UIKit
}
@objc public static func isFirstTappingGameProfileSelectorFromMainFrame() -> Bool {
let key = "hasTappedGameProfileSelectorFromMainFrame-202600801"
let key = "hasTappedGameProfileSelectorFromMainFrame-202600801-2"
let defaults = UserDefaults.standard
let launchedBefore = defaults.bool(forKey: key)
if !launchedBefore {
+6
View File
@@ -35,6 +35,12 @@ public extension CGPoint {
}
}
public extension CGVector {
var isNotZero: Bool {
dx != 0 && dx != 0
}
}
public extension Array where Element: Equatable {
@discardableResult
mutating func appendIfNotContains(_ newElement: Element) -> Bool {
+7 -2
View File
@@ -229,9 +229,14 @@ import UIKit
}
@objc public static func controllerMouseMoveVector(stickX: CGFloat, stickY: CGFloat, velocity: CGFloat, expo: CGFloat) -> CGVector {
let hypot = hypot(stickX, stickY)
guard hypot > 0 else {return CGVector(dx: 0, dy: 0)}
let targetHypot = controllerMouseExpoMappedOffset(hypot, expo: expo)
let targetX = targetHypot * (stickX/hypot)
let targetY = targetHypot * (stickY/hypot)
return CGVector(
dx: velocity * controllerMouseExpoMappedOffset(stickX, expo: expo),
dy: -velocity * controllerMouseExpoMappedOffset(stickY, expo: expo)
dx: targetX * velocity,
dy: -targetY * velocity
)
}
@@ -1908,6 +1908,8 @@ static NSMutableSet* hostList;
settings.controllerMouseStick = @(ControllerElementRightStick);
settings.controllerMouseLeftButton = @(ControllerElementDpadRight);
settings.controllerMouseRightButton = @(ControllerElementDpadUp);
settings.controllerMouseExpo = @(1.8);
settings.controllerMousePointerVelocity = @(15.0);
if (@available(iOS 14.0, tvOS 14.0, *)) nil;
else settings.appTheme = @(UIUserInterfaceStyleDark);
@@ -2809,12 +2811,12 @@ static NSMutableSet* hostList;
countdown:6
action:^{}
completion:^{
if(!self.gameProfileSelectorVC && !self.settingsViewController.layoutOnScreenControlsVC) [self openGameProfileSeletorWithAnimated:true];
dispatch_async(dispatch_get_main_queue(), ^{
[self openGameProfileSeletorWithAnimated:false];
});
}];
}
else if(!self.gameProfileSelectorVC && !self.settingsViewController.layoutOnScreenControlsVC) [self openGameProfileSeletorWithAnimated:true];
else if (self.gameProfileSelectorVC) [self.gameProfileSelectorVC.profileSelectorViewController dismissViewControllerAnimated:true completion:^{}];
else if (self.settingsViewController.layoutOnScreenControlsVC) [self.settingsViewController.layoutOnScreenControlsVC.profileSelectorViewController dismissViewControllerAnimated:true completion:^{}];
else [self openGameProfileSeletorWithAnimated:true];
break;
case RadialMenuItemHostView:
[self switchToHostView];
@@ -3236,15 +3236,17 @@ BOOL isCustomResolution(int resolutionSelected) {
return;
}
// self.layoutOnScreenControlsVC.view.backgroundColor = [UIColor colorWithWhite:0.55 alpha:1.0];
self.layoutOnScreenControlsVC.view.backgroundColor = UIColor.clearColor;
self.layoutOnScreenControlsVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
self.layoutOnScreenControlsVC.profileSelectorLoadingMode = ProfileSelectorLoadingModeSelectProfileFromMainFrame;
[self presentViewController:self.layoutOnScreenControlsVC animated:NO completion:^{
[self->_layoutOnScreenControlsVC presentProfileSelectorWith:ProfileSelectorLoadingModeSelectProfileFromMainFrame animated:animated];
}];
_layoutOnScreenControlsVC.toolbarStackView.hidden = true;
_layoutOnScreenControlsVC.toolbarRootView.hidden = true;
self->_layoutOnScreenControlsVC.toolbarStackView.hidden = true;
self->_layoutOnScreenControlsVC.toolbarRootView.hidden = true;
}
- (LayoutOnScreenControlsViewController *)instantiateOscLayoutViewController {