diff --git a/VoidLink/Input/InertialScroller.swift b/VoidLink/Input/InertialScroller.swift index 659c0970..9333f6af 100644 --- a/VoidLink/Input/InertialScroller.swift +++ b/VoidLink/Input/InertialScroller.swift @@ -12,10 +12,9 @@ class InertialScroller { public lazy var timer: SafeTimer? = { SafeTimer(interval: 1/displayLinkRate) { [weak self] in guard let self = self, handler != nil else {return} - let deceratedDeltaX = self.vector.dx * decelerationRate - let deceratedDeltaY = self.vector.dy * decelerationRate - self.vector = CGVector(dx: deceratedDeltaX, dy: deceratedDeltaY) - if abs(deceratedDeltaX) < self.timerSuspendThreshold && abs(deceratedDeltaY) < self.timerSuspendThreshold { + self.vector.dx = self.vector.dx * decelerationRate + self.vector.dy = self.vector.dy * decelerationRate + if abs(self.vector.dx) < self.timerSuspendThreshold && abs(self.vector.dy) < self.timerSuspendThreshold { self.timer?.pause() } (self.handler ?? {})() diff --git a/VoidLink/Input/MotionHandler.swift b/VoidLink/Input/MotionHandler.swift index 82e0e2e4..26f09765 100644 --- a/VoidLink/Input/MotionHandler.swift +++ b/VoidLink/Input/MotionHandler.swift @@ -111,6 +111,7 @@ import CoreMotion private var rightStickPhysicalInputX:Double = 0 private var rightStickPhysicalInputY:Double = 0 + public var gyroToStickOffset:CGVector = CGVector(dx: 0, dy: 0) private var leftStickPhysicalInputX:Double = 0 private var leftStickPhysicalInputY:Double = 0 @@ -302,10 +303,12 @@ import CoreMotion if oscProfile.mapGyroTo == MapGyroTo.mapGyroToControllerStick { if oscProfile.yawPitchToRightStick { - yaw = rightStickTouchInputX + rightStickPhysicalInputX + gyroInputToStickInput(input:yawSource*sensitvityYaw*widgetYawFactor*10) + gyroToStickOffset.dx = gyroInputToStickInput(input:yawSource*sensitvityYaw*widgetYawFactor*10) + yaw = rightStickTouchInputX + rightStickPhysicalInputX + gyroToStickOffset.dx yaw = self.clampStickInput(input: yaw) - pitch = rightStickTouchInputY + rightStickPhysicalInputY - gyroInputToStickInput(input:pitchSource*sensitvityPitch*widgetPitchFactor*10) + gyroToStickOffset.dy = -gyroInputToStickInput(input:pitchSource*sensitvityPitch*widgetPitchFactor*10) + pitch = rightStickTouchInputY + rightStickPhysicalInputY + gyroToStickOffset.dy pitch = self.clampStickInput(input: pitch) let offsetVector = ControllerUtil.compensated(offsetVector: CGVector(dx: yaw, dy: pitch), withMinOffset: gyroToStickMinOffset) diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 8288ae16..60e70528 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -143,8 +143,9 @@ import UIKit @objc public var deltaX: CGFloat @objc public var deltaY: CGFloat - @objc private var weightedDeltaX: Int = 0 - @objc private var weightedDeltaY: Int = 0 + private let VectorStickFactor = 1.5167 + private var weightedDeltaX: Int = 0 + private var weightedDeltaY: Int = 0 // for LSPAD, RSPAD @objc public var offSetX: CGFloat @@ -1288,11 +1289,15 @@ import UIKit //=========================================send on screen controller stick/trigger events - private func touchInputToStickInput(input: CGFloat) -> CGFloat{ + private func weightedTouchInputToStickOffset(input: CGFloat) -> CGFloat{ let target = stickMaxOffset * input / stickInputScale return fmax(fmin(target, stickMaxOffset),-stickMaxOffset) } + private func stickOffsetToWeightedTouchInput(offset: CGFloat) -> CGFloat { + return offset * stickInputScale / stickMaxOffset + } + private func touchInputToStickBallCoord(input: CGFloat) -> CGFloat { if input > stickInputScale { return stickBallMaxOffset @@ -1303,9 +1308,9 @@ import UIKit return input * (18/stickInputScale) } - private func sendRightStickTouchPadEvent(inputX: CGFloat, inputY: CGFloat){ - let targetX = self.touchInputToStickInput(input: inputX) - let targetY = -self.touchInputToStickInput(input: inputY) + private func sendRightStickTouchPadEvent(weightedTouchX: CGFloat, weightedTouchY: CGFloat){ + let targetX = self.weightedTouchInputToStickOffset(input: weightedTouchX) + let targetY = -self.weightedTouchInputToStickOffset(input: weightedTouchY) let mixRightStickInputToGyro = (oscProfile.mapGyroTo == MapGyroTo.mapGyroToControllerStick && oscProfile.yawPitchToRightStick) @@ -1317,9 +1322,9 @@ import UIKit self.motionHandler.mixOnScreenRightStickAndGyroInput(x: targetX, y: targetY) } - private func sendLeftStickTouchPadEvent(inputX: CGFloat, inputY: CGFloat){ - let targetX = self.touchInputToStickInput(input: inputX) - let targetY = -self.touchInputToStickInput(input: inputY) + private func sendLeftStickTouchPadEvent(weightedTouchX: CGFloat, weightedTouchY: CGFloat){ + let targetX = self.weightedTouchInputToStickOffset(input: weightedTouchX) + let targetY = -self.weightedTouchInputToStickOffset(input: weightedTouchY) let mixLeftStickInputToGyro = (oscProfile.mapGyroTo == MapGyroTo.mapGyroToControllerStick && oscProfile.rollToLeftStick) @@ -1778,32 +1783,32 @@ import UIKit case "LSPAD": DispatchQueue.global(qos: .userInteractive).async { self.weightedDeltaX = 1 - self.sendLeftStickTouchPadEvent(inputX: self.offSetX * self.sensitivityFactorX, inputY: self.offSetY * self.sensitivityFactorY) + self.sendLeftStickTouchPadEvent(weightedTouchX: self.offSetX * self.sensitivityFactorX, weightedTouchY: self.offSetY * self.sensitivityFactorY) } if widgetType == WidgetTypeEnum.touchPad {updateStickIndicator()} self.updateTouchLocation(touch: touches.first!) case "RSPAD": DispatchQueue.global(qos: .userInteractive).async { self.weightedDeltaX = 1 - self.sendRightStickTouchPadEvent(inputX: self.offSetX * self.sensitivityFactorX, inputY: self.offSetY * self.sensitivityFactorY) + self.sendRightStickTouchPadEvent(weightedTouchX: self.offSetX * self.sensitivityFactorX, weightedTouchY: self.offSetY * self.sensitivityFactorY) } if widgetType == WidgetTypeEnum.touchPad {updateStickIndicator()} self.updateTouchLocation(touch: touches.first!) case "LSVPAD": DispatchQueue.global(qos: .userInteractive).async { - self.weightedDeltaX = Int(self.deltaX*1.5167*self.sensitivityFactorX) - self.weightedDeltaY = Int(self.deltaY*1.5167*self.sensitivityFactorY) + self.weightedDeltaX = Int(self.deltaX*self.VectorStickFactor*self.sensitivityFactorX) + self.weightedDeltaY = Int(self.deltaY*self.VectorStickFactor*self.sensitivityFactorY) if self.firstTouchMoved { - self.sendLeftStickTouchPadEvent(inputX: CGFloat(self.weightedDeltaX), inputY: CGFloat(self.weightedDeltaY)) + self.sendLeftStickTouchPadEvent(weightedTouchX: CGFloat(self.weightedDeltaX), weightedTouchY: CGFloat(self.weightedDeltaY)) } self.updateTouchLocation(touch: touches.first!) } case "RSVPAD": DispatchQueue.global(qos: .userInteractive).async { - self.weightedDeltaX = Int(self.deltaX*1.5167*self.sensitivityFactorX) - self.weightedDeltaY = Int(self.deltaY*1.5167*self.sensitivityFactorY) + self.weightedDeltaX = Int(self.deltaX*self.VectorStickFactor*self.sensitivityFactorX) + self.weightedDeltaY = Int(self.deltaY*self.VectorStickFactor*self.sensitivityFactorY) if self.firstTouchMoved { - self.sendRightStickTouchPadEvent(inputX: CGFloat(self.weightedDeltaX), inputY: CGFloat(self.weightedDeltaY)) + self.sendRightStickTouchPadEvent(weightedTouchX: CGFloat(self.weightedDeltaX), weightedTouchY: CGFloat(self.weightedDeltaY)) } self.updateTouchLocation(touch: touches.first!) } @@ -2013,18 +2018,7 @@ import UIKit if !OnScreenWidgetView.editMode && self.widgetType == WidgetTypeEnum.touchPad && CommandManager.mousePadWithButtonActions.contains(self.touchPadString) && allSpawnedTouchesCount == 1 && !twoTouchesDetected { self.handleMousePadButtonActionUp() } - - /* - if !OnScreenWidgetView.editMode && self.widgetType == WidgetTypeEnum.touchPad && self.touchPadString == "TRACKBALL" && allSpawnedTouchesCount == 1 && !twoTouchesDetected { - if(mousePointerMoved){ - self.startTrackballMomentum() - mousePointerMoved = false //reset flag - } - else{ - self.stopTrackballMomentum() - } - }*/ - + if !OnScreenWidgetView.editMode && self.widgetType == WidgetTypeEnum.touchPad && CommandManager.mousePadWithButtonActions.contains(self.touchPadString) && twoTouchesDetected && touches.count == allSpawnedTouchesCount { // need to enable multi-touch first // touches.count == allCapturedTouchesCount means allfingers are lifting if(self.mouseButtonAction == MouseButtonAction.hovering) {self.sendMouseRightButtonClickEvent()} @@ -2046,9 +2040,9 @@ import UIKit if(!firstTouchMoved) {self.inertialScroller.vector = CGVector(dx: 0, dy: 0)} if self.inertialScroller.handler == nil { self.inertialScroller.handler = { - let weightedDeltaX = self.inertialScroller.vector.dx*1.5167*self.sensitivityFactorX - let weightedDeltaY = self.inertialScroller.vector.dy*1.5167*self.sensitivityFactorY - self.sendLeftStickTouchPadEvent(inputX: weightedDeltaX, inputY: weightedDeltaY) + let weightedDeltaX = self.inertialScroller.vector.dx*self.VectorStickFactor*self.sensitivityFactorX + let weightedDeltaY = self.inertialScroller.vector.dy*self.VectorStickFactor*self.sensitivityFactorY + self.sendLeftStickTouchPadEvent(weightedTouchX: weightedDeltaX, weightedTouchY: weightedDeltaY) } } self.inertialScroller.timer?.restart() @@ -2058,10 +2052,24 @@ import UIKit if self.decelerationRate > 0.50001 { if(!firstTouchMoved) {self.inertialScroller.vector = CGVector(dx: 0, dy: 0)} if self.inertialScroller.handler == nil { - self.inertialScroller.handler = { - let weightedDeltaX = self.inertialScroller.vector.dx*1.5167*self.sensitivityFactorX - let weightedDeltaY = self.inertialScroller.vector.dy*1.5167*self.sensitivityFactorY - self.sendRightStickTouchPadEvent(inputX: weightedDeltaX, inputY: weightedDeltaY) + var synthesizedDeltaX:CGFloat = 0 + var synthesizedDeltaY:CGFloat = 0 + self.inertialScroller.handler = { [self] in + let weightedScrollerVector = CGVector(dx: self.inertialScroller.vector.dx*self.VectorStickFactor*self.sensitivityFactorX, dy: self.inertialScroller.vector.dy*self.VectorStickFactor*self.sensitivityFactorY) + + if self.motionHandler.gyroMixInputStarted() { + let normailizedGyroVector = CGVector(dx: self.stickOffsetToWeightedTouchInput(offset: self.motionHandler.gyroToStickOffset.dx), dy: -self.stickOffsetToWeightedTouchInput(offset: self.motionHandler.gyroToStickOffset.dy)) + + let xConvergent = normailizedGyroVector.dx.sign != weightedScrollerVector.dx.sign && abs(normailizedGyroVector.dx) <= abs(weightedScrollerVector.dx) + let yConvergent = normailizedGyroVector.dy.sign != weightedScrollerVector.dy.sign && abs(normailizedGyroVector.dy) <= abs(weightedScrollerVector.dy) + + synthesizedDeltaX = xConvergent ? normailizedGyroVector.dx + weightedScrollerVector.dx : weightedScrollerVector.dx + synthesizedDeltaY = yConvergent ? normailizedGyroVector.dy + weightedScrollerVector.dy : weightedScrollerVector.dy + + self.inertialScroller.vector.dx = synthesizedDeltaX/(self.VectorStickFactor*self.sensitivityFactorX) + self.inertialScroller.vector.dy = synthesizedDeltaY/(self.VectorStickFactor*self.sensitivityFactorY) + } + self.sendRightStickTouchPadEvent(weightedTouchX: weightedScrollerVector.dx, weightedTouchY: weightedScrollerVector.dy) } } self.inertialScroller.timer?.restart()