- vertical stick indicator offset

- smaller stick indicator cross
- animation for stick ball return
- border detection for stick ball
- allow zero alpha for custom on-screen touch pads
This commit is contained in:
TrueZhuangjia
2025-02-26 22:48:10 +08:00
parent a17a27005d
commit 3efddab070
6 changed files with 89 additions and 34 deletions
@@ -292,7 +292,7 @@ static NSMutableDictionary *OnScreenWidgetViewsDict;
buttonState.backgroundAlpha = widgetView.backgroundAlpha;
buttonState.borderWidth = widgetView.borderWidth;
buttonState.sensitivityFactor = widgetView.sensitivityFactor;
buttonState.stickIndicatorXOffset = widgetView.stickIndicatorXOffset;
buttonState.stickIndicatorOffset = widgetView.stickIndicatorOffset;
NSData *buttonStateEncoded = [NSKeyedArchiver archivedDataWithRootObject:buttonState requiringSecureCoding:YES error:nil];
[buttonStatesEncoded addObject: buttonStateEncoded];
@@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) CGFloat heightFactor; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat borderWidth; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat sensitivityFactor; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat stickIndicatorXOffset; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat stickIndicatorOffset; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat oscLayerSizeFactor; // for OnScreenController CALayer
@property (nonatomic, assign) CGFloat backgroundAlpha; // for OnScreenController CALayer
@@ -36,7 +36,7 @@
[encoder encodeFloat:self.widthFactor forKey:@"widthFactor"];
[encoder encodeFloat:self.heightFactor forKey:@"heightFactor"];
[encoder encodeFloat:self.sensitivityFactor forKey:@"velocityFactor"];
[encoder encodeFloat:self.stickIndicatorXOffset forKey:@"stickIndicatorOffset"];
[encoder encodeFloat:self.stickIndicatorOffset forKey:@"stickIndicatorOffset"];
[encoder encodeFloat:self.oscLayerSizeFactor forKey:@"oscLayerSizeFactor"];
[encoder encodeFloat:self.backgroundAlpha forKey:@"backgroundAlpha"];
[encoder encodeFloat:self.borderWidth forKey:@"borderWidth"];
@@ -53,7 +53,7 @@
self.widthFactor = [decoder decodeFloatForKey:@"widthFactor"];
self.heightFactor = [decoder decodeFloatForKey:@"heightFactor"];
self.sensitivityFactor = [decoder decodeFloatForKey:@"velocityFactor"];
self.stickIndicatorXOffset = [decoder decodeFloatForKey:@"stickIndicatorOffset"];
self.stickIndicatorOffset = [decoder decodeFloatForKey:@"stickIndicatorOffset"];
self.oscLayerSizeFactor = [decoder decodeFloatForKey:@"oscLayerSizeFactor"];
self.backgroundAlpha = [decoder decodeFloatForKey:@"backgroundAlpha"];
self.borderWidth = [decoder decodeFloatForKey:@"borderWidth"];
+80 -25
View File
@@ -36,6 +36,8 @@ import UIKit
private var touchLockedForMoveEvent: UITouch
private var touchBegan: Bool = false
private let stickBallMaxOffset = 18.0
// for LSVPAD, RSVPAD
@objc public var deltaX: CGFloat
@@ -50,7 +52,7 @@ import UIKit
// for LSVPAD, RSVPAD, LSPAD, RSPAD
private let crossMarkColor: CGColor = UIColor(white: 1, alpha: 0.7).cgColor
private let crossMarkColor: CGColor = UIColor(white: 1, alpha: 0.70).cgColor
private let stickBallColor: CGColor = UIColor(white: 1, alpha: 0.75).cgColor
private var stickInputScale: CGFloat = 35
private var l3r3Indicator = CAShapeLayer()
@@ -62,7 +64,7 @@ import UIKit
private var touchTapTimeInterval: TimeInterval
private var touchTapTimeStamp: TimeInterval
private let QUICK_TAP_TIME_INTERVAL = 0.2
@objc public var stickIndicatorXOffset: CGFloat = 120
@objc public var stickIndicatorOffset: CGFloat = 120
// for all LRUD pads
private var upIndicator = CAShapeLayer()
@@ -87,7 +89,7 @@ import UIKit
private var twoTouchesDetected: Bool
private var storedCenter: CGPoint = .zero // location from persisted data
private let minimumBorderAlpha: CGFloat = 0.19
private var minimumBorderAlpha: CGFloat = 0.19
private var defaultBorderColor: CGColor = UIColor(white: 0.2, alpha: 0.3).cgColor
private let moonlightPurple: CGColor = UIColor(red: 0.5, green: 0.5, blue: 1.0, alpha: 0.86).cgColor
@@ -121,7 +123,7 @@ import UIKit
self.mousePointerMoved = false
self.touchLockedForMoveEvent = UITouch()
self.twoTouchesDetected = false
self.stickIndicatorXOffset = 95
self.stickIndicatorOffset = 95
self.sensitivityFactor = 1.0
super.init(frame: .zero)
@@ -212,6 +214,9 @@ import UIKit
let realBackgroundAlpha = self.backgroundAlpha - 0.18 // offset to be consistent with legacy onScreen controller layer opacity
self.backgroundColor = UIColor(white: 0.2, alpha: realBackgroundAlpha) // offset to be consistent with legacy onScreen controller layer opacity
var borderAlpha = realBackgroundAlpha * 1.01
if CommandManager.touchPadCmds.contains(self.keyString) {
minimumBorderAlpha = 0.0
}
if borderAlpha < minimumBorderAlpha {
borderAlpha = minimumBorderAlpha
}
@@ -335,14 +340,28 @@ import UIKit
//================================================================================================
//Indicator overlay for on-screen game controller left or right sticks (non-vector mode)
private func handleStickBallReachingBorder(){
stickBallLayer.lineWidth = 3.3
// stickBallLayer.shadowOffset = CGSize(width: 0.0, height: 0.0)
stickBallLayer.shadowOffset = CGSize(width: 0.0, height: 0.0)
// stickBallLayer.shadowColor = stickBallLayer.strokeColor
}
private func handleStickBallLeavingBorder(){
stickBallLayer.lineWidth = 0
stickBallLayer.shadowOffset = CGSize(width: 0.5, height: 0.5)
stickBallLayer.shadowOpacity = 0.8
stickBallLayer.shadowColor = UIColor.black.cgColor
}
// create stick indicator: the crossMark & stickBall:
@objc public func showStickIndicator(){
// tell if the self button is located on the left or right
self.selfViewOnTheRight = (self.storedCenter.x > self.appWindow.frame.width*0.5)
let offsetSign = selfViewOnTheRight ? -1 : 1
// self.selfViewOnTheRight = (self.storedCenter.x > self.appWindow.frame.width*0.5), deprecated
// let offsetSign = selfViewOnTheRight ? -1 : 1
let stickMarkerRelativeLocation:CGPoint
if !OnScreenWidgetView.editMode {
stickMarkerRelativeLocation = CGPointMake(touchBeganLocation.x + CGFloat(offsetSign) * self.stickIndicatorXOffset, touchBeganLocation.y)
stickMarkerRelativeLocation = CGPointMake(touchBeganLocation.x, touchBeganLocation.y - self.stickIndicatorOffset)
}
else{
stickMarkerRelativeLocation = CGPointMake(touchBeganLocation.x, touchBeganLocation.y)
@@ -356,7 +375,7 @@ import UIKit
private func createAndShowCrossMarkOnTouchPoint(at point: CGPoint) -> CAShapeLayer {
let crossLayer = CAShapeLayer()
let path = UIBezierPath()
let crossSize = 45.0
let crossSize = 26.0
path.move(to: CGPoint(x: point.x - crossSize / 2, y: point.y))
path.addLine(to: CGPoint(x: point.x + crossSize / 2, y: point.y))
@@ -367,7 +386,7 @@ import UIKit
crossLayer.path = path.cgPath
crossLayer.strokeColor = crossMarkColor
crossLayer.lineWidth = 1
crossLayer.lineWidth = 1.2
crossLayer.fillColor = crossMarkColor
self.layer.superlayer?.addSublayer(crossLayer)
@@ -394,7 +413,8 @@ import UIKit
// stickBallLayer.position = CG
// Set the stroke color and width (border of the circle)
stickBallLayer.strokeColor = stickBallColor
stickBallLayer.strokeColor = UIColor(red: 0.5, green: 0.5, blue: 1.0, alpha: 1.0).cgColor
//stickBallLayer.
stickBallLayer.lineWidth = 0
stickBallLayer.shadowOffset = CGSize(width: 0.5, height: 0.5)
stickBallLayer.shadowRadius = 0;
@@ -402,7 +422,7 @@ import UIKit
// Set the fill color (inside of the circle)
stickBallLayer.fillColor = stickBallColor // Light fill with some transparency
return stickBallLayer
}
@@ -411,13 +431,43 @@ import UIKit
CATransaction.setDisableActions(true)
self.stickBallLayer.removeAllAnimations()
if !OnScreenWidgetView.editMode {
self.stickBallLayer.position = CGPointMake(CGRectGetMidX(self.crossMarkLayer.frame) + touchInputToStickBallCoord(input: offSetX*sensitivityFactor), CGRectGetMidY(self.crossMarkLayer.frame) + touchInputToStickBallCoord(input: offSetY*sensitivityFactor))
let realOffsetX = touchInputToStickBallCoord(input: offSetX*sensitivityFactor)
let realOffsetY = touchInputToStickBallCoord(input: offSetY*sensitivityFactor)
self.stickBallLayer.position = CGPointMake(CGRectGetMidX(self.crossMarkLayer.frame) + realOffsetX, CGRectGetMidY(self.crossMarkLayer.frame) + realOffsetY)
if fabs(realOffsetX) == stickBallMaxOffset || fabs(realOffsetY) == stickBallMaxOffset {
handleStickBallReachingBorder()
}
else{
handleStickBallLeavingBorder()
}
}
else{
// illustrate offset distance in edit mode
let offsetSign = self.selfViewOnTheRight ? -1 : 1
// let offsetSign = self.selfViewOnTheRight ? -1 : 1 // dprecated
// let illlustrationPoint = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame)/4)
self.crossMarkLayer.position = CGPointMake(CGRectGetMidX(self.stickBallLayer.frame) + CGFloat(offsetSign) * stickIndicatorXOffset, CGRectGetMidY(self.stickBallLayer.frame))
self.crossMarkLayer.position = CGPointMake(CGRectGetMidX(self.stickBallLayer.frame), CGRectGetMidY(self.stickBallLayer.frame)-stickIndicatorOffset)
}
CATransaction.commit()
}
private func resetStickBallPositionAndRemoveIndicator(){
handleStickBallLeavingBorder()
CATransaction.begin()
// CATransaction.setDisableActions(true)
CATransaction.setAnimationDuration(0.15)
self.stickBallLayer.position = CGPointMake(CGRectGetMidX(self.crossMarkLayer.frame), CGRectGetMidY(self.crossMarkLayer.frame))
CATransaction.setCompletionBlock {
DispatchQueue.global().async {
// 后台执行耗时操作
usleep(200000)
DispatchQueue.main.async {
if !self.touchBegan {
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
}
}
}
// 动画结束后执行的代码
}
CATransaction.commit()
}
@@ -426,10 +476,6 @@ import UIKit
//=====LRUD(left right up & down buttons) touchPad touch =========================================
private func createAndShowLrudBall(at point: CGPoint) -> CAShapeLayer {
@@ -694,8 +740,12 @@ import UIKit
}
private func touchInputToStickBallCoord(input: CGFloat) -> CGFloat {
if input > stickInputScale {return 18}
if input < -stickInputScale {return -18}
if input > stickInputScale {
return stickBallMaxOffset
}
if input < -stickInputScale {
return -stickBallMaxOffset
}
return input * (18/stickInputScale)
}
@@ -767,9 +817,9 @@ import UIKit
//==============================================================================
// Touch event handling
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchBegan = true
super.touchesBegan(touches, with: event)
self.isMultipleTouchEnabled = self.keyString == "MOUSEPAD" // only enable multi-touch in mousePad mode
@@ -797,12 +847,18 @@ import UIKit
if CommandManager.touchPadCmds.contains(self.keyString) && touches.count == 1{ // don't use event?.allTouches?.count here, it will counts all touches including the ones captured by other UIViews
switch self.keyString {
case "LSPAD":
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
self.l3r3Indicator.removeFromSuperlayer()
self.showStickIndicator()
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
self.onScreenControls.pressDownControllerButton(LS_CLK_FLAG)}
break
case "RSPAD":
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
self.l3r3Indicator.removeFromSuperlayer()
self.showStickIndicator()
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
@@ -948,6 +1004,7 @@ import UIKit
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchBegan = false
super.touchesEnded(touches, with: event)
if self.keyString != "MOUSEPAD" {quickDoubleTapDetected = false} //do not reset this flag here in mousePad mode
@@ -976,12 +1033,10 @@ import UIKit
switch self.keyString{
case "LSPAD":
self.onScreenControls.clearLeftStickTouchPadFlag()
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
self.resetStickBallPositionAndRemoveIndicator()
case "RSPAD":
self.onScreenControls.clearRightStickTouchPadFlag()
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
self.resetStickBallPositionAndRemoveIndicator()
case "LSVPAD":
self.onScreenControls.clearLeftStickTouchPadFlag()
case "RSVPAD":
+1 -1
View File
@@ -403,7 +403,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
widgetView.heightFactor = buttonState.heightFactor;
widgetView.borderWidth = buttonState.borderWidth;
widgetView.sensitivityFactor = buttonState.sensitivityFactor;
widgetView.stickIndicatorXOffset = buttonState.stickIndicatorXOffset;
widgetView.stickIndicatorOffset = buttonState.stickIndicatorOffset;
// Add the widgetView to the view controller's view
[self->streamFrameTopLayerView addSubview:widgetView]; // add keyboard button to the stream frame view. must add it to the target view before setting location.
[widgetView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y];
@@ -93,7 +93,7 @@
widgetView.heightFactor = buttonState.heightFactor;
widgetView.borderWidth = buttonState.borderWidth;
widgetView.sensitivityFactor = buttonState.sensitivityFactor;
widgetView.stickIndicatorXOffset = buttonState.stickIndicatorXOffset;
widgetView.stickIndicatorOffset = buttonState.stickIndicatorOffset;
// widgetView.backgroundAlpha = buttonState.backgroundAlpha;
// Add the widgetView to the view controller's view
[self.view addSubview:widgetView];
@@ -436,8 +436,8 @@
[selectedWidgetView.crossMarkLayer removeFromSuperlayer];
selectedWidgetView.touchBeganLocation = CGPointMake(CGRectGetWidth(selectedWidgetView.frame)/2, CGRectGetHeight(selectedWidgetView.frame)/4);
[selectedWidgetView showStickIndicator];// this will create the indicator CAShapeLayers
[self.stickIndicatorOffsetSlider setValue:self->selectedWidgetView.stickIndicatorXOffset];
[stickIndicatorOffsetSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Indicator Offset: %.2f", self->selectedWidgetView.stickIndicatorXOffset]];
[self.stickIndicatorOffsetSlider setValue:self->selectedWidgetView.stickIndicatorOffset];
[stickIndicatorOffsetSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Indicator Offset: %.2f", self->selectedWidgetView.stickIndicatorOffset]];
[self->selectedWidgetView updateStickIndicator];
}
[widgetSizeSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Size: %.2f", self->selectedWidgetView.widthFactor]];
@@ -527,7 +527,7 @@
- (void)stickIndicatorOffsetSliderMoved{
[stickIndicatorOffsetSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Indicator Offset: %.2f", self.stickIndicatorOffsetSlider.value]];
if(self->selectedWidgetView != nil && self->widgetViewSelected){
self->selectedWidgetView.stickIndicatorXOffset = self.stickIndicatorOffsetSlider.value;
self->selectedWidgetView.stickIndicatorOffset = self.stickIndicatorOffsetSlider.value;
[self->selectedWidgetView updateStickIndicator];
}
return;