diff --git a/VoidLink/Base.lproj/iPad.storyboard b/VoidLink/Base.lproj/iPad.storyboard index f013e44d..0affe068 100644 --- a/VoidLink/Base.lproj/iPad.storyboard +++ b/VoidLink/Base.lproj/iPad.storyboard @@ -1385,14 +1385,14 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1892,6 +1932,8 @@ + + @@ -1943,6 +1985,8 @@ + + @@ -2501,7 +2545,7 @@ - + @@ -2826,7 +2870,7 @@ - + @@ -2835,13 +2879,13 @@ - + - + - + diff --git a/VoidLink/Base.lproj/iPhone.storyboard b/VoidLink/Base.lproj/iPhone.storyboard index dc577860..08219725 100644 --- a/VoidLink/Base.lproj/iPhone.storyboard +++ b/VoidLink/Base.lproj/iPhone.storyboard @@ -557,7 +557,7 @@ - + @@ -2200,14 +2200,14 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2750,6 +2790,8 @@ + + @@ -2800,6 +2842,8 @@ + + @@ -2868,19 +2912,19 @@ - + - + - + - + diff --git a/VoidLink/Input/ControllerSupport.m b/VoidLink/Input/ControllerSupport.m index 31572b37..562f135d 100644 --- a/VoidLink/Input/ControllerSupport.m +++ b/VoidLink/Input/ControllerSupport.m @@ -67,7 +67,10 @@ static const double MOUSE_SPEED_DIVISOR = 1.25; float _stickToMouseVelocity; CADisplayLink *_displayLink; - + float stickMaxOffset; + float _leftStickMinOffset; + float _rightStickMinOffset; + OnScreenControls *_osc; VoidController *_oscController; NSMutableSet* _activeGCControllers; @@ -1210,13 +1213,23 @@ double rc_expo(double x, double expo) { } else if(buttonFlagId.intValue!=self->_controllerMouseSwitch || !self->_mapControllerToMouse) UPDATE_BUTTON_FLAG(voidController, buttonFlagId.intValue, button.pressed); } + + CGFloat leftStickXRaw = gamepad.leftThumbstick.xAxis.value * self->stickMaxOffset; + CGFloat leftStickYRaw = gamepad.leftThumbstick.yAxis.value * self->stickMaxOffset; - leftStickX = self->_controllerMouseEnabledFlag ? 0 :gamepad.leftThumbstick.xAxis.value * 0x7FFE; - leftStickY = self->_controllerMouseEnabledFlag ? 0 : gamepad.leftThumbstick.yAxis.value * 0x7FFE; + CGFloat rightStickXRaw = gamepad.rightThumbstick.xAxis.value * self->stickMaxOffset; + CGFloat rightStickYRaw = gamepad.rightThumbstick.yAxis.value * self->stickMaxOffset; + - rightStickX = self->_controllerMouseEnabledFlag ? 0 : gamepad.rightThumbstick.xAxis.value * 0x7FFE; - rightStickY = self->_controllerMouseEnabledFlag ? 0 : gamepad.rightThumbstick.yAxis.value * 0x7FFE; + CGVector leftStickOffset = [ControllerUtil compensatedWithOffsetVector:CGVectorMake(leftStickXRaw, leftStickYRaw) withMinOffset:self->_leftStickMinOffset]; + CGVector rightStickOffset = [ControllerUtil compensatedWithOffsetVector:CGVectorMake(rightStickXRaw, rightStickYRaw) withMinOffset:self->_rightStickMinOffset]; + + leftStickX = self->_controllerMouseEnabledFlag ? 0 : leftStickOffset.dx; + leftStickY = self->_controllerMouseEnabledFlag ? 0 : leftStickOffset.dy; + + rightStickX = self->_controllerMouseEnabledFlag ? 0 : rightStickOffset.dx; + rightStickY = self->_controllerMouseEnabledFlag ? 0 : rightStickOffset.dy; if(self->_controllerMouseEnabledFlag){ self->stickToMouseInputX = self->_controllerMouseStick == LeftStickToMouse ? gamepad.leftThumbstick.xAxis.value : gamepad.rightThumbstick.xAxis.value; @@ -1751,6 +1764,10 @@ double rc_expo(double x, double expo) { _controllerGyroSwitchTogglePressed = false; _controllerGyroSwitchHoldPressed = false; + stickMaxOffset = 0x7FFE; + _leftStickMinOffset = oscProfile.physicalLeftStickMinOffset; + _rightStickMinOffset = oscProfile.physicalRightStickMinOffset; + if(oscProfile.controllerGyroSwitchMode == ControllerGyroSwitchDisabled && ![self useMotionHandler]) _gyroEnabledFlag = true; if(![self useMotionHandler]) [self->motionHandler stopGyroUpdateWithInterruptNoneGyroInput:false resetLeftStick:true]; diff --git a/VoidLink/Input/ControllerUtil.swift b/VoidLink/Input/ControllerUtil.swift index aecd169c..0da2dd7b 100644 --- a/VoidLink/Input/ControllerUtil.swift +++ b/VoidLink/Input/ControllerUtil.swift @@ -51,7 +51,9 @@ import GameController @objc class ControllerUtil: NSObject { - + + static private let stickMaxOffset:CGFloat = 0x7FFE + @objc static func listen( controller: GCController, swapABXY: Bool, @@ -74,8 +76,8 @@ import GameController handler(buttonDict, gamepad, element) } } - - + + // MARK: - 构建按钮映射 private static func buildMapping(for controller: GCController, swapABXY:Bool) -> [ControllerButton : GCControllerButtonInput] @@ -125,7 +127,7 @@ import GameController if let home = pad.buttonHome { result[.special] = home } - + if let controller = pad.controller { let profile = controller.physicalInputProfile if let paddle1 = profile.buttons[GCInputXboxPaddleOne] { @@ -189,4 +191,13 @@ import GameController case .null: return SwiftLocalizationHelper.localizedString(forKey: "Null") } } + + @objc static func compensated(offsetVector: CGVector, withMinOffset minOffset: CGFloat) -> CGVector{ + let vectorHypot = hypot(offsetVector.dx, offsetVector.dy) + guard vectorHypot > 0 else {return CGVector(dx: 0, dy: 0)} + let targetHypot = minOffset + (stickMaxOffset-minOffset)*(vectorHypot/stickMaxOffset) + let compensatedX = targetHypot * (offsetVector.dx/vectorHypot) + let compensatedY = targetHypot * (offsetVector.dy/vectorHypot) + return CGVector(dx: compensatedX, dy: compensatedY) + } } diff --git a/VoidLink/Input/CustomOSC/OSCProfile.h b/VoidLink/Input/CustomOSC/OSCProfile.h index f394a190..7cae79cb 100644 --- a/VoidLink/Input/CustomOSC/OSCProfile.h +++ b/VoidLink/Input/CustomOSC/OSCProfile.h @@ -42,6 +42,8 @@ typedef NS_ENUM(NSInteger, MapGyroTo) { @property (nonatomic, assign) CGFloat accelSensitivityY; @property (nonatomic, assign) CGFloat accelSensitivityZ; @property (nonatomic, assign) double gyroToStickMinOffset; +@property (nonatomic, assign) double physicalLeftStickMinOffset; +@property (nonatomic, assign) double physicalRightStickMinOffset; @property (nonatomic, assign) int controllerGyroSwitchMode; @property (nonatomic, assign) bool reverseGyroHoldButton; @property (nonatomic, assign) int controllerGyroSwitchHold; diff --git a/VoidLink/Input/CustomOSC/OSCProfile.m b/VoidLink/Input/CustomOSC/OSCProfile.m index 1a25c9f9..81917b36 100644 --- a/VoidLink/Input/CustomOSC/OSCProfile.m +++ b/VoidLink/Input/CustomOSC/OSCProfile.m @@ -44,6 +44,8 @@ [encoder encodeFloat:self.accelSensitivityY forKey:@"accelSensitivityY"]; [encoder encodeFloat:self.accelSensitivityZ forKey:@"accelSensitivityZ"]; [encoder encodeDouble:self.gyroToStickMinOffset forKey:@"gyroToStickMinOffset"]; + [encoder encodeDouble:self.physicalLeftStickMinOffset forKey:@"physicalLeftStickMinOffset"]; + [encoder encodeDouble:self.physicalRightStickMinOffset forKey:@"physicalRightStickMinOffset"]; [encoder encodeInt:self.controllerGyroSwitchMode forKey:@"controllerGyroSwitchMode"]; [encoder encodeBool:self.reverseGyroHoldButton forKey:@"reverseGyroHoldButton"]; [encoder encodeInt:self.controllerGyroSwitchHold forKey:@"controllerGyroSwitchHold"]; @@ -66,6 +68,8 @@ self.accelSensitivityY = [decoder containsValueForKey:@"accelSensitivityY"] ? [decoder decodeFloatForKey:@"accelSensitivityY"] : 1.0; self.accelSensitivityZ = [decoder containsValueForKey:@"accelSensitivityZ"] ? [decoder decodeFloatForKey:@"accelSensitivityZ"] : 1.0; self.gyroToStickMinOffset = [decoder containsValueForKey:@"gyroToStickMinOffset"] ? [decoder decodeDoubleForKey:@"gyroToStickMinOffset"] : 0; + self.physicalLeftStickMinOffset = [decoder containsValueForKey:@"physicalLeftStickMinOffset"] ? [decoder decodeDoubleForKey:@"physicalLeftStickMinOffset"] : 0; + self.physicalRightStickMinOffset = [decoder containsValueForKey:@"physicalRightStickMinOffset"] ? [decoder decodeDoubleForKey:@"physicalRightStickMinOffset"] : 0; self.controllerGyroSwitchMode = [decoder containsValueForKey:@"controllerGyroSwitchMode"] ? [decoder decodeIntForKey:@"controllerGyroSwitchMode"] : ControllerGyroSwitchDisabled; self.reverseGyroHoldButton = [decoder containsValueForKey:@"reverseGyroHoldButton"] ? [decoder decodeBoolForKey:@"reverseGyroHoldButton"] : false; self.controllerGyroSwitchHold = [decoder containsValueForKey:@"controllerGyroSwitchHold"] ? [decoder decodeIntForKey:@"controllerGyroSwitchHold"] : ControllerButtonNull; @@ -91,6 +95,8 @@ copy.accelSensitivityY = self.accelSensitivityY; copy.accelSensitivityZ = self.accelSensitivityZ; copy.gyroToStickMinOffset = self.gyroToStickMinOffset; + copy.physicalLeftStickMinOffset = self.physicalLeftStickMinOffset; + copy.physicalRightStickMinOffset = self.physicalRightStickMinOffset; copy.controllerGyroSwitchMode = self.controllerGyroSwitchMode; copy.reverseGyroHoldButton = self.reverseGyroHoldButton; copy.controllerGyroSwitchHold = self.controllerGyroSwitchHold; diff --git a/VoidLink/Input/MotionHandler.swift b/VoidLink/Input/MotionHandler.swift index abdee09a..82e0e2e4 100644 --- a/VoidLink/Input/MotionHandler.swift +++ b/VoidLink/Input/MotionHandler.swift @@ -304,21 +304,24 @@ import CoreMotion if oscProfile.yawPitchToRightStick { yaw = rightStickTouchInputX + rightStickPhysicalInputX + gyroInputToStickInput(input:yawSource*sensitvityYaw*widgetYawFactor*10) yaw = self.clampStickInput(input: yaw) - yaw = (yaw >= 0 ? 1.0 : -1.0) * gyroToStickMinOffset + (self.stickMaxOffset - gyroToStickMinOffset) * (yaw/self.stickMaxOffset) pitch = rightStickTouchInputY + rightStickPhysicalInputY - gyroInputToStickInput(input:pitchSource*sensitvityPitch*widgetPitchFactor*10) pitch = self.clampStickInput(input: pitch) - pitch = (pitch >= 0 ? 1.0 : -1.0) * gyroToStickMinOffset + (self.stickMaxOffset - gyroToStickMinOffset) * (pitch/self.stickMaxOffset) - - self.onScreenControls.sendRightStickTouchPadEvent(yaw, pitch) + + let offsetVector = ControllerUtil.compensated(offsetVector: CGVector(dx: yaw, dy: pitch), withMinOffset: gyroToStickMinOffset) + + self.onScreenControls.sendRightStickTouchPadEvent(offsetVector.dx, offsetVector.dy) } if oscProfile.rollToLeftStick { roll = gyroInputToStickInput(input:rollSource*sensitvityRoll*widgetRollFactor*0.2) rollIntegral = rollIntegral + roll - var mixedLeftStickOffset = self.clampStickInput(input: rollIntegral+leftStickTouchInputX+leftStickPhysicalInputX) - mixedLeftStickOffset = (mixedLeftStickOffset >= 0 ? 1.0 : -1.0) * gyroToStickMinOffset + (self.stickMaxOffset - gyroToStickMinOffset) * (mixedLeftStickOffset/self.stickMaxOffset) - self.onScreenControls.sendLeftStickTouchPadEvent(mixedLeftStickOffset, leftStickTouchInputY+leftStickPhysicalInputY) + let mixedLeftStickOffsetX = self.clampStickInput(input: rollIntegral+leftStickTouchInputX+leftStickPhysicalInputX) + let mixedLeftStickOffsetY = self.clampStickInput(input: leftStickTouchInputY+leftStickPhysicalInputY) + + let offsetVector = ControllerUtil.compensated(offsetVector: CGVector(dx: mixedLeftStickOffsetX, dy: mixedLeftStickOffsetY), withMinOffset: gyroToStickMinOffset) + + self.onScreenControls.sendLeftStickTouchPadEvent(offsetVector.dx, offsetVector.dy) } } } diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 23e470b8..8a189f5d 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -1291,31 +1291,29 @@ import UIKit } private func sendRightStickTouchPadEvent(inputX: CGFloat, inputY: CGFloat){ - var targetX = self.touchInputToStickInput(input: inputX) - var targetY = -self.touchInputToStickInput(input: inputY) - // vertical input must be inverted - + let targetX = self.touchInputToStickInput(input: inputX) + let targetY = -self.touchInputToStickInput(input: inputY) let mixRightStickInputToGyro = (oscProfile.mapGyroTo == MapGyroTo.mapGyroToControllerStick && oscProfile.yawPitchToRightStick) if !mixRightStickInputToGyro || (self.motionHandler.gyroMixInputStarted() != true) { - targetX = (targetX >= 0 ? 1.0 : -1.0) * self.minStickOffset + (self.stickMaxOffset - self.minStickOffset) * (targetX/self.stickMaxOffset) - targetY = (targetY >= 0 ? 1.0 : -1.0) * self.minStickOffset + (self.stickMaxOffset - self.minStickOffset) * (targetY/self.stickMaxOffset) - self.onScreenControls.sendRightStickTouchPadEvent(targetX, targetY) + + let offsetVector = ControllerUtil.compensated(offsetVector: CGVector(dx: targetX, dy: targetY), withMinOffset: minStickOffset) + self.onScreenControls.sendRightStickTouchPadEvent(offsetVector.dx, offsetVector.dy) } self.motionHandler.mixOnScreenRightStickAndGyroInput(x: targetX, y: targetY) } private func sendLeftStickTouchPadEvent(inputX: CGFloat, inputY: CGFloat){ - var targetX = self.touchInputToStickInput(input: inputX) - var targetY = -self.touchInputToStickInput(input: inputY) - targetX = (targetX >= 0 ? 1.0 : -1.0) * self.minStickOffset + (self.stickMaxOffset - self.minStickOffset) * (targetX/self.stickMaxOffset) - targetY = (targetY >= 0 ? 1.0 : -1.0) * self.minStickOffset + (self.stickMaxOffset - self.minStickOffset) * (targetY/self.stickMaxOffset) + let targetX = self.touchInputToStickInput(input: inputX) + let targetY = -self.touchInputToStickInput(input: inputY) let mixLeftStickInputToGyro = (oscProfile.mapGyroTo == MapGyroTo.mapGyroToControllerStick && oscProfile.rollToLeftStick) if !mixLeftStickInputToGyro || (self.motionHandler.gyroMixInputStarted() != true) { - self.onScreenControls.sendLeftStickTouchPadEvent(targetX, targetY) + + let offsetVector = ControllerUtil.compensated(offsetVector: CGVector(dx: targetX, dy: targetY), withMinOffset: minStickOffset) + self.onScreenControls.sendLeftStickTouchPadEvent(offsetVector.dx, offsetVector.dy) } self.motionHandler.mixOnScreenLeftStickAndGyroInput(x: targetX, y: targetY) } diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index 04e68705..6c948f68 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -1497,25 +1497,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Gyro toggle button: %@\nGyro hold-down button: %@" + "value" : "Gyro toggle button: %@\nGyro hold-down button: %@\n\nThese buttons are able to switch DS4 gyro mapping on & off when enabled." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "陀螺仪切换按键: %@\n陀螺仪保持按键: %@" + "value" : "陀螺仪切换按键: %@\n陀螺仪保持按键: %@\n\n以上按键被启用后,也可用于启动/暂停DS4陀螺仪映射" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "陀螺儀切換按鍵: %@\n陀螺儀保持按鍵: %@" + "value" : "陀螺儀切換按鍵: %@\n陀螺儀保持按鍵: %@\n\n以上按鍵啟用後,也可用於啟動/暫停 DS4 陀螺儀映射。" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "陀螺儀切換按鍵: %@\n陀螺儀保持按鍵: %@" + "value" : "陀螺儀切換按鍵: %@\n陀螺儀保持按鍵: %@\n\n以上按鍵啟用後,也可用於啟動/暫停 DS4 陀螺儀映射。" } } } @@ -2788,35 +2788,6 @@ } } }, - "gyroModeStackDoc" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/uscwmv3vz8g30rmk" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3" - } - }, - "zh-HK" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3" - } - } - } - }, "gyroModeStackTip" : { "extractionState" : "manual", "localizations" : { @@ -3520,6 +3491,35 @@ } } }, + "mapGyroToStackTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "- To map gyro directly to mouse/stick, must turn off DS4 gyro mapping in “Controller” section.\n\n- All settings in “Motion Control” section are saved with on-screen widget profile, which can be selected & managed in the right edge slide toolbox menu.\n\n- Motion control can be turned on & off by controller buttons or on-screen buttons" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "- 关闭“手柄”菜单分区的DS4陀螺仪映射后, 方可将陀螺仪直接映射为手柄或鼠标。\n\n- “体感控制”菜单分区的所有设置均保存在屏显控件配置中,可在右边缘滑出的工具箱菜单中切换。\n\n- 体感控制陀螺仪可由手柄按键或屏显按键开关。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "- 關閉「手柄」選單分區的 DS4 陀螺儀映射後,方可將陀螺儀直接映射為手柄或滑鼠。\n\n- 「體感控制」選單分區的所有設定皆儲存在螢幕顯示小工具配置中,可在右邊緣滑出的工具箱選單中切換。\n\n- 體感控制陀螺儀可由手把按鍵或螢幕顯示按鍵開關。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "- 關閉「手柄」選單分區的 DS4 陀螺儀映射後,方可將陀螺儀直接映射為手柄或滑鼠。\n\n- 「體感控制」選單分區的所有設定皆儲存在螢幕顯示小工具配置中,可在右邊緣滑出的工具箱選單中切換。\n\n- 體感控制陀螺儀可由手把按鍵或螢幕顯示按鍵開關。" + } + } + } + }, "micPermissionTip" : { "extractionState" : "manual", "localizations" : { @@ -4655,6 +4655,35 @@ } } }, + "physicaStickMinOffsetTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This is saved in onscreen widget profile, which can be selected & managed in toolbox menu slide from the right screen edge." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "此项设置保存在屏显控件配置方案中, 可在屏幕右边缘滑出的工具箱菜单中切换。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "此項設定儲存在螢幕小工具配置方案中,可在螢幕右邊緣滑出的工具箱選單中切換。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "此項設定儲存在螢幕小工具配置方案中,可在螢幕右邊緣滑出的工具箱選單中切換。" + } + } + } + }, "pipStackTip" : { "extractionState" : "manual", "localizations" : { @@ -5606,6 +5635,35 @@ } } }, + "reverseHoldButtonStackTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When enabled, the gyro-hold button becomes a gyro-pause button: holding it down pauses the gyro, and releasing it reactivates it." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用该项后,陀螺仪保持按键变为陀螺仪暂停按键。按住暂停陀螺仪,松开重新启动陀螺仪。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "啟用此項後,陀螺儀保持按鍵將變為陀螺儀暫停按鍵。按住可暫停陀螺儀,鬆開則重新啟動陀螺儀。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "啟用此項後,陀螺儀保持按鍵將變為陀螺儀暫停按鍵。按住可暫停陀螺儀,鬆開則重新啟動陀螺儀。" + } + } + } + }, "right" : { "extractionState" : "manual", "localizations" : { @@ -7182,6 +7240,35 @@ } } }, + "yourMotionControlSoution" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/watpxdpsogirwie0" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/iy4zgh86odhfgf6h" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/iy4zgh86odhfgf6h" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/iy4zgh86odhfgf6h" + } + } + } + }, "yuv444StackTip" : { "extractionState" : "manual", "localizations" : { diff --git a/VoidLink/ViewControllers/SettingsViewController.h b/VoidLink/ViewControllers/SettingsViewController.h index 5d12bed6..8576fce1 100644 --- a/VoidLink/ViewControllers/SettingsViewController.h +++ b/VoidLink/ViewControllers/SettingsViewController.h @@ -232,6 +232,12 @@ @property (strong, nonatomic) IBOutlet UIStackView *reverseHoldButtonStack; @property (strong, nonatomic) IBOutlet UISwitch *reverseHoldButtonSwitch; +@property (strong, nonatomic) IBOutlet UIStackView *leftStickMinOffsetStack; +@property (strong, nonatomic) IBOutlet UISlider *leftStickMinOffsetSlider; + +@property (strong, nonatomic) IBOutlet UIStackView *rightStickMinOffsetStack; +@property (strong, nonatomic) IBOutlet UISlider *rightStickMinOffsetSlider; + @property (strong, nonatomic) IBOutlet UIStackView *testStack; @property (nonatomic, strong) MicHandler *micHandler; diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index b6a9a4ad..139ea844 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -352,7 +352,7 @@ BOOL isCustomResolution(int resolutionSelected) { NSLog(@"Mic error: %@", error); } -- (void)reloadMotionControlConfigs{ +- (void)reloadGameProfileConfigs{ oscProfile = [oscProfileMan getSelectedProfile]; self.controllerGyroSwitchButtonSetter.selectedSegmentIndex = oscProfile.controllerGyroSwitchMode; @@ -384,10 +384,15 @@ BOOL isCustomResolution(int resolutionSelected) { [self.gyroToStickMinOffsetSlider setValue:(uint16_t)oscProfile.gyroToStickMinOffset]; [self gyroMinStickOffsetSliderMoved:self.gyroToStickMinOffsetSlider]; + [self.leftStickMinOffsetSlider setValue:(uint16_t)oscProfile.physicalLeftStickMinOffset]; + [self leftStickMinOffsetSliderMoved:self.leftStickMinOffsetSlider]; + [self.rightStickMinOffsetSlider setValue:(uint16_t)oscProfile.physicalRightStickMinOffset]; + [self rightStickMinOffsetSliderMoved:self.rightStickMinOffsetSlider]; + [self.synthPhysicalInputSwitch setOn:oscProfile.synthesizePhysicalStick]; } -- (void)saveMotionControlConfigs{ +- (void)saveGameProfileConfigs{ CGFloat yawSensitivityPercent = [self map_velocFactorDisplay_fromSliderValue:self.yawSensitivitySlider.value]; CGFloat pitchSensitivityPercent = [self map_velocFactorDisplay_fromSliderValue:self.pitchSensitivitySlider.value]; @@ -403,6 +408,8 @@ BOOL isCustomResolution(int resolutionSelected) { && oscProfile.synthesizePhysicalStick == self.synthPhysicalInputSwitch.isOn && oscProfile.controllerGyroSwitchMode == self.controllerGyroSwitchButtonSetter.selectedSegmentIndex && oscProfile.reverseGyroHoldButton == self.reverseHoldButtonSwitch.isOn + && (int16_t)(oscProfile.physicalLeftStickMinOffset) == (int16_t)self.leftStickMinOffsetSlider.value + && (int16_t)(oscProfile.physicalRightStickMinOffset) == (int16_t)self.rightStickMinOffsetSlider.value ); if(!configNotChanged){ @@ -416,6 +423,8 @@ BOOL isCustomResolution(int resolutionSelected) { oscProfile.synthesizePhysicalStick = self.synthPhysicalInputSwitch.isOn; oscProfile.controllerGyroSwitchMode = (int)self.controllerGyroSwitchButtonSetter.selectedSegmentIndex; oscProfile.reverseGyroHoldButton = self.reverseHoldButtonSwitch.isOn; + oscProfile.physicalLeftStickMinOffset = (int16_t)self.leftStickMinOffsetSlider.value; + oscProfile.physicalRightStickMinOffset = (int16_t)self.rightStickMinOffsetSlider.value; [oscProfileMan replaceSelectedProfileWith:oscProfile overwriteDefault:YES]; } } @@ -442,7 +451,7 @@ BOOL isCustomResolution(int resolutionSelected) { object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(reloadMotionControlConfigs) + selector:@selector(reloadGameProfileConfigs) name:@"OscLayoutCloseNotification" object:nil]; @@ -496,7 +505,7 @@ BOOL isCustomResolution(int resolutionSelected) { }; */ - [self reloadMotionControlConfigs]; + [self reloadGameProfileConfigs]; self->tempSettings = [self->dataMan getSettings]; } @@ -785,6 +794,8 @@ BOOL isCustomResolution(int resolutionSelected) { [self addSetting:self.emulatedControllerTypeStack ofId:@"emulatedControllerTypeStack" withInfoTag:YES withDynamicLabel:NO to:controllerSection]; [self addSetting:self.gyroModeStack ofId:@"gyroModeStack" withInfoTag:YES withDynamicLabel:YES to:controllerSection]; [self addSetting:self.gyroSensitivityStack ofId:@"gyroSensitivityStack" withInfoTag:NO withDynamicLabel:YES to:controllerSection]; + [self addSetting:self.leftStickMinOffsetStack ofId:@"leftStickMinOffsetStack" withInfoTag:YES withDynamicLabel:YES to:controllerSection]; + [self addSetting:self.rightStickMinOffsetStack ofId:@"rightStickMinOffsetStack" withInfoTag:YES withDynamicLabel:YES to:controllerSection]; [self addSetting:self.controllerToMouseStack ofId:@"controllerToMouseStack" withInfoTag:YES withDynamicLabel:YES to:controllerSection]; [self addSetting:self.controllerMouseVelocityStack ofId:@"controllerMouseVelocityStack" withInfoTag:NO withDynamicLabel:YES to:controllerSection]; [self addSetting:self.controllerMouseExpoStack ofId:@"controllerMouseExpoStack" withInfoTag:YES withDynamicLabel:YES to:controllerSection]; @@ -800,7 +811,7 @@ BOOL isCustomResolution(int resolutionSelected) { } [self addSetting:self.controllerGyroSwitchButtonStack ofId:@"controllerGyroSwitchButtonStack" withInfoTag:YES withDynamicLabel:YES to:motionControlSection]; [self addSetting:self.reverseHoldButtonStack ofId:@"reverseHoldButtonStack" withInfoTag:YES withDynamicLabel:YES to:motionControlSection]; - [self addSetting:self.mapGyroToStack ofId:@"mapGyroToStack" withInfoTag:NO withDynamicLabel:NO to:motionControlSection]; + [self addSetting:self.mapGyroToStack ofId:@"mapGyroToStack" withInfoTag:YES withDynamicLabel:NO to:motionControlSection]; [self addSetting:self.gyroToStickSwitchStack ofId:@"gyroToStickStack" withInfoTag:NO withDynamicLabel:NO to:motionControlSection]; [self addSetting:self.yawPitchSensitivityStack ofId:@"yawPitchSensitivityStack" withInfoTag:NO withDynamicLabel:NO to:motionControlSection]; [self addDynamicLabelForStack:self.yawSensitivityStack]; @@ -1328,11 +1339,19 @@ BOOL isCustomResolution(int resolutionSelected) { showOnlineDocAction = true; onlineDocLink = [LocalizationHelper localizedStringForKey:@"emulatedControllerTypeStackDoc"]; } + if([sender.superview.accessibilityIdentifier isEqualToString: @"gyroModeStack"]){ tipText = [LocalizationHelper localizedStringForKey:@"gyroModeStackTip"]; showOnlineDocAction = true; - onlineDocLink = [LocalizationHelper localizedStringForKey:@"gyroModeStackDoc"]; + onlineDocLink = [LocalizationHelper localizedStringForKey:@"yourMotionControlSoution"]; } + if([sender.superview.accessibilityIdentifier isEqualToString: @"mapGyroToStack"]){ + tipText = [LocalizationHelper localizedStringForKey:@"mapGyroToStackTip"]; + showOnlineDocAction = true; + onlineDocLink = [LocalizationHelper localizedStringForKey:@"yourMotionControlSoution"]; + } + + if([sender.superview.accessibilityIdentifier isEqualToString: @"renderingBackendStack"]){ tipText = [LocalizationHelper localizedStringForKey:@"renderingBackendStackTip"]; showOnlineDocAction = false; @@ -1388,7 +1407,19 @@ BOOL isCustomResolution(int resolutionSelected) { tipText = [LocalizationHelper localizedStringForKey:@"controllerToMouseStackTip", [ControllerUtil stringFor:tempSettings.controllerMouseSwitch.intValue], [LocalizationHelper localizedStringForKey:tempSettings.controllerMouseStick.intValue == LeftStickToMouse ? @"Left stick" : @"Right stick"], [ControllerUtil stringFor:tempSettings.controllerMouseLeftButton.intValue], [ControllerUtil stringFor:tempSettings.controllerMouseRightButton.intValue]]; showOnlineDocAction = false; } - + if([sender.superview.accessibilityIdentifier isEqualToString: @"reverseHoldButtonStack"]){ + tipText = [LocalizationHelper localizedStringForKey:@"reverseHoldButtonStackTip"]; + showOnlineDocAction = false; + } + if([sender.superview.accessibilityIdentifier isEqualToString: @"leftStickMinOffsetStack"]){ + tipText = [LocalizationHelper localizedStringForKey:@"physicaStickMinOffsetTip"]; + showOnlineDocAction = false; + } + if([sender.superview.accessibilityIdentifier isEqualToString: @"rightStickMinOffsetStack"]){ + tipText = [LocalizationHelper localizedStringForKey:@"physicaStickMinOffsetTip"]; + showOnlineDocAction = false; + } + UIAlertController *tipsAlertController = [UIAlertController alertControllerWithTitle: [LocalizationHelper localizedStringForKey:@"Tips"] message:tipText preferredStyle:UIAlertControllerStyleAlert]; @@ -1810,7 +1841,10 @@ BOOL isCustomResolution(int resolutionSelected) { [self.emulatedControllerTypeSelector setSelectedSegmentIndex:[self controllerTypeToSegmentIndex:self->tempSettings.emulatedControllerType.intValue]]; [self.emulatedControllerTypeSelector addTarget:self action:@selector(emulatedControllerTypeChanged:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self emulatedControllerTypeChanged:self.emulatedControllerTypeSelector]; - + + [self.leftStickMinOffsetSlider addTarget:self action:@selector(leftStickMinOffsetSliderMoved:) forControlEvents:UIControlEventValueChanged]; + [self.rightStickMinOffsetSlider addTarget:self action:@selector(rightStickMinOffsetSliderMoved:) forControlEvents:UIControlEventValueChanged]; + [self.audioOnPcSwitch setOn:self->tempSettings.playAudioOnPC]; [self.localVolumeSlider setValue:self->tempSettings.localVolume.floatValue*100]; @@ -2521,6 +2555,14 @@ BOOL isCustomResolution(int resolutionSelected) { [self findDynamicLabelFromStack:_gyroToStickMinOffsetStack].text = [NSString stringWithFormat:@" %d ", (int16_t)sender.value]; } +- (void)leftStickMinOffsetSliderMoved:(UISlider* )sender{ + [self findDynamicLabelFromStack:_leftStickMinOffsetStack].text = [NSString stringWithFormat:@" %d ", (int16_t)sender.value]; +} + +- (void)rightStickMinOffsetSliderMoved:(UISlider* )sender{ + [self findDynamicLabelFromStack:_rightStickMinOffsetStack].text = [NSString stringWithFormat:@" %d ", (int16_t)sender.value]; +} + - (void)invokeOscLayout{ // init CustomOSC stuff /* sets a reference to the correct 'LayoutOnScreenControlsViewController' depending on whether the user is on an iPhone or iPad */ @@ -3212,7 +3254,7 @@ BOOL isCustomResolution(int resolutionSelected) { if(![MicHandler permissionGranted]) [self.redirectMicSwitch setOn:false]; - [self saveMotionControlConfigs]; + [self saveGameProfileConfigs]; } - (void) saveSettings { diff --git a/VoidLink/mul.lproj/iPad.xcstrings b/VoidLink/mul.lproj/iPad.xcstrings index fe6978fc..a14352a0 100644 --- a/VoidLink/mul.lproj/iPad.xcstrings +++ b/VoidLink/mul.lproj/iPad.xcstrings @@ -163,6 +163,36 @@ } } }, + "3XV-jL-NYF.text" : { + "comment" : "Class = \"UILabel\"; text = \"Left Stick Minimum Offset\"; ObjectID = \"3XV-jL-NYF\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Left Stick Minimum Offset" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "左摇杆最小偏移" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "左搖桿最小偏移" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "左搖桿最小偏移" + } + } + } + }, "4FU-iP-c6T.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; 4FU-iP-c6T.segmentTitles[0] = \"Captured\"; ObjectID = \"4FU-iP-c6T\";", "extractionState" : "extracted_with_value", @@ -2311,6 +2341,36 @@ } } }, + "f3L-bA-RW6.text" : { + "comment" : "Class = \"UILabel\"; text = \"Right Stick Minimum Offset\"; ObjectID = \"f3L-bA-RW6\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Right Stick Minimum Offset" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "右摇杆最小偏移" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "右搖桿最小偏移" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "右搖桿最小偏移" + } + } + } + }, "FJv-HJ-UYJ.text" : { "comment" : "Class = \"UILabel\"; text = \"Touch Move Event Interval\"; ObjectID = \"FJv-HJ-UYJ\";", "extractionState" : "extracted_with_value", @@ -2852,30 +2912,30 @@ } }, "HqA-an-KEe.text" : { - "comment" : "Class = \"UILabel\"; text = \"Minimum offset (Gyro→Stick)\"; ObjectID = \"HqA-an-KEe\";", + "comment" : "Class = \"UILabel\"; text = \"Minimum Offset (Gyro→Stick)\"; ObjectID = \"HqA-an-KEe\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Minimum offset (Gyro→Stick)" + "value" : "Minimum Offset (Gyro→Stick)" } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "最小偏移量(陀螺仪→摇杆)" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "最小偏移量(陀螺儀→搖桿)" } }, "zh-HK" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "最小偏移量(陀螺儀→搖桿)" } } diff --git a/VoidLink/mul.lproj/iPhone.xcstrings b/VoidLink/mul.lproj/iPhone.xcstrings index 5dee1d5b..fcbe651f 100644 --- a/VoidLink/mul.lproj/iPhone.xcstrings +++ b/VoidLink/mul.lproj/iPhone.xcstrings @@ -950,30 +950,30 @@ } }, "52u-T9-1Hv.text" : { - "comment" : "Class = \"UILabel\"; text = \"Minimum offset (Gyro→Stick)\"; ObjectID = \"52u-T9-1Hv\";", + "comment" : "Class = \"UILabel\"; text = \"Minimum Offset (Gyro→Stick)\"; ObjectID = \"52u-T9-1Hv\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Minimum offset (Gyro→Stick)" + "value" : "Minimum Offset (Gyro→Stick)" } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "最小偏移量(陀螺仪→摇杆)" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "最小偏移量(陀螺儀→搖桿)" } }, "zh-HK" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "最小偏移量(陀螺儀→搖桿)" } } @@ -4063,6 +4063,36 @@ } } }, + "q6s-4H-y9n.text" : { + "comment" : "Class = \"UILabel\"; text = \"Right Stick Minimum Offset\"; ObjectID = \"q6s-4H-y9n\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Right Stick Minimum Offset" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "右摇杆最小偏移" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "右搖桿最小偏移" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "右搖桿最小偏移" + } + } + } + }, "q6v-Jb-ysy.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; q6v-Jb-ysy.segmentTitles[0] = \"Xbox 360\"; ObjectID = \"q6v-Jb-ysy\";", "extractionState" : "extracted_with_value", @@ -5203,6 +5233,36 @@ } } }, + "whI-oR-V8o.text" : { + "comment" : "Class = \"UILabel\"; text = \"Left Stick Minimum Offset\"; ObjectID = \"whI-oR-V8o\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Left Stick Minimum Offset" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "左摇杆最小偏移" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "左搖桿最小偏移" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "左搖桿最小偏移" + } + } + } + }, "wOV-Sp-UUE.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; wOV-Sp-UUE.segmentTitles[0] = \"Slide From Left Edge\"; ObjectID = \"wOV-Sp-UUE\";", "extractionState" : "extracted_with_value",